Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 29 Feb 2008 16:32:15 +0000 (08:32 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 29 Feb 2008 16:32:15 +0000 (08:32 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6:
  arch/sh/drivers/dma/dma-sh.c: Correct use of ! and &
  serial: Move asm-sh/sci.h to linux/serial_sci.h.
  sh: Fix up HAS_SR_RB typo in entry-macros.

  maple: fix device detection
  sh: fix rtc_resources setup for sh770x
  sh: heartbeat: ioremap is expected to succeed
  sh: Storage class should be before const qualifier
  maple: remove unused variable
  sh: SH5-103 needs to select CPU_SH5.
  sh: Rename SH-3 CCR3 reg to avoid synclink_cs clash.

178 files changed:
Documentation/debugging-via-ohci1394.txt
Documentation/feature-removal-schedule.txt
Documentation/ide.txt
MAINTAINERS
arch/sparc/kernel/led.c
arch/sparc64/kernel/ds.c
arch/sparc64/kernel/mdesc.c
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/um/kernel/process.c
arch/x86/Kconfig.cpu
arch/x86/boot/memory.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/transmeta.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/hpet.c
arch/x86/kernel/process_64.c
arch/x86/kernel/setup_64.c
arch/x86/kernel/smpboot_64.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/tsc_32.c
arch/x86/kernel/vsyscall_64.c
arch/x86/lguest/boot.c
arch/x86/mm/init_64.c
arch/x86/mm/pageattr.c
arch/x86/vdso/Makefile
drivers/ata/libata-core.c
drivers/ata/libata.h
drivers/char/rtc.c
drivers/connector/connector.c
drivers/firewire/fw-cdev.c
drivers/firewire/fw-device.c
drivers/firewire/fw-device.h
drivers/firewire/fw-sbp2.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-dma.c
drivers/ide/ide-probe.c
drivers/ide/ide-tape.c
drivers/ide/ide.c
drivers/ide/legacy/qd65xx.c
drivers/ide/pci/cmd640.c
drivers/ide/pci/hpt366.c
drivers/ieee1394/sbp2.c
drivers/ieee1394/sbp2.h
drivers/infiniband/hw/cxgb3/iwch_mem.c
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/hw/nes/nes.h
drivers/infiniband/hw/nes/nes_cm.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_hw.h
drivers/infiniband/hw/nes/nes_verbs.c
drivers/net/Kconfig
drivers/net/bnx2x.c
drivers/net/bnx2x.h
drivers/net/bnx2x_fw_defs.h
drivers/net/bnx2x_hsi.h
drivers/net/bnx2x_init.h
drivers/net/bnx2x_reg.h
drivers/net/cs89x0.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/defines.h
drivers/net/e1000e/e1000.h
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/phy.c
drivers/net/ehea/ehea.h
drivers/net/ehea/ehea_main.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/gianfar.c
drivers/net/igb/igb_main.c
drivers/net/ixgb/ixgb_ethtool.c
drivers/net/macb.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/phy/mdio_bus.c
drivers/net/ps3_gelic_wireless.c
drivers/net/sis190.c
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/tlan.c
drivers/net/tulip/uli526x.c
drivers/net/via-rhine.c
drivers/net/virtio_net.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43legacy/Kconfig
drivers/net/wireless/bcm43xx/Kconfig
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/decl.h
drivers/net/wireless/libertas/main.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00reg.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/s390/net/claw.c
drivers/ssb/Kconfig
drivers/ssb/Makefile
drivers/ssb/driver_pcicore.c
drivers/ssb/ssb_private.h
fs/ext4/dir.c
fs/ext4/extents.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/ext4/namei.c
fs/ext4/resize.c
fs/proc/base.c
fs/xfs/xfs_bit.c
fs/xfs/xfs_bit.h
fs/xfs/xfs_rtalloc.c
include/asm-x86/futex.h
include/asm-x86/lguest.h
include/asm-x86/nops.h
include/asm-x86/page_64.h
include/linux/connector.h
include/linux/elfcore-compat.h
include/linux/ext4_fs_extents.h
include/linux/netfilter.h
include/linux/sched.h
include/net/sctp/user.h
kernel/lockdep.c
kernel/printk.c
kernel/sched.c
kernel/sched_fair.c
net/8021q/vlanproc.c
net/appletalk/atalk_proc.c
net/atm/br2684.c
net/atm/clip.c
net/atm/lec.c
net/atm/mpoa_proc.c
net/atm/proc.c
net/bluetooth/l2cap.c
net/core/neighbour.c
net/core/pktgen.c
net/ipv4/devinet.c
net/ipv4/ip_gre.c
net/ipv4/ipcomp.c
net/ipv4/ipip.c
net/ipv4/route.c
net/ipv6/addrconf.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipcomp6.c
net/ipv6/proc.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/sysctl_net_ipv6.c
net/ipx/ipx_proc.c
net/key/af_key.c
net/llc/llc_proc.c
net/mac80211/ieee80211_sta.c
net/netfilter/nf_conntrack_core.c
net/netfilter/xt_conntrack.c
net/sctp/auth.c
net/sctp/ipv6.c
net/sctp/objcnt.c
net/sctp/proc.c
net/sctp/protocol.c
net/sctp/socket.c
net/sctp/ulpevent.c
net/sunrpc/cache.c
net/sunrpc/stats.c
net/tipc/cluster.c
net/tipc/link.c
net/tipc/ref.c
net/tipc/zone.c
net/wanrouter/wanproc.c
net/x25/x25_proc.c

index de4804e8b396eb29000b37dd8fa575f5cd7dee8d..c360d4e91b4892d6be5a6ed5efcb981d4a3ad19f 100644 (file)
@@ -36,14 +36,15 @@ available (notebooks) or too slow for extensive debug information (like ACPI).
 Drivers
 -------
 
-The OHCI-1394 drivers in drivers/firewire and drivers/ieee1394 initialize
-the OHCI-1394 controllers to a working state and can be used to enable
-physical DMA. By default you only have to load the driver, and physical
-DMA access will be granted to all remote nodes, but it can be turned off
-when using the ohci1394 driver.
-
-Because these drivers depend on the PCI enumeration to be completed, an
-initialization routine which can runs pretty early (long before console_init(),
+The ohci1394 driver in drivers/ieee1394 initializes the OHCI-1394 controllers
+to a working state and enables physical DMA by default for all remote nodes.
+This can be turned off by ohci1394's module parameter phys_dma=0.
+
+The alternative firewire-ohci driver in drivers/firewire uses filtered physical
+DMA, hence is not yet suitable for remote debugging.
+
+Because ohci1394 depends on the PCI enumeration to be completed, an
+initialization routine which runs pretty early (long before console_init()
 which makes the printk buffer appear on the console can be called) was written.
 
 To activate it, enable CONFIG_PROVIDE_OHCI1394_DMA_INIT (Kernel hacking menu:
index 4d3aa519eadfc5cebea01e5244f0435702264319..ba899ff2a8f9b825b13808df694c6fe6c56642e0 100644 (file)
@@ -172,6 +172,16 @@ Who:       Len Brown <len.brown@intel.com>
 
 ---------------------------
 
+What:  ide-tape driver
+When:  July 2008
+Files: drivers/ide/ide-tape.c
+Why:   This driver might not have any users anymore and maintaining it for no
+       reason is an effort no one wants to make.
+Who:   Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>, Borislav Petkov
+       <petkovbb@googlemail.com>
+
+---------------------------
+
 What: libata spindown skipping and warning
 When: Dec 2008
 Why:  Some halt(8) implementations synchronize caches for and spin
index 94e2e3b9e77f03ebcb0a3d0b146e53397a6fcfc0..bcd7cd1278efd285d456fe058d1774b5181d5a7b 100644 (file)
@@ -258,8 +258,6 @@ Summary of ide driver parameters for kernel command line
                          As for VLB, it is safest to not specify it.
                          Bigger values are safer than smaller ones.
 
- "idex=noprobe"                : do not attempt to access/use this interface
  "idex=base"           : probe for an interface at the addr specified,
                          where "base" is usually 0x1f0 or 0x170
                          and "ctl" is assumed to be "base"+0x206
@@ -307,53 +305,6 @@ Also for legacy CMD640 host driver (cmd640) you need to use "probe_vlb"
 kernel paremeter to enable probing for VLB version of the chipset (PCI ones
 are detected automatically).
 
-================================================================================
-
-IDE ATAPI streaming tape driver
--------------------------------
-
-This driver is a part of the Linux ide driver and works in co-operation
-with linux/drivers/block/ide.c.
-
-The driver, in co-operation with ide.c, basically traverses the
-request-list for the block device interface. The character device
-interface, on the other hand, creates new requests, adds them
-to the request-list of the block device, and waits for their completion.
-
-Pipelined operation mode is now supported on both reads and writes.
-
-The block device major and minor numbers are determined from the
-tape's relative position in the ide interfaces, as explained in ide.c.
-
-The character device interface consists of the following devices:
-
- ht0           major 37, minor 0       first  IDE tape, rewind on close.
- ht1           major 37, minor 1       second IDE tape, rewind on close.
- ...
- nht0          major 37, minor 128     first  IDE tape, no rewind on close.
- nht1          major 37, minor 129     second IDE tape, no rewind on close.
- ...
-
-Run /dev/MAKEDEV to create the above entries.
-
-The general magnetic tape commands compatible interface, as defined by
-include/linux/mtio.h, is accessible through the character device.
-
-General ide driver configuration options, such as the interrupt-unmask
-flag, can be configured by issuing an ioctl to the block device interface,
-as any other ide device.
-
-Our own ide-tape ioctl's can be issued to either the block device or
-the character device interface.
-
-Maximal throughput with minimal bus load will usually be achieved in the
-following scenario:
-
-       1.      ide-tape is operating in the pipelined operation mode.
-       2.      No buffering is performed by the user backup program.
-
-
-
 ================================================================================
 
 Some Terminology
index 36c7bc641dba3efe58f3e78b9a51a62b7ea515b3..7990587542362113c7a1f94e7ef4202261f33adc 100644 (file)
@@ -982,6 +982,12 @@ M: mchan@broadcom.com
 L:     netdev@vger.kernel.org
 S:     Supported
 
+BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER
+P:     Eliezer Tamir
+M:     eliezert@broadcom.com
+L:     netdev@vger.kernel.org
+S:     Supported
+
 BROADCOM TG3 GIGABIT ETHERNET DRIVER
 P:     Michael Chan
 M:     mchan@broadcom.com
@@ -2744,6 +2750,8 @@ S:        Maintained
 NETEFFECT IWARP RNIC DRIVER (IW_NES)
 P:     Faisal Latif
 M:     flatif@neteffect.com
+P:     Nishi Gupta
+M:     ngupta@neteffect.com
 P:     Glenn Streiff
 M:     gstreiff@neteffect.com
 L:     general@lists.openfabrics.org
@@ -3884,10 +3892,13 @@ M:      trivial@kernel.org
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
-TULIP NETWORK DRIVER
-L:     tulip-users@lists.sourceforge.net
-W:     http://sourceforge.net/projects/tulip/
-S:     Orphan
+TULIP NETWORK DRIVERS
+P:     Grant Grundler
+M:     grundler@parisc-linux.org
+P:     Kyle McMartin
+M:     kyle@parisc-linux.org
+L:     netdev@vger.kernel.org
+S:     Maintained
 
 TUN/TAP driver
 P:     Maxim Krasnyansky
index 313d1620ae8ec65b3ce43c1ee8b180ec7abdeb68..59e9344e7a0da2f5f0ccc8f4586e3ef89a85debe 100644 (file)
@@ -3,6 +3,9 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/string.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
 
 #include <asm/auxio.h>
 
index eeb5a2fc788d2615e47660ae7c6962ca1777126a..bd76482077be66aa3e9e1d6e22d3523a34e4597a 100644 (file)
@@ -525,10 +525,10 @@ static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
        }
 }
 
-static int dr_cpu_configure(struct ds_info *dp,
-                           struct ds_cap_state *cp,
-                           u64 req_num,
-                           cpumask_t *mask)
+static int __cpuinit dr_cpu_configure(struct ds_info *dp,
+                                     struct ds_cap_state *cp,
+                                     u64 req_num,
+                                     cpumask_t *mask)
 {
        struct ds_data *resp;
        int resp_len, ncpus, cpu;
@@ -623,9 +623,9 @@ static int dr_cpu_unconfigure(struct ds_info *dp,
        return 0;
 }
 
-static void dr_cpu_data(struct ds_info *dp,
-                       struct ds_cap_state *cp,
-                       void *buf, int len)
+static void __cpuinit dr_cpu_data(struct ds_info *dp,
+                                 struct ds_cap_state *cp,
+                                 void *buf, int len)
 {
        struct ds_data *data = buf;
        struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
index 856659bb13116ed7444c263ec1a9f8087c660ec7..9100835895691e1c8f93f6ac38b8bfcf42db7132 100644 (file)
@@ -758,7 +758,7 @@ static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
        get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
 }
 
-void __devinit mdesc_fill_in_cpu_data(cpumask_t mask)
+void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask)
 {
        struct mdesc_handle *hp = mdesc_grab();
        u64 mp;
index e2027f27c0fe73f2f43546aa838577e86fc6e3ba..2650d0d33ac25cbc656baa97adec4c29e1a65a93 100644 (file)
@@ -244,16 +244,8 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
        if (regs->tstate & TSTATE_PRIV) {
                const struct exception_table_entry *entry;
 
-               if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) {
-                       if (insn & 0x2000)
-                               asi = (regs->tstate >> 24);
-                       else
-                               asi = (insn >> 5);
-               }
-       
-               /* Look in asi.h: All _S asis have LS bit set */
-               if ((asi & 0x1) &&
-                   (entry = search_exception_tables(regs->tpc))) {
+               entry = search_exception_tables(regs->tpc);
+               if (entry) {
                        regs->tpc = entry->fixup;
                        regs->tnpc = regs->tpc + 4;
                        return;
@@ -294,7 +286,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
                unsigned long tpc = regs->tpc;
 
                /* Sanity check the PC. */
-               if ((tpc >= KERNBASE && tpc < (unsigned long) _etext) ||
+               if ((tpc >= KERNBASE && tpc < (unsigned long) __init_end) ||
                    (tpc >= MODULES_VADDR && tpc < MODULES_END)) {
                        /* Valid, no problems... */
                } else {
index 9e6bca266d88338df73baf4dd1079a5c17672b69..b5c30416fdac221e9bc31c4d720865769c988e85 100644 (file)
@@ -1010,7 +1010,8 @@ static struct linux_prom64_registers pall[MAX_BANKS] __initdata;
 static int pall_ents __initdata;
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
-static unsigned long kernel_map_range(unsigned long pstart, unsigned long pend, pgprot_t prot)
+static unsigned long __ref kernel_map_range(unsigned long pstart,
+                                           unsigned long pend, pgprot_t prot)
 {
        unsigned long vstart = PAGE_OFFSET + pstart;
        unsigned long vend = PAGE_OFFSET + pend;
index fc50d2f959d12f44bc6c41171f3cc030d6ad38fa..e8cb9ff183e9fe1da41020bc39ffe22b43ef56c7 100644 (file)
@@ -128,8 +128,6 @@ void *get_current(void)
        return current;
 }
 
-extern void schedule_tail(struct task_struct *prev);
-
 /*
  * This is called magically, by its address being stuffed in a jmp_buf
  * and being longjmp-d to.
index e09a6b73a1aab5c3fc6a353e22af4936b047416f..6d50064db182303dd27402b2e6c1c84d4502971b 100644 (file)
@@ -377,6 +377,19 @@ config X86_OOSTORE
        def_bool y
        depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
 
+#
+# P6_NOPs are a relatively minor optimization that require a family >=
+# 6 processor, except that it is broken on certain VIA chips.
+# Furthermore, AMD chips prefer a totally different sequence of NOPs
+# (which work on all CPUs).  As a result, disallow these if we're
+# compiling X86_GENERIC but not X86_64 (these NOPs do work on all
+# x86-64 capable chips); the list of processors in the right-hand clause
+# are the cores that benefit from this optimization.
+#
+config X86_P6_NOP
+       def_bool y
+       depends on (X86_64 || !X86_GENERIC) && (M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || MCORE2 || PENTIUM4)
+
 config X86_TSC
        def_bool y
        depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
@@ -390,6 +403,7 @@ config X86_CMOV
 config X86_MINIMUM_CPU_FAMILY
        int
        default "64" if X86_64
+       default "6" if X86_32 && X86_P6_NOP
        default "4" if X86_32 && (X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK)
        default "3"
 
index 378353956b5dfc86469b66419b9680e1770a7410..e77d89f9e8aa23c13751bee268718e8ed7ee54a7 100644 (file)
@@ -37,6 +37,12 @@ static int detect_memory_e820(void)
                      "=m" (*desc)
                    : "D" (desc), "d" (SMAP), "a" (0xe820));
 
+               /* BIOSes which terminate the chain with CF = 1 as opposed
+                  to %ebx = 0 don't always report the SMAP signature on
+                  the final, failing, probe. */
+               if (err)
+                       break;
+
                /* Some BIOSes stop returning SMAP in the middle of
                   the search loop.  We don't know exactly how the BIOS
                   screwed up the map at that point, we might have a
@@ -47,9 +53,6 @@ static int detect_memory_e820(void)
                        break;
                }
 
-               if (err)
-                       break;
-
                count++;
                desc++;
        } while (next && count < E820MAX);
index a33d53017997df4849660cccbab4f45a223a2bd3..8ea040124f7dc930de83225dbe45d9c642e7f196 100644 (file)
@@ -128,13 +128,11 @@ void foo(void)
        OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
 #endif
 
-#ifdef CONFIG_LGUEST_GUEST
+#if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE)
        BLANK();
        OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
        OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir);
-#endif
 
-#ifdef CONFIG_LGUEST
        BLANK();
        OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc);
        OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc);
index f86a3c4a2669909be340d195a6ee93201c53cdf9..a38aafaefc230b4bfc49c34c98fc2c443fff8318 100644 (file)
@@ -504,7 +504,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 
        /* Clear all flags overriden by options */
        for (i = 0; i < NCAPINTS; i++)
-               c->x86_capability[i] ^= cleared_cpu_caps[i];
+               c->x86_capability[i] &= ~cleared_cpu_caps[i];
 
        /* Init Machine Check Exception if available. */
        mcheck_init(c);
index b6e136f23d3d3219094bc9fdadaeaba048f01b96..be83336fddba9c6c3629bbe1748aa42480a6e707 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <asm/msr.h>
+#include <asm/kvm_para.h>
 #include "mtrr.h"
 
 u32 num_var_ranges = 0;
@@ -649,6 +650,7 @@ static __init int amd_special_default_mtrr(void)
 
 /**
  * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
+ * @end_pfn: ending page frame number
  *
  * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
  * memory configurations.  This routine checks that the highest MTRR matches
@@ -688,8 +690,11 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
 
        /* kvm/qemu doesn't have mtrr set right, don't trim them all */
        if (!highest_pfn) {
-               printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n");
-               WARN_ON(1);
+               if (!kvm_para_available()) {
+                       printk(KERN_WARNING
+                               "WARNING: strange, CPU MTRRs all blank?\n");
+                       WARN_ON(1);
+               }
                return 0;
        }
 
index 200fb3f9ebfbda2ec232deec234ded94128f4cfb..e8b422c1c51267419275e5db474fbd2b5e237ea3 100644 (file)
@@ -76,13 +76,6 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
        /* All Transmeta CPUs have a constant TSC */
        set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
        
-       /* If we can run i686 user-space code, call us an i686 */
-#define USER686 ((1 << X86_FEATURE_TSC)|\
-                (1 << X86_FEATURE_CX8)|\
-                (1 << X86_FEATURE_CMOV))
-        if (c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686)
-               c->x86 = 6;
-
 #ifdef CONFIG_SYSCTL
        /* randomize_va_space slows us down enormously;
           it probably triggers retranslation of x86->native bytecode */
index 2ad9a1bc6a73fafd6ea8e34b9117877eb2e736dd..c20c9e7e08dd2a644860dabc206ae1fb843ea173 100644 (file)
@@ -453,6 +453,7 @@ ENTRY(stub_execve)
        CFI_REGISTER rip, r11
        SAVE_REST
        FIXUP_TOP_OF_STACK %r11
+       movq %rsp, %rcx
        call sys_execve
        RESTORE_TOP_OF_STACK %r11
        movq %rax,RAX(%rsp)
@@ -1036,15 +1037,16 @@ ENDPROC(child_rip)
  *     rdi: name, rsi: argv, rdx: envp
  *
  * We want to fallback into:
- *     extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
+ *     extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs)
  *
  * do_sys_execve asm fallback arguments:
- *     rdi: name, rsi: argv, rdx: envp, fake frame on the stack
+ *     rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
  */
 ENTRY(kernel_execve)
        CFI_STARTPROC
        FAKE_STACK_FRAME $0
        SAVE_ALL        
+       movq %rsp,%rcx
        call sys_execve
        movq %rax, RAX(%rsp)    
        RESTORE_REST
index 25eb98540a41e067f7593753a51b8430fd8930df..fd8ca53943a8e0f01b86bb0157d5027de0bcf5bd 100644 (file)
@@ -606,7 +606,7 @@ ENTRY(_stext)
 .section ".bss.page_aligned","wa"
        .align PAGE_SIZE_asm
 #ifdef CONFIG_X86_PAE
-ENTRY(swapper_pg_pmd)
+swapper_pg_pmd:
        .fill 1024*KPMDS,4,0
 #else
 ENTRY(swapper_pg_dir)
index eb415043a9297d742f3df5d9a1de10fa35d0b69b..a007454133a33743b60fce4ebd3c90e8c32ee85e 100644 (file)
@@ -379,18 +379,24 @@ NEXT_PAGE(level2_ident_pgt)
        /* Since I easily can, map the first 1G.
         * Don't set NX because code runs from these pages.
         */
-       PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
+       PMDS(0, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
 
 NEXT_PAGE(level2_kernel_pgt)
-       /* 40MB kernel mapping. The kernel code cannot be bigger than that.
-          When you change this change KERNEL_TEXT_SIZE in page.h too. */
-       /* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
-       PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL, KERNEL_TEXT_SIZE/PMD_SIZE)
-       /* Module mapping starts here */
-       .fill   (PTRS_PER_PMD - (KERNEL_TEXT_SIZE/PMD_SIZE)),8,0
+       /*
+        * 128 MB kernel mapping. We spend a full page on this pagetable
+        * anyway.
+        *
+        * The kernel code+data+bss must not be bigger than that.
+        *
+        * (NOTE: at +128MB starts the module area, see MODULES_VADDR.
+        *  If you want to increase this then increase MODULES_VADDR
+        *  too.)
+        */
+       PMDS(0, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL,
+               KERNEL_IMAGE_SIZE/PMD_SIZE)
 
 NEXT_PAGE(level2_spare_pgt)
-       .fill   512,8,0
+       .fill   512, 8, 0
 
 #undef PMDS
 #undef NEXT_PAGE
index 429d084e014d4b11a829bbf01f53fdc860e276e2..235fd6c77504c9baedcfddd1610b143910e97e21 100644 (file)
@@ -368,8 +368,8 @@ static int hpet_clocksource_register(void)
        return 0;
 }
 
-/*
- * Try to setup the HPET timer
+/**
+ * hpet_enable - Try to setup the HPET timer. Returns 1 on success.
  */
 int __init hpet_enable(void)
 {
index b0cc8f0136d8096e9e4cdad316787f89d4f55a8c..43f287744f9f4351328f3cec21de5095815c526a 100644 (file)
@@ -730,16 +730,16 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
  */
 asmlinkage
 long sys_execve(char __user *name, char __user * __user *argv,
-               char __user * __user *envp, struct pt_regs regs)
+               char __user * __user *envp, struct pt_regs *regs)
 {
        long error;
        char * filename;
 
        filename = getname(name);
        error = PTR_ERR(filename);
-       if (IS_ERR(filename)) 
+       if (IS_ERR(filename))
                return error;
-       error = do_execve(filename, argv, envp, &regs); 
+       error = do_execve(filename, argv, envp, regs);
        putname(filename);
        return error;
 }
index 6fd804f0782145be3b45c223590c5c287a9bdb57..7637dc91c79bebac16365bbcff3b480c408584ef 100644 (file)
@@ -1021,7 +1021,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 
        /* Clear all flags overriden by options */
        for (i = 0; i < NCAPINTS; i++)
-               c->x86_capability[i] ^= cleared_cpu_caps[i];
+               c->x86_capability[i] &= ~cleared_cpu_caps[i];
 
 #ifdef CONFIG_X86_MCE
        mcheck_init(c);
index d53bd6fcb42877106dea1c2e8500c31f2614f15a..0880f2c388a901fd318ac39856e4105b98e4d09d 100644 (file)
@@ -554,10 +554,10 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
        int timeout;
        unsigned long start_rip;
        struct create_idle c_idle = {
-               .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle),
                .cpu = cpu,
                .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
        };
+       INIT_WORK(&c_idle.work, do_fork_idle);
 
        /* allocate memory for gdts of secondary cpus. Hotplug is considered */
        if (!cpu_gdt_descr[cpu].address &&
index 02f0f61f5b1131a511851546393ef06665787507..c28c342c162f0a90d3ad6e50ba0fb1d5ecd132a7 100644 (file)
@@ -25,6 +25,8 @@ static int save_stack_stack(void *data, char *name)
 static void save_stack_address(void *data, unsigned long addr, int reliable)
 {
        struct stack_trace *trace = data;
+       if (!reliable)
+               return;
        if (trace->skip > 0) {
                trace->skip--;
                return;
@@ -37,6 +39,8 @@ static void
 save_stack_address_nosched(void *data, unsigned long addr, int reliable)
 {
        struct stack_trace *trace = (struct stack_trace *)data;
+       if (!reliable)
+               return;
        if (in_sched_functions(addr))
                return;
        if (trace->skip > 0) {
index 43517e324be83e73096fe28a39ec5275c9a378e0..f14cfd9d1f94c1a634833da25e86eea9cb43b864 100644 (file)
@@ -28,7 +28,8 @@ EXPORT_SYMBOL_GPL(tsc_khz);
 static int __init tsc_setup(char *str)
 {
        printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
-                               "cannot disable TSC.\n");
+                               "cannot disable TSC completely.\n");
+       mark_tsc_unstable("user disabled TSC");
        return 1;
 }
 #else
index 3f82427745802f0e30ff19ff5ed5aee7e50d7fa2..b6be812fac0502cd2caccc19dcec0a147a0dc3fa 100644 (file)
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 #define __syscall_clobber "r11","cx","memory"
-#define __pa_vsymbol(x)                        \
-       ({unsigned long v;              \
-       extern char __vsyscall_0;       \
-         asm("" : "=r" (v) : "0" (x)); \
-         ((v - VSYSCALL_START) + __pa_symbol(&__vsyscall_0)); })
 
 /*
  * vsyscall_gtod_data contains data that is :
@@ -102,7 +97,7 @@ static __always_inline void do_get_tz(struct timezone * tz)
 static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
 {
        int ret;
-       asm volatile("vsysc2: syscall"
+       asm volatile("syscall"
                : "=a" (ret)
                : "0" (__NR_gettimeofday),"D" (tv),"S" (tz)
                : __syscall_clobber );
@@ -112,7 +107,7 @@ static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
 static __always_inline long time_syscall(long *t)
 {
        long secs;
-       asm volatile("vsysc1: syscall"
+       asm volatile("syscall"
                : "=a" (secs)
                : "0" (__NR_time),"D" (t) : __syscall_clobber);
        return secs;
@@ -227,50 +222,10 @@ long __vsyscall(3) venosys_1(void)
 }
 
 #ifdef CONFIG_SYSCTL
-
-#define SYSCALL 0x050f
-#define NOP2    0x9090
-
-/*
- * NOP out syscall in vsyscall page when not needed.
- */
-static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
-                        void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-       extern u16 vsysc1, vsysc2;
-       u16 __iomem *map1;
-       u16 __iomem *map2;
-       int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
-       if (!write)
-               return ret;
-       /* gcc has some trouble with __va(__pa()), so just do it this
-          way. */
-       map1 = ioremap(__pa_vsymbol(&vsysc1), 2);
-       if (!map1)
-               return -ENOMEM;
-       map2 = ioremap(__pa_vsymbol(&vsysc2), 2);
-       if (!map2) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       if (!vsyscall_gtod_data.sysctl_enabled) {
-               writew(SYSCALL, map1);
-               writew(SYSCALL, map2);
-       } else {
-               writew(NOP2, map1);
-               writew(NOP2, map2);
-       }
-       iounmap(map2);
-out:
-       iounmap(map1);
-       return ret;
-}
-
 static ctl_table kernel_table2[] = {
        { .procname = "vsyscall64",
          .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int),
-         .mode = 0644,
-         .proc_handler = vsyscall_sysctl_change },
+         .mode = 0644 },
        {}
 };
 
@@ -279,7 +234,6 @@ static ctl_table kernel_root_table2[] = {
          .child = kernel_table2 },
        {}
 };
-
 #endif
 
 /* Assume __initcall executes before all user space. Hopefully kmod
index 5afdde4895dcefe823e0e500df57d977a7ffa350..cccb38a59653bff74271593004f995a457645b54 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/lguest_launcher.h>
 #include <linux/virtio_console.h>
 #include <linux/pm.h>
+#include <asm/lguest.h>
 #include <asm/paravirt.h>
 #include <asm/param.h>
 #include <asm/page.h>
  * behaving in simplified but equivalent ways.  In particular, the Guest is the
  * same kernel as the Host (or at least, built from the same source code). :*/
 
-/* Declarations for definitions in lguest_guest.S */
-extern char lguest_noirq_start[], lguest_noirq_end[];
-extern const char lgstart_cli[], lgend_cli[];
-extern const char lgstart_sti[], lgend_sti[];
-extern const char lgstart_popf[], lgend_popf[];
-extern const char lgstart_pushf[], lgend_pushf[];
-extern const char lgstart_iret[], lgend_iret[];
-extern void lguest_iret(void);
-
 struct lguest_data lguest_data = {
        .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
        .noirq_start = (u32)lguest_noirq_start,
@@ -489,7 +481,7 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
        *pmdp = pmdval;
        lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
-                  (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+                  (__pa(pmdp)&(PAGE_SIZE-1)), 0);
 }
 
 /* There are a couple of legacy places where the kernel sets a PTE, but we
index bb652f5a93fb9c6e73e1fa09dd97617d9c41c574..a02a14f0f324f9a3392810a46d587dfcda23a157 100644 (file)
@@ -172,8 +172,9 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
 }
 
 /*
- * The head.S code sets up the kernel high mapping from:
- * __START_KERNEL_map to __START_KERNEL_map + KERNEL_TEXT_SIZE
+ * The head.S code sets up the kernel high mapping:
+ *
+ *   from __START_KERNEL_map to __START_KERNEL_map + size (== _end-_text)
  *
  * phys_addr holds the negative offset to the kernel, which is added
  * to the compile time generated pmds. This results in invalid pmds up
@@ -515,14 +516,6 @@ void __init mem_init(void)
 
        /* clear_bss() already clear the empty_zero_page */
 
-       /* temporary debugging - double check it's true: */
-       {
-               int i;
-
-               for (i = 0; i < 1024; i++)
-                       WARN_ON_ONCE(empty_zero_page[i]);
-       }
-
        reservedpages = 0;
 
        /* this will put all low memory onto the freelists */
index 464d8fc21ce69b67d8d8bf057f5a57ef6a84c677..14e48b5a94ba193c1cb4acc667482e05905d373e 100644 (file)
@@ -44,6 +44,12 @@ static inline unsigned long highmap_end_pfn(void)
 
 #endif
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+# define debug_pagealloc 1
+#else
+# define debug_pagealloc 0
+#endif
+
 static inline int
 within(unsigned long addr, unsigned long start, unsigned long end)
 {
@@ -355,45 +361,48 @@ out_unlock:
 
 static LIST_HEAD(page_pool);
 static unsigned long pool_size, pool_pages, pool_low;
-static unsigned long pool_used, pool_failed, pool_refill;
+static unsigned long pool_used, pool_failed;
 
-static void cpa_fill_pool(void)
+static void cpa_fill_pool(struct page **ret)
 {
-       struct page *p;
        gfp_t gfp = GFP_KERNEL;
+       unsigned long flags;
+       struct page *p;
 
-       /* Do not allocate from interrupt context */
-       if (in_irq() || irqs_disabled())
-               return;
        /*
-        * Check unlocked. I does not matter when we have one more
-        * page in the pool. The bit lock avoids recursive pool
-        * allocations:
+        * Avoid recursion (on debug-pagealloc) and also signal
+        * our priority to get to these pagetables:
         */
-       if (pool_pages >= pool_size || test_and_set_bit_lock(0, &pool_refill))
+       if (current->flags & PF_MEMALLOC)
                return;
+       current->flags |= PF_MEMALLOC;
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
        /*
-        * We could do:
-        * gfp = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
-        * but this fails on !PREEMPT kernels
+        * Allocate atomically from atomic contexts:
         */
-       gfp =  GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
-#endif
+       if (in_atomic() || irqs_disabled() || debug_pagealloc)
+               gfp =  GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
 
-       while (pool_pages < pool_size) {
+       while (pool_pages < pool_size || (ret && !*ret)) {
                p = alloc_pages(gfp, 0);
                if (!p) {
                        pool_failed++;
                        break;
                }
-               spin_lock_irq(&pgd_lock);
+               /*
+                * If the call site needs a page right now, provide it:
+                */
+               if (ret && !*ret) {
+                       *ret = p;
+                       continue;
+               }
+               spin_lock_irqsave(&pgd_lock, flags);
                list_add(&p->lru, &page_pool);
                pool_pages++;
-               spin_unlock_irq(&pgd_lock);
+               spin_unlock_irqrestore(&pgd_lock, flags);
        }
-       clear_bit_unlock(0, &pool_refill);
+
+       current->flags &= ~PF_MEMALLOC;
 }
 
 #define SHIFT_MB               (20 - PAGE_SHIFT)
@@ -414,11 +423,15 @@ void __init cpa_init(void)
         * GiB. Shift MiB to Gib and multiply the result by
         * POOL_PAGES_PER_GB:
         */
-       gb = ((si.totalram >> SHIFT_MB) + ROUND_MB_GB) >> SHIFT_MB_GB;
-       pool_size = POOL_PAGES_PER_GB * gb;
+       if (debug_pagealloc) {
+               gb = ((si.totalram >> SHIFT_MB) + ROUND_MB_GB) >> SHIFT_MB_GB;
+               pool_size = POOL_PAGES_PER_GB * gb;
+       } else {
+               pool_size = 1;
+       }
        pool_low = pool_size;
 
-       cpa_fill_pool();
+       cpa_fill_pool(NULL);
        printk(KERN_DEBUG
               "CPA: page pool initialized %lu of %lu pages preallocated\n",
               pool_pages, pool_size);
@@ -440,16 +453,20 @@ static int split_large_page(pte_t *kpte, unsigned long address)
        spin_lock_irqsave(&pgd_lock, flags);
        if (list_empty(&page_pool)) {
                spin_unlock_irqrestore(&pgd_lock, flags);
-               return -ENOMEM;
+               base = NULL;
+               cpa_fill_pool(&base);
+               if (!base)
+                       return -ENOMEM;
+               spin_lock_irqsave(&pgd_lock, flags);
+       } else {
+               base = list_first_entry(&page_pool, struct page, lru);
+               list_del(&base->lru);
+               pool_pages--;
+
+               if (pool_pages < pool_low)
+                       pool_low = pool_pages;
        }
 
-       base = list_first_entry(&page_pool, struct page, lru);
-       list_del(&base->lru);
-       pool_pages--;
-
-       if (pool_pages < pool_low)
-               pool_low = pool_pages;
-
        /*
         * Check for races, another CPU might have split this page
         * up for us already:
@@ -734,7 +751,8 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
                cpa_flush_all(cache);
 
 out:
-       cpa_fill_pool();
+       cpa_fill_pool(NULL);
+
        return ret;
 }
 
@@ -897,7 +915,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
         * Try to refill the page pool here. We can do this only after
         * the tlb flush.
         */
-       cpa_fill_pool();
+       cpa_fill_pool(NULL);
 }
 
 #ifdef CONFIG_HIBERNATION
index f385a4b4a484e36d3262ca154b96dcfd596b7510..b8bd0c4aa02e4d0bae958c2fec0fa492c49ca583 100644 (file)
@@ -48,7 +48,7 @@ obj-$(VDSO64-y)                       += vdso-syms.lds
 # Match symbols in the DSO that look like VDSO*; produce a file of constants.
 #
 sed-vdsosym := -e 's/^00*/0/' \
-       -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p'
+       -e 's/^\([[:xdigit:]]*\) . \(VDSO[[:alnum:]_]*\)$$/\2 = 0x\1;/p'
 quiet_cmd_vdsosym = VDSOSYM $@
       cmd_vdsosym = $(NM) $< | sed -n $(sed-vdsosym) | LC_ALL=C sort > $@
 
index fbc24358ada030bf3cc329682ee617374229dd3a..4fbcce758b04deb227729ebd6b445009cb37777a 100644 (file)
@@ -113,7 +113,7 @@ int atapi_enabled = 1;
 module_param(atapi_enabled, int, 0444);
 MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
 
-int atapi_dmadir = 0;
+static int atapi_dmadir = 0;
 module_param(atapi_dmadir, int, 0444);
 MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
 
@@ -6567,6 +6567,8 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
        ata_lpm_enable(host);
 
        rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
+       if (rc == 0)
+               host->dev->power.power_state = mesg;
        return rc;
 }
 
@@ -6585,6 +6587,7 @@ void ata_host_resume(struct ata_host *host)
 {
        ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET,
                            ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+       host->dev->power.power_state = PMSG_ON;
 
        /* reenable link pm */
        ata_lpm_disable(host);
index 6036dedfe377579b494a85cff095a793d2b3331d..aa884f71a12a4733d9de5dab53a42650abdbfd84 100644 (file)
@@ -56,7 +56,6 @@ enum {
 extern unsigned int ata_print_id;
 extern struct workqueue_struct *ata_aux_wq;
 extern int atapi_enabled;
-extern int atapi_dmadir;
 extern int atapi_passthru16;
 extern int libata_fua;
 extern int libata_noacpi;
index 78b151c4d20f94b0bccecc1acb3540e14b77cdc9..5c3142b6f1fcdf102a92b79dec3b9d000b4d4a3b 100644 (file)
@@ -110,8 +110,8 @@ static int rtc_has_irq = 1;
 #define hpet_set_rtc_irq_bit(arg)              0
 #define hpet_rtc_timer_init()                  do { } while (0)
 #define hpet_rtc_dropped_irq()                 0
-#define hpet_register_irq_handler(h)           0
-#define hpet_unregister_irq_handler(h)         0
+#define hpet_register_irq_handler(h)           ({ 0; })
+#define hpet_unregister_irq_handler(h)         ({ 0; })
 #ifdef RTC_IRQ
 static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
 {
index fea2d3ed9cbdacd57661f5a1a5227a1bde2ffeb2..85e2ba7fcfbab1b4533079da8bd812f22203952d 100644 (file)
@@ -47,7 +47,7 @@ static LIST_HEAD(notify_list);
 
 static struct cn_dev cdev;
 
-int cn_already_initialized = 0;
+static int cn_already_initialized;
 
 /*
  * msg->seq and msg->ack are used to determine message genealogy.
index 7e73cbaa4121047ffe6eb7c5f137357e0739c58e..46bc197a047fe84329f4ec868e351ae0438cac2e 100644 (file)
@@ -109,15 +109,17 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
        struct client *client;
        unsigned long flags;
 
-       device = fw_device_from_devt(inode->i_rdev);
+       device = fw_device_get_by_devt(inode->i_rdev);
        if (device == NULL)
                return -ENODEV;
 
        client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (client == NULL)
+       if (client == NULL) {
+               fw_device_put(device);
                return -ENOMEM;
+       }
 
-       client->device = fw_device_get(device);
+       client->device = device;
        INIT_LIST_HEAD(&client->event_list);
        INIT_LIST_HEAD(&client->resource_list);
        spin_lock_init(&client->lock);
@@ -644,6 +646,10 @@ static int ioctl_create_iso_context(struct client *client, void *buffer)
        struct fw_cdev_create_iso_context *request = buffer;
        struct fw_iso_context *context;
 
+       /* We only support one context at this time. */
+       if (client->iso_context != NULL)
+               return -EBUSY;
+
        if (request->channel > 63)
                return -EINVAL;
 
@@ -790,8 +796,9 @@ static int ioctl_start_iso(struct client *client, void *buffer)
 {
        struct fw_cdev_start_iso *request = buffer;
 
-       if (request->handle != 0)
+       if (client->iso_context == NULL || request->handle != 0)
                return -EINVAL;
+
        if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
                if (request->tags == 0 || request->tags > 15)
                        return -EINVAL;
@@ -808,7 +815,7 @@ static int ioctl_stop_iso(struct client *client, void *buffer)
 {
        struct fw_cdev_stop_iso *request = buffer;
 
-       if (request->handle != 0)
+       if (client->iso_context == NULL || request->handle != 0)
                return -EINVAL;
 
        return fw_iso_context_stop(client->iso_context);
index de9066e69adfbeea440d31cec1c0945f337db728..2ab13e0f3469c2f3ccd4b68d120be57f4107c3a6 100644 (file)
@@ -358,12 +358,9 @@ static ssize_t
 guid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct fw_device *device = fw_device(dev);
-       u64 guid;
 
-       guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
-
-       return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
-                       (unsigned long long)guid);
+       return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n",
+                       device->config_rom[3], device->config_rom[4]);
 }
 
 static struct device_attribute fw_device_attributes[] = {
@@ -610,12 +607,14 @@ static DECLARE_RWSEM(idr_rwsem);
 static DEFINE_IDR(fw_device_idr);
 int fw_cdev_major;
 
-struct fw_device *fw_device_from_devt(dev_t devt)
+struct fw_device *fw_device_get_by_devt(dev_t devt)
 {
        struct fw_device *device;
 
        down_read(&idr_rwsem);
        device = idr_find(&fw_device_idr, MINOR(devt));
+       if (device)
+               fw_device_get(device);
        up_read(&idr_rwsem);
 
        return device;
@@ -627,13 +626,14 @@ static void fw_device_shutdown(struct work_struct *work)
                container_of(work, struct fw_device, work.work);
        int minor = MINOR(device->device.devt);
 
-       down_write(&idr_rwsem);
-       idr_remove(&fw_device_idr, minor);
-       up_write(&idr_rwsem);
-
        fw_device_cdev_remove(device);
        device_for_each_child(&device->device, NULL, shutdown_unit);
        device_unregister(&device->device);
+
+       down_write(&idr_rwsem);
+       idr_remove(&fw_device_idr, minor);
+       up_write(&idr_rwsem);
+       fw_device_put(device);
 }
 
 static struct device_type fw_device_type = {
@@ -682,10 +682,13 @@ static void fw_device_init(struct work_struct *work)
        }
 
        err = -ENOMEM;
+
+       fw_device_get(device);
        down_write(&idr_rwsem);
        if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
                err = idr_get_new(&fw_device_idr, device, &minor);
        up_write(&idr_rwsem);
+
        if (err < 0)
                goto error;
 
@@ -717,13 +720,22 @@ static void fw_device_init(struct work_struct *work)
         */
        if (atomic_cmpxchg(&device->state,
                    FW_DEVICE_INITIALIZING,
-                   FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
+                   FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) {
                fw_device_shutdown(&device->work.work);
-       else
-               fw_notify("created new fw device %s "
-                         "(%d config rom retries, S%d00)\n",
-                         device->device.bus_id, device->config_rom_retries,
-                         1 << device->max_speed);
+       } else {
+               if (device->config_rom_retries)
+                       fw_notify("created device %s: GUID %08x%08x, S%d00, "
+                                 "%d config ROM retries\n",
+                                 device->device.bus_id,
+                                 device->config_rom[3], device->config_rom[4],
+                                 1 << device->max_speed,
+                                 device->config_rom_retries);
+               else
+                       fw_notify("created device %s: GUID %08x%08x, S%d00\n",
+                                 device->device.bus_id,
+                                 device->config_rom[3], device->config_rom[4],
+                                 1 << device->max_speed);
+       }
 
        /*
         * Reschedule the IRM work if we just finished reading the
@@ -741,7 +753,9 @@ static void fw_device_init(struct work_struct *work)
        idr_remove(&fw_device_idr, minor);
        up_write(&idr_rwsem);
  error:
-       put_device(&device->device);
+       fw_device_put(device);          /* fw_device_idr's reference */
+
+       put_device(&device->device);    /* our reference */
 }
 
 static int update_unit(struct device *dev, void *data)
index 0854fe2bc11085943d0b7edcdef5884d8996c60c..43808c02793e27682892da07ecfd1f5750a396e4 100644 (file)
@@ -77,13 +77,13 @@ fw_device_is_shutdown(struct fw_device *device)
 }
 
 struct fw_device *fw_device_get(struct fw_device *device);
+struct fw_device *fw_device_get_by_devt(dev_t devt);
 void fw_device_put(struct fw_device *device);
 int fw_device_enable_phys_dma(struct fw_device *device);
 
 void fw_device_cdev_update(struct fw_device *device);
 void fw_device_cdev_remove(struct fw_device *device);
 
-struct fw_device *fw_device_from_devt(dev_t devt);
 extern int fw_cdev_major;
 
 struct fw_unit {
index 19ece9b6d7425906d6cff48cee2ebfba172f5141..5259491580fccc8fa47a42fcad98b469441522e6 100644 (file)
  * and many others.
  */
 
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/mod_devicetable.h>
-#include <linux/device.h>
 #include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/blkdev.h>
 #include <linux/string.h>
 #include <linux/stringify.h>
 #include <linux/timer.h>
@@ -47,9 +48,9 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 
-#include "fw-transaction.h"
-#include "fw-topology.h"
 #include "fw-device.h"
+#include "fw-topology.h"
+#include "fw-transaction.h"
 
 /*
  * So far only bridges from Oxford Semiconductor are known to support
@@ -82,6 +83,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
  *   Don't use this with devices which don't have this bug.
  *
+ * - delay inquiry
+ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
+ *
  * - override internal blacklist
  *   Instead of adding to the built-in blacklist, use only the workarounds
  *   specified in the module load parameter.
@@ -91,6 +95,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
 #define SBP2_WORKAROUND_INQUIRY_36     0x2
 #define SBP2_WORKAROUND_MODE_SENSE_8   0x4
 #define SBP2_WORKAROUND_FIX_CAPACITY   0x8
+#define SBP2_WORKAROUND_DELAY_INQUIRY  0x10
+#define SBP2_INQUIRY_DELAY             12
 #define SBP2_WORKAROUND_OVERRIDE       0x100
 
 static int sbp2_param_workarounds;
@@ -100,6 +106,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
        ", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
        ", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
        ", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+       ", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
        ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
        ", or a combination)");
 
@@ -132,6 +139,7 @@ struct sbp2_logical_unit {
        int generation;
        int retries;
        struct delayed_work work;
+       bool blocked;
 };
 
 /*
@@ -141,16 +149,18 @@ struct sbp2_logical_unit {
 struct sbp2_target {
        struct kref kref;
        struct fw_unit *unit;
+       const char *bus_id;
+       struct list_head lu_list;
 
        u64 management_agent_address;
        int directory_id;
        int node_id;
        int address_high;
-
-       unsigned workarounds;
-       struct list_head lu_list;
-
+       unsigned int workarounds;
        unsigned int mgt_orb_timeout;
+
+       int dont_block; /* counter for each logical unit */
+       int blocked;    /* ditto */
 };
 
 /*
@@ -160,7 +170,7 @@ struct sbp2_target {
  */
 #define SBP2_MIN_LOGIN_ORB_TIMEOUT     5000U   /* Timeout in ms */
 #define SBP2_MAX_LOGIN_ORB_TIMEOUT     40000U  /* Timeout in ms */
-#define SBP2_ORB_TIMEOUT               2000    /* Timeout in ms */
+#define SBP2_ORB_TIMEOUT               2000U   /* Timeout in ms */
 #define SBP2_ORB_NULL                  0x80000000
 #define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
 
@@ -297,7 +307,7 @@ struct sbp2_command_orb {
 static const struct {
        u32 firmware_revision;
        u32 model;
-       unsigned workarounds;
+       unsigned int workarounds;
 } sbp2_workarounds_table[] = {
        /* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
                .firmware_revision      = 0x002800,
@@ -305,6 +315,11 @@ static const struct {
                .workarounds            = SBP2_WORKAROUND_INQUIRY_36 |
                                          SBP2_WORKAROUND_MODE_SENSE_8,
        },
+       /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
+               .firmware_revision      = 0x002800,
+               .model                  = 0x000000,
+               .workarounds            = SBP2_WORKAROUND_DELAY_INQUIRY,
+       },
        /* Initio bridges, actually only needed for some older ones */ {
                .firmware_revision      = 0x000200,
                .model                  = ~0,
@@ -501,6 +516,9 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
        unsigned int timeout;
        int retval = -ENOMEM;
 
+       if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device))
+               return 0;
+
        orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
        if (orb == NULL)
                return -ENOMEM;
@@ -553,20 +571,20 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
 
        retval = -EIO;
        if (sbp2_cancel_orbs(lu) == 0) {
-               fw_error("orb reply timed out, rcode=0x%02x\n",
-                        orb->base.rcode);
+               fw_error("%s: orb reply timed out, rcode=0x%02x\n",
+                        lu->tgt->bus_id, orb->base.rcode);
                goto out;
        }
 
        if (orb->base.rcode != RCODE_COMPLETE) {
-               fw_error("management write failed, rcode 0x%02x\n",
-                        orb->base.rcode);
+               fw_error("%s: management write failed, rcode 0x%02x\n",
+                        lu->tgt->bus_id, orb->base.rcode);
                goto out;
        }
 
        if (STATUS_GET_RESPONSE(orb->status) != 0 ||
            STATUS_GET_SBP_STATUS(orb->status) != 0) {
-               fw_error("error status: %d:%d\n",
+               fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id,
                         STATUS_GET_RESPONSE(orb->status),
                         STATUS_GET_SBP_STATUS(orb->status));
                goto out;
@@ -590,29 +608,147 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
 
 static void
 complete_agent_reset_write(struct fw_card *card, int rcode,
-                          void *payload, size_t length, void *data)
+                          void *payload, size_t length, void *done)
+{
+       complete(done);
+}
+
+static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
 {
-       struct fw_transaction *t = data;
+       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       DECLARE_COMPLETION_ONSTACK(done);
+       struct fw_transaction t;
+       static u32 z;
+
+       fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST,
+                       lu->tgt->node_id, lu->generation, device->max_speed,
+                       lu->command_block_agent_address + SBP2_AGENT_RESET,
+                       &z, sizeof(z), complete_agent_reset_write, &done);
+       wait_for_completion(&done);
+}
 
-       kfree(t);
+static void
+complete_agent_reset_write_no_wait(struct fw_card *card, int rcode,
+                                  void *payload, size_t length, void *data)
+{
+       kfree(data);
 }
 
-static int sbp2_agent_reset(struct sbp2_logical_unit *lu)
+static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
 {
        struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
        struct fw_transaction *t;
-       static u32 zero;
+       static u32 z;
 
-       t = kzalloc(sizeof(*t), GFP_ATOMIC);
+       t = kmalloc(sizeof(*t), GFP_ATOMIC);
        if (t == NULL)
-               return -ENOMEM;
+               return;
 
        fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
                        lu->tgt->node_id, lu->generation, device->max_speed,
                        lu->command_block_agent_address + SBP2_AGENT_RESET,
-                       &zero, sizeof(zero), complete_agent_reset_write, t);
+                       &z, sizeof(z), complete_agent_reset_write_no_wait, t);
+}
 
-       return 0;
+static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation)
+{
+       struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card;
+       unsigned long flags;
+
+       /* serialize with comparisons of lu->generation and card->generation */
+       spin_lock_irqsave(&card->lock, flags);
+       lu->generation = generation;
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
+{
+       /*
+        * We may access dont_block without taking card->lock here:
+        * All callers of sbp2_allow_block() and all callers of sbp2_unblock()
+        * are currently serialized against each other.
+        * And a wrong result in sbp2_conditionally_block()'s access of
+        * dont_block is rather harmless, it simply misses its first chance.
+        */
+       --lu->tgt->dont_block;
+}
+
+/*
+ * Blocks lu->tgt if all of the following conditions are met:
+ *   - Login, INQUIRY, and high-level SCSI setup of all of the target's
+ *     logical units have been finished (indicated by dont_block == 0).
+ *   - lu->generation is stale.
+ *
+ * Note, scsi_block_requests() must be called while holding card->lock,
+ * otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to
+ * unblock the target.
+ */
+static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
+{
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct Scsi_Host *shost =
+               container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (!tgt->dont_block && !lu->blocked &&
+           lu->generation != card->generation) {
+               lu->blocked = true;
+               if (++tgt->blocked == 1) {
+                       scsi_block_requests(shost);
+                       fw_notify("blocked %s\n", lu->tgt->bus_id);
+               }
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/*
+ * Unblocks lu->tgt as soon as all its logical units can be unblocked.
+ * Note, it is harmless to run scsi_unblock_requests() outside the
+ * card->lock protected section.  On the other hand, running it inside
+ * the section might clash with shost->host_lock.
+ */
+static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
+{
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct Scsi_Host *shost =
+               container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+       unsigned long flags;
+       bool unblock = false;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (lu->blocked && lu->generation == card->generation) {
+               lu->blocked = false;
+               unblock = --tgt->blocked == 0;
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       if (unblock) {
+               scsi_unblock_requests(shost);
+               fw_notify("unblocked %s\n", lu->tgt->bus_id);
+       }
+}
+
+/*
+ * Prevents future blocking of tgt and unblocks it.
+ * Note, it is harmless to run scsi_unblock_requests() outside the
+ * card->lock protected section.  On the other hand, running it inside
+ * the section might clash with shost->host_lock.
+ */
+static void sbp2_unblock(struct sbp2_target *tgt)
+{
+       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct Scsi_Host *shost =
+               container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       ++tgt->dont_block;
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       scsi_unblock_requests(shost);
 }
 
 static void sbp2_release_target(struct kref *kref)
@@ -621,23 +757,24 @@ static void sbp2_release_target(struct kref *kref)
        struct sbp2_logical_unit *lu, *next;
        struct Scsi_Host *shost =
                container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
-       struct fw_device *device = fw_device(tgt->unit->device.parent);
+
+       /* prevent deadlocks */
+       sbp2_unblock(tgt);
 
        list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
-               if (lu->sdev)
+               if (lu->sdev) {
                        scsi_remove_device(lu->sdev);
-
-               if (!fw_device_is_shutdown(device))
-                       sbp2_send_management_orb(lu, tgt->node_id,
-                                       lu->generation, SBP2_LOGOUT_REQUEST,
-                                       lu->login_id, NULL);
+                       scsi_device_put(lu->sdev);
+               }
+               sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
+                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
 
                fw_core_remove_address_handler(&lu->address_handler);
                list_del(&lu->link);
                kfree(lu);
        }
        scsi_remove_host(shost);
-       fw_notify("released %s\n", tgt->unit->device.bus_id);
+       fw_notify("released %s\n", tgt->bus_id);
 
        put_device(&tgt->unit->device);
        scsi_host_put(shost);
@@ -666,33 +803,43 @@ static void sbp2_login(struct work_struct *work)
 {
        struct sbp2_logical_unit *lu =
                container_of(work, struct sbp2_logical_unit, work.work);
-       struct Scsi_Host *shost =
-               container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]);
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_device *device = fw_device(tgt->unit->device.parent);
+       struct Scsi_Host *shost;
        struct scsi_device *sdev;
        struct scsi_lun eight_bytes_lun;
-       struct fw_unit *unit = lu->tgt->unit;
-       struct fw_device *device = fw_device(unit->device.parent);
        struct sbp2_login_response response;
        int generation, node_id, local_node_id;
 
+       if (fw_device_is_shutdown(device))
+               goto out;
+
        generation    = device->generation;
        smp_rmb();    /* node_id must not be older than generation */
        node_id       = device->node_id;
        local_node_id = device->card->node_id;
 
+       /* If this is a re-login attempt, log out, or we might be rejected. */
+       if (lu->sdev)
+               sbp2_send_management_orb(lu, device->node_id, generation,
+                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+
        if (sbp2_send_management_orb(lu, node_id, generation,
                                SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
-               if (lu->retries++ < 5)
+               if (lu->retries++ < 5) {
                        sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
-               else
-                       fw_error("failed to login to %s LUN %04x\n",
-                                unit->device.bus_id, lu->lun);
+               } else {
+                       fw_error("%s: failed to login to LUN %04x\n",
+                                tgt->bus_id, lu->lun);
+                       /* Let any waiting I/O fail from now on. */
+                       sbp2_unblock(lu->tgt);
+               }
                goto out;
        }
 
-       lu->generation        = generation;
-       lu->tgt->node_id      = node_id;
-       lu->tgt->address_high = local_node_id << 16;
+       tgt->node_id      = node_id;
+       tgt->address_high = local_node_id << 16;
+       sbp2_set_generation(lu, generation);
 
        /* Get command block agent offset and login id. */
        lu->command_block_agent_address =
@@ -700,8 +847,8 @@ static void sbp2_login(struct work_struct *work)
                response.command_block_agent.low;
        lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
 
-       fw_notify("logged in to %s LUN %04x (%d retries)\n",
-                 unit->device.bus_id, lu->lun, lu->retries);
+       fw_notify("%s: logged in to LUN %04x (%d retries)\n",
+                 tgt->bus_id, lu->lun, lu->retries);
 
 #if 0
        /* FIXME: The linux1394 sbp2 does this last step. */
@@ -711,26 +858,62 @@ static void sbp2_login(struct work_struct *work)
        PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
        sbp2_agent_reset(lu);
 
+       /* This was a re-login. */
+       if (lu->sdev) {
+               sbp2_cancel_orbs(lu);
+               sbp2_conditionally_unblock(lu);
+               goto out;
+       }
+
+       if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
+               ssleep(SBP2_INQUIRY_DELAY);
+
        memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
        eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
        eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
+       shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
 
        sdev = __scsi_add_device(shost, 0, 0,
                                 scsilun_to_int(&eight_bytes_lun), lu);
-       if (IS_ERR(sdev)) {
-               sbp2_send_management_orb(lu, node_id, generation,
-                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
-               /*
-                * Set this back to sbp2_login so we fall back and
-                * retry login on bus reset.
-                */
-               PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
-       } else {
-               lu->sdev = sdev;
+       /*
+        * FIXME:  We are unable to perform reconnects while in sbp2_login().
+        * Therefore __scsi_add_device() will get into trouble if a bus reset
+        * happens in parallel.  It will either fail or leave us with an
+        * unusable sdev.  As a workaround we check for this and retry the
+        * whole login and SCSI probing.
+        */
+
+       /* Reported error during __scsi_add_device() */
+       if (IS_ERR(sdev))
+               goto out_logout_login;
+
+       /* Unreported error during __scsi_add_device() */
+       smp_rmb(); /* get current card generation */
+       if (generation != device->card->generation) {
+               scsi_remove_device(sdev);
                scsi_device_put(sdev);
+               goto out_logout_login;
        }
+
+       /* No error during __scsi_add_device() */
+       lu->sdev = sdev;
+       sbp2_allow_block(lu);
+       goto out;
+
+ out_logout_login:
+       smp_rmb(); /* generation may have changed */
+       generation = device->generation;
+       smp_rmb(); /* node_id must not be older than generation */
+
+       sbp2_send_management_orb(lu, device->node_id, generation,
+                                SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+       /*
+        * If a bus reset happened, sbp2_update will have requeued
+        * lu->work already.  Reset the work from reconnect to login.
+        */
+       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
  out:
-       sbp2_target_put(lu->tgt);
+       sbp2_target_put(tgt);
 }
 
 static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
@@ -755,6 +938,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
        lu->sdev = NULL;
        lu->lun  = lun_entry & 0xffff;
        lu->retries = 0;
+       lu->blocked = false;
+       ++tgt->dont_block;
        INIT_LIST_HEAD(&lu->orb_list);
        INIT_DELAYED_WORK(&lu->work, sbp2_login);
 
@@ -813,7 +998,7 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
                        if (timeout > tgt->mgt_orb_timeout)
                                fw_notify("%s: config rom contains %ds "
                                          "management ORB timeout, limiting "
-                                         "to %ds\n", tgt->unit->device.bus_id,
+                                         "to %ds\n", tgt->bus_id,
                                          timeout / 1000,
                                          tgt->mgt_orb_timeout / 1000);
                        break;
@@ -836,12 +1021,12 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
                                  u32 firmware_revision)
 {
        int i;
-       unsigned w = sbp2_param_workarounds;
+       unsigned int w = sbp2_param_workarounds;
 
        if (w)
                fw_notify("Please notify linux1394-devel@lists.sourceforge.net "
                          "if you need the workarounds parameter for %s\n",
-                         tgt->unit->device.bus_id);
+                         tgt->bus_id);
 
        if (w & SBP2_WORKAROUND_OVERRIDE)
                goto out;
@@ -863,8 +1048,7 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
        if (w)
                fw_notify("Workarounds for %s: 0x%x "
                          "(firmware_revision 0x%06x, model_id 0x%06x)\n",
-                         tgt->unit->device.bus_id,
-                         w, firmware_revision, model);
+                         tgt->bus_id, w, firmware_revision, model);
        tgt->workarounds = w;
 }
 
@@ -888,6 +1072,7 @@ static int sbp2_probe(struct device *dev)
        tgt->unit = unit;
        kref_init(&tgt->kref);
        INIT_LIST_HEAD(&tgt->lu_list);
+       tgt->bus_id = unit->device.bus_id;
 
        if (fw_device_enable_phys_dma(device) < 0)
                goto fail_shost_put;
@@ -938,10 +1123,13 @@ static void sbp2_reconnect(struct work_struct *work)
 {
        struct sbp2_logical_unit *lu =
                container_of(work, struct sbp2_logical_unit, work.work);
-       struct fw_unit *unit = lu->tgt->unit;
-       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_device *device = fw_device(tgt->unit->device.parent);
        int generation, node_id, local_node_id;
 
+       if (fw_device_is_shutdown(device))
+               goto out;
+
        generation    = device->generation;
        smp_rmb();    /* node_id must not be older than generation */
        node_id       = device->node_id;
@@ -950,10 +1138,17 @@ static void sbp2_reconnect(struct work_struct *work)
        if (sbp2_send_management_orb(lu, node_id, generation,
                                     SBP2_RECONNECT_REQUEST,
                                     lu->login_id, NULL) < 0) {
-               if (lu->retries++ >= 5) {
-                       fw_error("failed to reconnect to %s\n",
-                                unit->device.bus_id);
-                       /* Fall back and try to log in again. */
+               /*
+                * If reconnect was impossible even though we are in the
+                * current generation, fall back and try to log in again.
+                *
+                * We could check for "Function rejected" status, but
+                * looking at the bus generation as simpler and more general.
+                */
+               smp_rmb(); /* get current card generation */
+               if (generation == device->card->generation ||
+                   lu->retries++ >= 5) {
+                       fw_error("%s: failed to reconnect\n", tgt->bus_id);
                        lu->retries = 0;
                        PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
                }
@@ -961,17 +1156,18 @@ static void sbp2_reconnect(struct work_struct *work)
                goto out;
        }
 
-       lu->generation        = generation;
-       lu->tgt->node_id      = node_id;
-       lu->tgt->address_high = local_node_id << 16;
+       tgt->node_id      = node_id;
+       tgt->address_high = local_node_id << 16;
+       sbp2_set_generation(lu, generation);
 
-       fw_notify("reconnected to %s LUN %04x (%d retries)\n",
-                 unit->device.bus_id, lu->lun, lu->retries);
+       fw_notify("%s: reconnected to LUN %04x (%d retries)\n",
+                 tgt->bus_id, lu->lun, lu->retries);
 
        sbp2_agent_reset(lu);
        sbp2_cancel_orbs(lu);
+       sbp2_conditionally_unblock(lu);
  out:
-       sbp2_target_put(lu->tgt);
+       sbp2_target_put(tgt);
 }
 
 static void sbp2_update(struct fw_unit *unit)
@@ -986,6 +1182,7 @@ static void sbp2_update(struct fw_unit *unit)
         * Iteration over tgt->lu_list is therefore safe here.
         */
        list_for_each_entry(lu, &tgt->lu_list, link) {
+               sbp2_conditionally_block(lu);
                lu->retries = 0;
                sbp2_queue_work(lu, 0);
        }
@@ -1063,7 +1260,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
 
        if (status != NULL) {
                if (STATUS_GET_DEAD(*status))
-                       sbp2_agent_reset(orb->lu);
+                       sbp2_agent_reset_no_wait(orb->lu);
 
                switch (STATUS_GET_RESPONSE(*status)) {
                case SBP2_STATUS_REQUEST_COMPLETE:
@@ -1089,6 +1286,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
                 * or when sending the write (less likely).
                 */
                result = DID_BUS_BUSY << 16;
+               sbp2_conditionally_block(orb->lu);
        }
 
        dma_unmap_single(device->card->device, orb->base.request_bus,
@@ -1197,7 +1395,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
        struct sbp2_logical_unit *lu = cmd->device->hostdata;
        struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
        struct sbp2_command_orb *orb;
-       unsigned max_payload;
+       unsigned int max_payload;
        int retval = SCSI_MLQUEUE_HOST_BUSY;
 
        /*
@@ -1275,6 +1473,10 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
 {
        struct sbp2_logical_unit *lu = sdev->hostdata;
 
+       /* (Re-)Adding logical units via the SCSI stack is not supported. */
+       if (!lu)
+               return -ENOSYS;
+
        sdev->allow_restart = 1;
 
        /*
@@ -1319,7 +1521,7 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
 {
        struct sbp2_logical_unit *lu = cmd->device->hostdata;
 
-       fw_notify("sbp2_scsi_abort\n");
+       fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id);
        sbp2_agent_reset(lu);
        sbp2_cancel_orbs(lu);
 
index 310e497b58380d5d348c29d9d890204e1cf47edf..c8d0e8715997475abe51e683ee5b5aff2f44109c 100644 (file)
@@ -670,8 +670,8 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
  * and attempt to recover if there are problems.  Returns  0 if everything's
  * ok; nonzero if the request has been terminated.
  */
-static
-int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
+static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
+                               int len, int ireason, int rw)
 {
        /*
         * ireason == 0: the drive wants to receive data from us
@@ -701,6 +701,9 @@ int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw)
                                drive->name, __FUNCTION__, ireason);
        }
 
+       if (rq->cmd_type == REQ_TYPE_ATA_PC)
+               rq->cmd_flags |= REQ_FAILED;
+
        cdrom_end_request(drive, 0);
        return -1;
 }
@@ -1071,11 +1074,11 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        /*
         * check which way to transfer data
         */
-       if (blk_fs_request(rq) || blk_pc_request(rq)) {
-               if (ide_cd_check_ireason(drive, len, ireason, write))
-                       return ide_stopped;
+       if (ide_cd_check_ireason(drive, rq, len, ireason, write))
+               return ide_stopped;
 
-               if (blk_fs_request(rq) && write == 0) {
+       if (blk_fs_request(rq)) {
+               if (write == 0) {
                        int nskip;
 
                        if (ide_cd_check_transfer_size(drive, len)) {
@@ -1101,16 +1104,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        if (ireason == 0) {
                write = 1;
                xferfunc = HWIF(drive)->atapi_output_bytes;
-       } else if (ireason == 2 || (ireason == 1 &&
-                  (blk_fs_request(rq) || blk_pc_request(rq)))) {
+       } else {
                write = 0;
                xferfunc = HWIF(drive)->atapi_input_bytes;
-       } else {
-               printk(KERN_ERR "%s: %s: The drive "
-                               "appears confused (ireason = 0x%02x). "
-                               "Trying to recover by ending request.\n",
-                               drive->name, __FUNCTION__, ireason);
-               goto end_request;
        }
 
        /*
@@ -1182,11 +1178,10 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                        else
                                rq->data += blen;
                }
+               if (!write && blk_sense_request(rq))
+                       rq->sense_len += blen;
        }
 
-       if (write && blk_sense_request(rq))
-               rq->sense_len += thislen;
-
        /*
         * pad, if necessary
         */
@@ -1931,6 +1926,7 @@ static const struct cd_list_entry ide_cd_quirks_list[] = {
        { "MATSHITADVD-ROM SR-8186", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
        { "MATSHITADVD-ROM SR-8176", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
        { "MATSHITADVD-ROM SR-8174", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
+       { "Optiarc DVD RW AD-5200A", NULL,   IDE_CD_FLAG_PLAY_AUDIO_OK      },
        { NULL, NULL, 0 }
 };
 
index 8f5bed471050d955713f5d5230aa7327ad993dec..39501d130256109ad50d06a6b904249e9163f08a 100644 (file)
@@ -867,7 +867,7 @@ static void idedisk_setup (ide_drive_t *drive)
 
        /* Only print cache size when it was specified */
        if (id->buf_size)
-               printk (" w/%dKiB Cache", id->buf_size/2);
+               printk(KERN_CONT " w/%dKiB Cache", id->buf_size / 2);
 
        printk(KERN_CONT ", CHS=%d/%d/%d\n",
                         drive->bios_cyl, drive->bios_head, drive->bios_sect);
@@ -949,7 +949,8 @@ static void ide_device_shutdown(ide_drive_t *drive)
                return;
        }
 
-       printk("Shutdown: %s\n", drive->name);
+       printk(KERN_INFO "Shutdown: %s\n", drive->name);
+
        drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
 }
 
index d0e7b537353e38ea1bb23ff6f0604f0d93777752..2de99e4be5c9b963ebfbf263884d6f55f1d82d56 100644 (file)
@@ -1,9 +1,13 @@
 /*
+ *  IDE DMA support (including IDE PCI BM-DMA).
+ *
  *  Copyright (C) 1995-1998   Mark Lord
  *  Copyright (C) 1999-2000   Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2004, 2007  Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
  */
 
 /*
  */
 
 /*
- * This module provides support for the bus-master IDE DMA functions
- * of various PCI chipsets, including the Intel PIIX (i82371FB for
- * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and 
- * 440 chipsets), and the PIIX4 (i82371AB for the 430 TX chipset)
- * ("PIIX" stands for "PCI ISA IDE Xcellerator").
- *
- * Pretty much the same code works for other IDE PCI bus-mastering chipsets.
- *
- * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
- *
- * By default, DMA support is prepared for use, but is currently enabled only
- * for drives which already have DMA enabled (UltraDMA or mode 2 multi/single),
- * or which are recognized as "good" (see table below).  Drives with only mode0
- * or mode1 (multi/single) DMA should also work with this chipset/driver
- * (eg. MC2112A) but are not enabled by default.
- *
- * Use "hdparm -i" to view modes supported by a given drive.
- *
- * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling
- * DMA support, but must be (re-)compiled against this kernel version or later.
- *
- * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
- * If problems arise, ide.c will disable DMA operation after a few retries.
- * This error recovery mechanism works and has been extremely well exercised.
- *
- * IDE drives, depending on their vintage, may support several different modes
- * of DMA operation.  The boot-time modes are indicated with a "*" in
- * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
- * the "hdparm -X" feature.  There is seldom a need to do this, as drives
- * normally power-up with their "best" PIO/DMA modes enabled.
- *
- * Testing has been done with a rather extensive number of drives,
- * with Quantum & Western Digital models generally outperforming the pack,
- * and Fujitsu & Conner (and some Seagate which are really Conner) drives
- * showing more lackluster throughput.
- *
- * Keep an eye on /var/adm/messages for "DMA disabled" messages.
- *
- * Some people have reported trouble with Intel Zappa motherboards.
- * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
- * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
- * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
- *
  * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
  * fixing the problem with the BIOS on some Acer motherboards.
  *
  *
  * Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
  * for supplying a Promise UDMA board & WD UDMA drive for this work!
- *
- * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
- *
- * ATA-66/100 and recovery functions, I forgot the rest......
- *
  */
 
 #include <linux/module.h>
index 4a2cb28682263d6a3c3a861490dfbe770d96c2d6..194ecb0049eb1ed37c3dde4c00d3a83273c1dc88 100644 (file)
@@ -756,7 +756,8 @@ static int ide_probe_port(ide_hwif_t *hwif)
 
        BUG_ON(hwif->present);
 
-       if (hwif->noprobe)
+       if (hwif->noprobe ||
+           (hwif->drives[0].noprobe && hwif->drives[1].noprobe))
                return -EACCES;
 
        /*
index 0598ecfd5f3706b0402182875f324474361bbf5b..43e0e05577763b4bcd166dc4d14128dd94dac9d2 100644 (file)
@@ -3765,6 +3765,11 @@ static int ide_tape_probe(ide_drive_t *drive)
        g->fops = &idetape_block_ops;
        ide_register_region(g);
 
+       printk(KERN_WARNING "It is possible that this driver does not have any"
+               " users anymore and, as a result, it will be REMOVED soon."
+               " Please notify Bart <bzolnier@gmail.com> or Boris"
+               " <petkovbb@gmail.com> in case you still need it.\n");
+
        return 0;
 
 out_free_tape:
index 477833f0daf501cbb1a67150e6523818a1fc38f6..fa16bc30bbc985efe4efc4ad9c91d93b3d7b0ed7 100644 (file)
@@ -590,11 +590,6 @@ void ide_unregister(unsigned int index, int init_default, int restore)
                hwif->extra_ports = 0;
        }
 
-       /*
-        * Note that we only release the standard ports,
-        * and do not even try to handle any extra ports
-        * allocated for weird IDE interface chipsets.
-        */
        ide_hwif_release_regions(hwif);
 
        /* copy original settings */
@@ -1036,10 +1031,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                        drive->nice1 = (arg >> IDE_NICE_1) & 1;
                        return 0;
                case HDIO_DRIVE_RESET:
-               {
-                       unsigned long flags;
-                       if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-                       
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EACCES;
+
                        /*
                         *      Abort the current command on the
                         *      group if there is one, taking
@@ -1058,17 +1052,15 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
                        ide_abort(drive, "drive reset");
 
                        BUG_ON(HWGROUP(drive)->handler);
-                               
+
                        /* Ensure nothing gets queued after we
                           drop the lock. Reset will clear the busy */
-                  
+
                        HWGROUP(drive)->busy = 1;
                        spin_unlock_irqrestore(&ide_lock, flags);
                        (void) ide_do_reset(drive);
 
                        return 0;
-               }
-
                case HDIO_GET_BUSSTATE:
                        if (!capable(CAP_SYS_ADMIN))
                                return -EACCES;
@@ -1449,7 +1441,7 @@ static int __init ide_setup(char *s)
 
                        case -1: /* "noprobe" */
                                hwif->noprobe = 1;
-                               goto done;
+                               goto obsolete_option;
 
                        case 1: /* base */
                                vals[1] = vals[0] + 0x206; /* default ctl */
index bba29df5f21d6094660c777724c38ef9d2de454b..2f4f47ad602f61ca8ec3614d484dcc5939a46c05 100644 (file)
@@ -334,43 +334,6 @@ static void __init qd6580_port_init_devs(ide_hwif_t *hwif)
        hwif->drives[1].drive_data = t2;
 }
 
-/*
- * qd_unsetup:
- *
- * called to unsetup an ata channel : back to default values, unlinks tuning
- */
-/*
-static void __exit qd_unsetup(ide_hwif_t *hwif)
-{
-       u8 config = hwif->config_data;
-       int base = hwif->select_data;
-       void *set_pio_mode = (void *)hwif->set_pio_mode;
-
-       if (hwif->chipset != ide_qd65xx)
-               return;
-
-       printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
-
-       hwif->selectproc = NULL;
-       hwif->set_pio_mode = NULL;
-
-       if (set_pio_mode == (void *)qd6500_set_pio_mode) {
-               // will do it for both
-               outb(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
-       } else if (set_pio_mode == (void *)qd6580_set_pio_mode) {
-               if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
-                       outb(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
-                       outb(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
-               } else {
-                       outb(hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
-               }
-       } else {
-               printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
-               printk(KERN_WARNING "keeping settings !\n");
-       }
-}
-*/
-
 static const struct ide_port_info qd65xx_port_info __initdata = {
        .chipset                = ide_qd65xx,
        .host_flags             = IDE_HFLAG_IO_32BIT |
@@ -444,6 +407,8 @@ static int __init qd_probe(int base)
                printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
                        config, control, QD_ID3);
 
+               outb(QD_DEF_CONTR, QD_CONTROL_PORT);
+
                if (control & QD_CONTR_SEC_DISABLED) {
                        /* secondary disabled */
 
@@ -460,8 +425,6 @@ static int __init qd_probe(int base)
 
                        ide_device_add(idx, &qd65xx_port_info);
 
-                       outb(QD_DEF_CONTR, QD_CONTROL_PORT);
-
                        return 1;
                } else {
                        ide_hwif_t *mate;
@@ -487,8 +450,6 @@ static int __init qd_probe(int base)
 
                        ide_device_add(idx, &qd65xx_port_info);
 
-                       outb(QD_DEF_CONTR, QD_CONTROL_PORT);
-
                        return 0; /* no other qd65xx possible */
                }
        }
index bd24dad3cfc6b2a82c990120ff7e10ac567599ab..ec667982809c18ae8ddf59bc5023190134cb33c1 100644 (file)
@@ -787,7 +787,8 @@ static int __init cmd640x_init(void)
        /*
         * Try to enable the secondary interface, if not already enabled
         */
-       if (cmd_hwif1->noprobe) {
+       if (cmd_hwif1->noprobe ||
+           (cmd_hwif1->drives[0].noprobe && cmd_hwif1->drives[1].noprobe)) {
                port2 = "not probed";
        } else {
                b = get_cmd640_reg(CNTRL);
index d0f7bb8b8adf1d881fe4d2f7c5f86106dc4b63d1..6357bb6269ab42bfc14623006e0fef089484ae08 100644 (file)
@@ -1570,10 +1570,12 @@ static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_devic
                if (rev < 3)
                        info = &hpt36x;
                else {
-                       static const struct hpt_info *hpt37x_info[] =
-                               { &hpt370, &hpt370a, &hpt372, &hpt372n };
-
-                       info = hpt37x_info[min_t(u8, rev, 6) - 3];
+                       switch (min_t(u8, rev, 6)) {
+                       case 3: info = &hpt370;  break;
+                       case 4: info = &hpt370a; break;
+                       case 5: info = &hpt372;  break;
+                       case 6: info = &hpt372n; break;
+                       }
                        idx++;
                }
                break;
@@ -1626,7 +1628,7 @@ static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_devic
        return ide_setup_pci_device(dev, &d);
 }
 
-static const struct pci_device_id hpt366_pci_tbl[] = {
+static const struct pci_device_id hpt366_pci_tbl[] __devinitconst = {
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366),  0 },
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372),  1 },
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302),  2 },
index 28e155a9e2a5a6bc8e424e2e1dc235f94fac2c26..9e2b1964d71add2103a735164cc7560de5ca3b38 100644 (file)
@@ -183,6 +183,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
  *   Don't use this with devices which don't have this bug.
  *
+ * - delay inquiry
+ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
+ *
  * - override internal blacklist
  *   Instead of adding to the built-in blacklist, use only the workarounds
  *   specified in the module load parameter.
@@ -195,6 +198,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
        ", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
        ", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
        ", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+       ", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
        ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
        ", or a combination)");
 
@@ -357,6 +361,11 @@ static const struct {
                .workarounds            = SBP2_WORKAROUND_INQUIRY_36 |
                                          SBP2_WORKAROUND_MODE_SENSE_8,
        },
+       /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
+               .firmware_revision      = 0x002800,
+               .model_id               = 0x000000,
+               .workarounds            = SBP2_WORKAROUND_DELAY_INQUIRY,
+       },
        /* Initio bridges, actually only needed for some older ones */ {
                .firmware_revision      = 0x000200,
                .model_id               = SBP2_ROM_VALUE_WILDCARD,
@@ -914,6 +923,9 @@ static int sbp2_start_device(struct sbp2_lu *lu)
        sbp2_agent_reset(lu, 1);
        sbp2_max_speed_and_size(lu);
 
+       if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
+               ssleep(SBP2_INQUIRY_DELAY);
+
        error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
        if (error) {
                SBP2_ERR("scsi_add_device failed");
@@ -1962,6 +1974,9 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
 {
        struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
 
+       if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
+               return -ENODEV;
+
        lu->sdev = sdev;
        sdev->allow_restart = 1;
 
index d2ecb0d8a1bba4e577eef7c03dbcbb8df5ee0eee..80d8e097b0651487a17d8b6e1fd5105ce79706aa 100644 (file)
@@ -343,6 +343,8 @@ enum sbp2lu_state_types {
 #define SBP2_WORKAROUND_INQUIRY_36     0x2
 #define SBP2_WORKAROUND_MODE_SENSE_8   0x4
 #define SBP2_WORKAROUND_FIX_CAPACITY   0x8
+#define SBP2_WORKAROUND_DELAY_INQUIRY  0x10
+#define SBP2_INQUIRY_DELAY             12
 #define SBP2_WORKAROUND_OVERRIDE       0x100
 
 #endif /* SBP2_H */
index 73bfd1656f86434bae2c36215a6d073607a07a7c..b8797c66676d6837b265f816e55d923d450047be 100644 (file)
@@ -136,14 +136,8 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list,
 
        /* Find largest page shift we can use to cover buffers */
        for (*shift = PAGE_SHIFT; *shift < 27; ++(*shift))
-               if (num_phys_buf > 1) {
-                       if ((1ULL << *shift) & mask)
-                               break;
-               } else
-                       if (1ULL << *shift >=
-                           buffer_list[0].size +
-                           (buffer_list[0].addr & ((1ULL << *shift) - 1)))
-                               break;
+               if ((1ULL << *shift) & mask)
+                       break;
 
        buffer_list[0].size += buffer_list[0].addr & ((1ULL << *shift) - 1);
        buffer_list[0].addr &= ~0ull << *shift;
index 7f8853b44ee173579d2af89d54c09acfa5117ff9..b2112f5a422fbd8bcf6d993f707a0b8b604ad5e1 100644 (file)
@@ -567,12 +567,12 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
 
        /* Init the adapter */
        nesdev->nesadapter = nes_init_adapter(nesdev, hw_rev);
-       nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
        if (!nesdev->nesadapter) {
                printk(KERN_ERR PFX "Unable to initialize adapter.\n");
                ret = -ENOMEM;
                goto bail5;
        }
+       nesdev->nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
 
        /* nesdev->base_doorbell_index =
                        nesdev->nesadapter->pd_config_base[PCI_FUNC(nesdev->pcidev->devfn)]; */
index fd57e8a1582f210383044ab7748eabbccdcf662d..a48b288618ece5d569644915455e51251e4d5e97 100644 (file)
@@ -285,6 +285,21 @@ struct nes_device {
 };
 
 
+static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad)
+{
+       u32 crc_value;
+       crc_value = crc32c(~0, (void *)nes_quad, sizeof (struct nes_v4_quad));
+
+       /*
+        * With commit ef19454b ("[LIB] crc32c: Keep intermediate crc
+        * state in cpu order"), behavior of crc32c changes on
+        * big-endian platforms.  Our algorithm expects the previous
+        * behavior; otherwise we have RDMA connection establishment
+        * issue on big-endian.
+        */
+       return cpu_to_le32(crc_value);
+}
+
 static inline void
 set_wqe_64bit_value(__le32 *wqe_words, u32 index, u64 value)
 {
index bd5cfeaac203df2da0f09ea63ff2fc5e5c9b0c0f..39adb267fb1553fb45d96104b361eb6442ba8658 100644 (file)
@@ -370,11 +370,11 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
        int ret = 0;
        u32 was_timer_set;
 
+       if (!cm_node)
+               return -EINVAL;
        new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC);
        if (!new_send)
                return -1;
-       if (!cm_node)
-               return -EINVAL;
 
        /* new_send->timetosend = currenttime */
        new_send->retrycount = NES_DEFAULT_RETRYS;
@@ -947,6 +947,7 @@ static int mini_cm_dec_refcnt_listen(struct nes_cm_core *cm_core,
                nes_debug(NES_DBG_CM, "destroying listener (%p)\n", listener);
 
                kfree(listener);
+               listener = NULL;
                ret = 0;
                cm_listens_destroyed++;
        } else {
@@ -2319,6 +2320,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        struct iw_cm_event cm_event;
        struct nes_hw_qp_wqe *wqe;
        struct nes_v4_quad nes_quad;
+       u32 crc_value;
        int ret;
 
        ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
@@ -2435,8 +2437,8 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        nes_quad.TcpPorts[1]   = cm_id->local_addr.sin_port;
 
        /* Produce hash key */
-       nesqp->hte_index = cpu_to_be32(
-                       crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+       crc_value = get_crc_value(&nes_quad);
+       nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
        nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, CRC = 0x%08X\n",
                        nesqp->hte_index, nesqp->hte_index & adapter->hte_index_mask);
 
@@ -2750,6 +2752,7 @@ void cm_event_connected(struct nes_cm_event *event)
        struct iw_cm_event cm_event;
        struct nes_hw_qp_wqe *wqe;
        struct nes_v4_quad nes_quad;
+       u32 crc_value;
        int ret;
 
        /* get all our handles */
@@ -2827,8 +2830,8 @@ void cm_event_connected(struct nes_cm_event *event)
        nes_quad.TcpPorts[1] = cm_id->local_addr.sin_port;
 
        /* Produce hash key */
-       nesqp->hte_index = cpu_to_be32(
-                       crc32c(~0, (void *)&nes_quad, sizeof(nes_quad)) ^ 0xffffffff);
+       crc_value = get_crc_value(&nes_quad);
+       nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff);
        nes_debug(NES_DBG_CM, "HTE Index = 0x%08X, After CRC = 0x%08X\n",
                        nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
 
index 7c4c0fbf0abd3ff9322a07888afe5cb00d4c34d2..49e53e4c1ebef475bf5337bb346472c98a8ec72f 100644 (file)
@@ -156,15 +156,14 @@ static void nes_nic_tune_timer(struct nes_device *nesdev)
 
        spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
 
-       if (shared_timer->cq_count_old < cq_count) {
-               if (cq_count > shared_timer->threshold_low)
-                       shared_timer->cq_direction_downward=0;
-       }
-       if (shared_timer->cq_count_old >= cq_count)
+       if (shared_timer->cq_count_old <= cq_count)
+               shared_timer->cq_direction_downward = 0;
+       else
                shared_timer->cq_direction_downward++;
        shared_timer->cq_count_old = cq_count;
        if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
-               if (cq_count <= shared_timer->threshold_low) {
+               if (cq_count <= shared_timer->threshold_low &&
+                   shared_timer->threshold_low > 4) {
                        shared_timer->threshold_low = shared_timer->threshold_low/2;
                        shared_timer->cq_direction_downward=0;
                        nesdev->currcq_count = 0;
@@ -1728,7 +1727,6 @@ int nes_napi_isr(struct nes_device *nesdev)
                        nesdev->int_req &= ~NES_INT_TIMER;
                        nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
                        nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
-                       nesadapter->tune_timer.timer_in_use_old = 0;
                }
                nesdev->deepcq_count = 0;
                return 1;
@@ -1867,7 +1865,6 @@ void nes_dpc(unsigned long param)
                                        nesdev->int_req &= ~NES_INT_TIMER;
                                        nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
                                        nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
-                                       nesdev->nesadapter->tune_timer.timer_in_use_old = 0;
                                } else {
                                        nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
                                }
index 1e10df550c9ea49e3a2f04414a61bbb941f97ac2..b7e2844f096b620489c0b338e65e400937c16c4a 100644 (file)
@@ -962,7 +962,7 @@ struct nes_arp_entry {
 #define DEFAULT_JUMBO_NES_QL_LOW    12
 #define DEFAULT_JUMBO_NES_QL_TARGET 40
 #define DEFAULT_JUMBO_NES_QL_HIGH   128
-#define NES_NIC_CQ_DOWNWARD_TREND   8
+#define NES_NIC_CQ_DOWNWARD_TREND   16
 
 struct nes_hw_tune_timer {
     //u16 cq_count;
index 4dafbe16e82a8366aed841269c3d54535c091cfc..a651e9d9f0efdba6e38612b738f9455ccf2a1bcf 100644 (file)
@@ -929,7 +929,7 @@ static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,
                                NES_MAX_USER_DB_REGIONS, nesucontext->first_free_db);
                nes_debug(NES_DBG_PD, "find_first_zero_biton doorbells returned %u, mapping pd_id %u.\n",
                                nespd->mmap_db_index, nespd->pd_id);
-               if (nespd->mmap_db_index > NES_MAX_USER_DB_REGIONS) {
+               if (nespd->mmap_db_index >= NES_MAX_USER_DB_REGIONS) {
                        nes_debug(NES_DBG_PD, "mmap_db_index > MAX\n");
                        nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
                        kfree(nespd);
@@ -1327,7 +1327,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
                                                                  (long long unsigned int)req.user_wqe_buffers);
                                                        nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
                                                        kfree(nesqp->allocated_buffer);
-                                                       return ERR_PTR(-ENOMEM);
+                                                       return ERR_PTR(-EFAULT);
                                                }
                                        }
 
@@ -1674,6 +1674,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
                }
                nes_debug(NES_DBG_CQ, "CQ Virtual Address = %08lX, size = %u.\n",
                                (unsigned long)req.user_cq_buffer, entries);
+               err = 1;
                list_for_each_entry(nespbl, &nes_ucontext->cq_reg_mem_list, list) {
                        if (nespbl->user_base == (unsigned long )req.user_cq_buffer) {
                                list_del(&nespbl->list);
@@ -1686,7 +1687,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
                if (err) {
                        nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
                        kfree(nescq);
-                       return ERR_PTR(err);
+                       return ERR_PTR(-EFAULT);
                }
 
                pbl_entries = nespbl->pbl_size >> 3;
@@ -1831,9 +1832,6 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
                                spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
                        }
                }
-               nes_debug(NES_DBG_CQ, "iWARP CQ%u create timeout expired, major code = 0x%04X,"
-                               " minor code = 0x%04X\n",
-                               nescq->hw_cq.cq_number, cqp_request->major_code, cqp_request->minor_code);
                if (!context)
                        pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
                                        nescq->hw_cq.cq_pbase);
index f337800076c0fdba7fe986e8dd27d897f8cce1ef..a0f0e605d630389bbed8450c1446905002e1a836 100644 (file)
@@ -90,6 +90,11 @@ config MACVLAN
          This allows one to create virtual interfaces that map packets to
          or from specific MAC addresses to a particular interface.
 
+         Macvlan devices can be added using the "ip" command from the
+         iproute2 package starting with the iproute2-2.6.23 release:
+
+         "ip link add link <real dev> [ address MAC ] [ NAME ] type macvlan"
+
          To compile this driver as a module, choose M here: the module
          will be called macvlan.
 
@@ -2363,6 +2368,7 @@ config GELIC_NET
 config GELIC_WIRELESS
        bool "PS3 Wireless support"
        depends on GELIC_NET
+       select WIRELESS_EXT
        help
         This option adds the support for the wireless feature of PS3.
         If you have the wireless-less model of PS3 or have no plan to
index afc7f34b1dcf3afbf8dd6eb02b272abe94c8edf5..8af142ccf373feb060b82fae91e7a5fe9adae10b 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007 Broadcom Corporation
+ * Copyright (c) 2007-2008 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Based on code from Michael Chan's bnx2 driver
  * UDP CSUM errata workaround by Arik Gendelman
  * Slowpath rework by Vladislav Zolotarov
- * Statistics and Link managment by Yitchak Gertner
+ * Statistics and Link management by Yitchak Gertner
  *
  */
 
 /* define this to make the driver freeze on error
  * to allow getting debug info
- * (you will need to reboot afterwords)
+ * (you will need to reboot afterwards)
  */
 /*#define BNX2X_STOP_ON_ERROR*/
 
 #include "bnx2x.h"
 #include "bnx2x_init.h"
 
-#define DRV_MODULE_VERSION      "0.40.15"
-#define DRV_MODULE_RELDATE      "$DateTime: 2007/11/15 07:28:37 $"
-#define BNX2X_BC_VER           0x040009
+#define DRV_MODULE_VERSION      "1.40.22"
+#define DRV_MODULE_RELDATE      "2007/11/27"
+#define BNX2X_BC_VER           0x040200
 
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT             (5*HZ)
 
 static char version[] __devinitdata =
-       "Broadcom NetXtreme II 577xx 10Gigabit Ethernet Driver "
+       "Broadcom NetXtreme II 5771X 10Gigabit Ethernet Driver "
        DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
 MODULE_AUTHOR("Eliezer Tamir <eliezert@broadcom.com>");
 MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
-MODULE_INFO(cvs_version, "$Revision: #356 $");
 
 static int use_inta;
 static int poll;
@@ -94,8 +93,8 @@ module_param(debug, int, 0);
 MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X");
 MODULE_PARM_DESC(poll, "use polling (for debug)");
 MODULE_PARM_DESC(onefunc, "enable only first function");
-MODULE_PARM_DESC(nomcp, "ignore managment CPU (Implies onefunc)");
-MODULE_PARM_DESC(debug, "defualt debug msglevel");
+MODULE_PARM_DESC(nomcp, "ignore management CPU (Implies onefunc)");
+MODULE_PARM_DESC(debug, "default debug msglevel");
 
 #ifdef BNX2X_MULTI
 module_param(use_multi, int, 0);
@@ -298,8 +297,7 @@ static void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
 
 static int bnx2x_mc_assert(struct bnx2x *bp)
 {
-       int i, j;
-       int rc = 0;
+       int i, j, rc = 0;
        char last_idx;
        const char storm[] = {"XTCU"};
        const u32 intmem_base[] = {
@@ -313,8 +311,9 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
        for (i = 0; i < 4; i++) {
                last_idx = REG_RD8(bp, XSTORM_ASSERT_LIST_INDEX_OFFSET +
                                   intmem_base[i]);
-               BNX2X_ERR("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n",
-                         storm[i], last_idx);
+               if (last_idx)
+                       BNX2X_LOG("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n",
+                                 storm[i], last_idx);
 
                /* print the asserts */
                for (j = 0; j < STROM_ASSERT_ARRAY_SIZE; j++) {
@@ -330,7 +329,7 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
                                      intmem_base[i]);
 
                        if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                               BNX2X_ERR("DATA %cSTORM_ASSERT_INDEX 0x%x ="
+                               BNX2X_LOG("DATA %cSTORM_ASSERT_INDEX 0x%x ="
                                          " 0x%08x 0x%08x 0x%08x 0x%08x\n",
                                          storm[i], j, row3, row2, row1, row0);
                                rc++;
@@ -341,6 +340,7 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
        }
        return rc;
 }
+
 static void bnx2x_fw_dump(struct bnx2x *bp)
 {
        u32 mark, offset;
@@ -348,21 +348,22 @@ static void bnx2x_fw_dump(struct bnx2x *bp)
        int word;
 
        mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104);
-       printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n", mark);
+       mark = ((mark + 0x3) & ~0x3);
+       printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n" KERN_ERR, mark);
 
        for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
                        data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
                                                  offset + 4*word));
                data[8] = 0x0;
-               printk(KERN_ERR PFX "%s", (char *)data);
+               printk(KERN_CONT "%s", (char *)data);
        }
        for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
                        data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
                                                  offset + 4*word));
                data[8] = 0x0;
-               printk(KERN_ERR PFX "%s", (char *)data);
+               printk(KERN_CONT "%s", (char *)data);
        }
        printk("\n" KERN_ERR PFX "end of fw dump\n");
 }
@@ -427,10 +428,10 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
                }
        }
 
-       BNX2X_ERR("def_c_idx(%u)  def_u_idx(%u)  def_t_idx(%u)"
-                 "  def_x_idx(%u)  def_att_idx(%u)  attn_state(%u)"
+       BNX2X_ERR("def_c_idx(%u)  def_u_idx(%u)  def_x_idx(%u)"
+                 "  def_t_idx(%u)  def_att_idx(%u)  attn_state(%u)"
                  "  spq_prod_idx(%u)\n",
-                 bp->def_c_idx, bp->def_u_idx, bp->def_t_idx, bp->def_x_idx,
+                 bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx,
                  bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
 
 
@@ -441,7 +442,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
        DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n");
 }
 
-static void bnx2x_enable_int(struct bnx2x *bp)
+static void bnx2x_int_enable(struct bnx2x *bp)
 {
        int port = bp->port;
        u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
@@ -454,18 +455,26 @@ static void bnx2x_enable_int(struct bnx2x *bp)
                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
        } else {
                val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+                       HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
                        HC_CONFIG_0_REG_INT_LINE_EN_0 |
                        HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+               /* Errata A0.158 workaround */
+               DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)  MSI-X %d\n",
+                  val, port, addr, msix);
+
+               REG_WR(bp, addr, val);
+
                val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
        }
 
-       DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)  msi %d\n",
+       DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)  MSI-X %d\n",
           val, port, addr, msix);
 
        REG_WR(bp, addr, val);
 }
 
-static void bnx2x_disable_int(struct bnx2x *bp)
+static void bnx2x_int_disable(struct bnx2x *bp)
 {
        int port = bp->port;
        u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
@@ -484,15 +493,15 @@ static void bnx2x_disable_int(struct bnx2x *bp)
                BNX2X_ERR("BUG! proper val not read from IGU!\n");
 }
 
-static void bnx2x_disable_int_sync(struct bnx2x *bp)
+static void bnx2x_int_disable_sync(struct bnx2x *bp)
 {
 
        int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
        int i;
 
        atomic_inc(&bp->intr_sem);
-       /* prevent the HW from sending interrupts*/
-       bnx2x_disable_int(bp);
+       /* prevent the HW from sending interrupts */
+       bnx2x_int_disable(bp);
 
        /* make sure all ISRs are done */
        if (msix) {
@@ -775,6 +784,7 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
                mb(); /* force bnx2x_wait_ramrod to see the change */
                return;
        }
+
        switch (command | bp->state) {
        case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT):
                DP(NETIF_MSG_IFUP, "got setup ramrod\n");
@@ -787,20 +797,20 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
                fp->state = BNX2X_FP_STATE_HALTED;
                break;
 
-       case (RAMROD_CMD_ID_ETH_PORT_DEL | BNX2X_STATE_CLOSING_WAIT4_DELETE):
-               DP(NETIF_MSG_IFDOWN, "got delete ramrod\n");
-               bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
-               break;
-
        case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT):
-               DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid);
-               bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_DELETED;
+               DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n",
+                  cid);
+               bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED;
                break;
 
        case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
                DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
                break;
 
+       case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
+               DP(NETIF_MSG_IFUP, "got (un)set mac ramrod\n");
+               break;
+
        default:
                BNX2X_ERR("unexpected ramrod (%d)  state is %x\n",
                          command, bp->state);
@@ -1179,12 +1189,175 @@ static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
        return val;
 }
 
+static int bnx2x_hw_lock(struct bnx2x *bp, u32 resource)
+{
+       u32 cnt;
+       u32 lock_status;
+       u32 resource_bit = (1 << resource);
+       u8 func = bp->port;
+
+       /* Validating that the resource is within range */
+       if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+               DP(NETIF_MSG_HW,
+                  "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+                  resource, HW_LOCK_MAX_RESOURCE_VALUE);
+               return -EINVAL;
+       }
+
+       /* Validating that the resource is not already taken */
+       lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8);
+       if (lock_status & resource_bit) {
+               DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
+                  lock_status, resource_bit);
+               return -EEXIST;
+       }
+
+       /* Try for 1 second every 5ms */
+       for (cnt = 0; cnt < 200; cnt++) {
+               /* Try to acquire the lock */
+               REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + func*8 + 4,
+                      resource_bit);
+               lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8);
+               if (lock_status & resource_bit)
+                       return 0;
+
+               msleep(5);
+       }
+       DP(NETIF_MSG_HW, "Timeout\n");
+       return -EAGAIN;
+}
+
+static int bnx2x_hw_unlock(struct bnx2x *bp, u32 resource)
+{
+       u32 lock_status;
+       u32 resource_bit = (1 << resource);
+       u8 func = bp->port;
+
+       /* Validating that the resource is within range */
+       if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+               DP(NETIF_MSG_HW,
+                  "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+                  resource, HW_LOCK_MAX_RESOURCE_VALUE);
+               return -EINVAL;
+       }
+
+       /* Validating that the resource is currently taken */
+       lock_status = REG_RD(bp, MISC_REG_DRIVER_CONTROL_1 + func*8);
+       if (!(lock_status & resource_bit)) {
+               DP(NETIF_MSG_HW, "lock_status 0x%x  resource_bit 0x%x\n",
+                  lock_status, resource_bit);
+               return -EFAULT;
+       }
+
+       REG_WR(bp, MISC_REG_DRIVER_CONTROL_1 + func*8, resource_bit);
+       return 0;
+}
+
+static int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode)
+{
+       /* The GPIO should be swapped if swap register is set and active */
+       int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
+                        REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ bp->port;
+       int gpio_shift = gpio_num +
+                       (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
+       u32 gpio_mask = (1 << gpio_shift);
+       u32 gpio_reg;
+
+       if (gpio_num > MISC_REGISTERS_GPIO_3) {
+               BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
+               return -EINVAL;
+       }
+
+       bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
+       /* read GPIO and mask except the float bits */
+       gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT);
+
+       switch (mode) {
+       case MISC_REGISTERS_GPIO_OUTPUT_LOW:
+               DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output low\n",
+                  gpio_num, gpio_shift);
+               /* clear FLOAT and set CLR */
+               gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+               gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS);
+               break;
+
+       case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
+               DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> output high\n",
+                  gpio_num, gpio_shift);
+               /* clear FLOAT and set SET */
+               gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+               gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_SET_POS);
+               break;
+
+       case MISC_REGISTERS_GPIO_INPUT_HI_Z :
+               DP(NETIF_MSG_LINK, "Set GPIO %d (shift %d) -> input\n",
+                  gpio_num, gpio_shift);
+               /* set FLOAT */
+               gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
+               break;
+
+       default:
+               break;
+       }
+
+       REG_WR(bp, MISC_REG_GPIO, gpio_reg);
+       bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_GPIO);
+
+       return 0;
+}
+
+static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
+{
+       u32 spio_mask = (1 << spio_num);
+       u32 spio_reg;
+
+       if ((spio_num < MISC_REGISTERS_SPIO_4) ||
+           (spio_num > MISC_REGISTERS_SPIO_7)) {
+               BNX2X_ERR("Invalid SPIO %d\n", spio_num);
+               return -EINVAL;
+       }
+
+       bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
+       /* read SPIO and mask except the float bits */
+       spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_REGISTERS_SPIO_FLOAT);
+
+       switch (mode) {
+       case MISC_REGISTERS_SPIO_OUTPUT_LOW :
+               DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num);
+               /* clear FLOAT and set CLR */
+               spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+               spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_CLR_POS);
+               break;
+
+       case MISC_REGISTERS_SPIO_OUTPUT_HIGH :
+               DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num);
+               /* clear FLOAT and set SET */
+               spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+               spio_reg |=  (spio_mask << MISC_REGISTERS_SPIO_SET_POS);
+               break;
+
+       case MISC_REGISTERS_SPIO_INPUT_HI_Z:
+               DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num);
+               /* set FLOAT */
+               spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS);
+               break;
+
+       default:
+               break;
+       }
+
+       REG_WR(bp, MISC_REG_SPIO, spio_reg);
+       bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_SPIO);
+
+       return 0;
+}
+
 static int bnx2x_mdio22_write(struct bnx2x *bp, u32 reg, u32 val)
 {
-       int rc;
-       u32 tmp, i;
        int port = bp->port;
        u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+       u32 tmp;
+       int i, rc;
 
 /*      DP(NETIF_MSG_HW, "phy_addr 0x%x  reg 0x%x  val 0x%08x\n",
           bp->phy_addr, reg, val); */
@@ -1236,8 +1409,8 @@ static int bnx2x_mdio22_read(struct bnx2x *bp, u32 reg, u32 *ret_val)
 {
        int port = bp->port;
        u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
-       u32 val, i;
-       int rc;
+       u32 val;
+       int i, rc;
 
        if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
 
@@ -1286,58 +1459,54 @@ static int bnx2x_mdio22_read(struct bnx2x *bp, u32 reg, u32 *ret_val)
        return rc;
 }
 
-static int bnx2x_mdio45_write(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
+static int bnx2x_mdio45_ctrl_write(struct bnx2x *bp, u32 mdio_ctrl,
+                                  u32 phy_addr, u32 reg, u32 addr, u32 val)
 {
-       int rc = 0;
-       u32 tmp, i;
-       int port = bp->port;
-       u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+       u32 tmp;
+       int i, rc = 0;
 
-       if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
-
-               tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-               tmp &= ~EMAC_MDIO_MODE_AUTO_POLL;
-               EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
-               REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-               udelay(40);
-       }
-
-       /* set clause 45 mode */
-       tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-       tmp |= EMAC_MDIO_MODE_CLAUSE_45;
-       EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+       /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
+        * (a value of 49==0x31) and make sure that the AUTO poll is off
+        */
+       tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       tmp &= ~(EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT);
+       tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
+               (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
+       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
+       REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       udelay(40);
 
        /* address */
-       tmp = ((bp->phy_addr << 21) | (reg << 16) | addr |
+       tmp = ((phy_addr << 21) | (reg << 16) | addr |
               EMAC_MDIO_COMM_COMMAND_ADDRESS |
               EMAC_MDIO_COMM_START_BUSY);
-       EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp);
+       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
 
        for (i = 0; i < 50; i++) {
                udelay(10);
 
-               tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+               tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
                if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
                        udelay(5);
                        break;
                }
        }
-
        if (tmp & EMAC_MDIO_COMM_START_BUSY) {
                BNX2X_ERR("write phy register failed\n");
 
                rc = -EBUSY;
+
        } else {
                /* data */
-               tmp = ((bp->phy_addr << 21) | (reg << 16) | val |
+               tmp = ((phy_addr << 21) | (reg << 16) | val |
                       EMAC_MDIO_COMM_COMMAND_WRITE_45 |
                       EMAC_MDIO_COMM_START_BUSY);
-               EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp);
+               REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
 
                for (i = 0; i < 50; i++) {
                        udelay(10);
 
-                       tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+                       tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
                        if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
                                udelay(5);
                                break;
@@ -1351,75 +1520,78 @@ static int bnx2x_mdio45_write(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
                }
        }
 
-       /* unset clause 45 mode */
-       tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-       tmp &= ~EMAC_MDIO_MODE_CLAUSE_45;
-       EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
-
-       if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
-
-               tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+       /* unset clause 45 mode, set the MDIO clock to a faster value
+        * (0x13 => 6.25Mhz) and restore the AUTO poll if needed
+        */
+       tmp = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       tmp &= ~(EMAC_MDIO_MODE_CLAUSE_45 | EMAC_MDIO_MODE_CLOCK_CNT);
+       tmp |= (0x13 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
+       if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG)
                tmp |= EMAC_MDIO_MODE_AUTO_POLL;
-               EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
-       }
+       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
 
        return rc;
 }
 
-static int bnx2x_mdio45_read(struct bnx2x *bp, u32 reg, u32 addr,
-                            u32 *ret_val)
+static int bnx2x_mdio45_write(struct bnx2x *bp, u32 phy_addr, u32 reg,
+                             u32 addr, u32 val)
 {
-       int port = bp->port;
-       u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
-       u32 val, i;
-       int rc = 0;
+       u32 emac_base = bp->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
 
-       if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+       return bnx2x_mdio45_ctrl_write(bp, emac_base, phy_addr,
+                                      reg, addr, val);
+}
 
-               val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-               val &= ~EMAC_MDIO_MODE_AUTO_POLL;
-               EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
-               REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-               udelay(40);
-       }
+static int bnx2x_mdio45_ctrl_read(struct bnx2x *bp, u32 mdio_ctrl,
+                                 u32 phy_addr, u32 reg, u32 addr,
+                                 u32 *ret_val)
+{
+       u32 val;
+       int i, rc = 0;
 
-       /* set clause 45 mode */
-       val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-       val |= EMAC_MDIO_MODE_CLAUSE_45;
-       EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+       /* set clause 45 mode, slow down the MDIO clock to 2.5MHz
+        * (a value of 49==0x31) and make sure that the AUTO poll is off
+        */
+       val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       val &= ~(EMAC_MDIO_MODE_AUTO_POLL | EMAC_MDIO_MODE_CLOCK_CNT);
+       val |= (EMAC_MDIO_MODE_CLAUSE_45 |
+               (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
+       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
+       REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       udelay(40);
 
        /* address */
-       val = ((bp->phy_addr << 21) | (reg << 16) | addr |
+       val = ((phy_addr << 21) | (reg << 16) | addr |
               EMAC_MDIO_COMM_COMMAND_ADDRESS |
               EMAC_MDIO_COMM_START_BUSY);
-       EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val);
+       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
 
        for (i = 0; i < 50; i++) {
                udelay(10);
 
-               val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+               val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
                if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
                        udelay(5);
                        break;
                }
        }
-
        if (val & EMAC_MDIO_COMM_START_BUSY) {
                BNX2X_ERR("read phy register failed\n");
 
                *ret_val = 0;
                rc = -EBUSY;
+
        } else {
                /* data */
-               val = ((bp->phy_addr << 21) | (reg << 16) |
+               val = ((phy_addr << 21) | (reg << 16) |
                       EMAC_MDIO_COMM_COMMAND_READ_45 |
                       EMAC_MDIO_COMM_START_BUSY);
-               EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val);
+               REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
 
                for (i = 0; i < 50; i++) {
                        udelay(10);
 
-                       val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+                       val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
                        if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
                                val &= EMAC_MDIO_COMM_DATA;
                                break;
@@ -1436,31 +1608,39 @@ static int bnx2x_mdio45_read(struct bnx2x *bp, u32 reg, u32 addr,
                *ret_val = val;
        }
 
-       /* unset clause 45 mode */
-       val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
-       val &= ~EMAC_MDIO_MODE_CLAUSE_45;
-       EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
-
-       if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
-
-               val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+       /* unset clause 45 mode, set the MDIO clock to a faster value
+        * (0x13 => 6.25Mhz) and restore the AUTO poll if needed
+        */
+       val = REG_RD(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
+       val &= ~(EMAC_MDIO_MODE_CLAUSE_45 | EMAC_MDIO_MODE_CLOCK_CNT);
+       val |= (0x13 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
+       if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG)
                val |= EMAC_MDIO_MODE_AUTO_POLL;
-               EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
-       }
+       REG_WR(bp, mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
 
        return rc;
 }
 
-static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
+static int bnx2x_mdio45_read(struct bnx2x *bp, u32 phy_addr, u32 reg,
+                            u32 addr, u32 *ret_val)
+{
+       u32 emac_base = bp->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+
+       return bnx2x_mdio45_ctrl_read(bp, emac_base, phy_addr,
+                                     reg, addr, ret_val);
+}
+
+static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 phy_addr, u32 reg,
+                              u32 addr, u32 val)
 {
        int i;
        u32 rd_val;
 
        might_sleep();
        for (i = 0; i < 10; i++) {
-               bnx2x_mdio45_write(bp, reg, addr, val);
+               bnx2x_mdio45_write(bp, phy_addr, reg, addr, val);
                msleep(5);
-               bnx2x_mdio45_read(bp, reg, addr, &rd_val);
+               bnx2x_mdio45_read(bp, phy_addr, reg, addr, &rd_val);
                /* if the read value is not the same as the value we wrote,
                   we should write it again */
                if (rd_val == val)
@@ -1471,18 +1651,81 @@ static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
 }
 
 /*
- * link managment
+ * link management
  */
 
+static void bnx2x_pause_resolve(struct bnx2x *bp, u32 pause_result)
+{
+       switch (pause_result) {                 /* ASYM P ASYM P */
+       case 0xb:                               /*   1  0   1  1 */
+               bp->flow_ctrl = FLOW_CTRL_TX;
+               break;
+
+       case 0xe:                               /*   1  1   1  0 */
+               bp->flow_ctrl = FLOW_CTRL_RX;
+               break;
+
+       case 0x5:                               /*   0  1   0  1 */
+       case 0x7:                               /*   0  1   1  1 */
+       case 0xd:                               /*   1  1   0  1 */
+       case 0xf:                               /*   1  1   1  1 */
+               bp->flow_ctrl = FLOW_CTRL_BOTH;
+               break;
+
+       default:
+               break;
+       }
+}
+
+static u8 bnx2x_ext_phy_resove_fc(struct bnx2x *bp)
+{
+       u32 ext_phy_addr;
+       u32 ld_pause;   /* local */
+       u32 lp_pause;   /* link partner */
+       u32 an_complete; /* AN complete */
+       u32 pause_result;
+       u8 ret = 0;
+
+       ext_phy_addr = ((bp->ext_phy_config &
+                        PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                                       PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+       /* read twice */
+       bnx2x_mdio45_read(bp, ext_phy_addr,
+                         EXT_PHY_KR_AUTO_NEG_DEVAD,
+                         EXT_PHY_KR_STATUS, &an_complete);
+       bnx2x_mdio45_read(bp, ext_phy_addr,
+                         EXT_PHY_KR_AUTO_NEG_DEVAD,
+                         EXT_PHY_KR_STATUS, &an_complete);
+
+       if (an_complete & EXT_PHY_KR_AUTO_NEG_COMPLETE) {
+               ret = 1;
+               bnx2x_mdio45_read(bp, ext_phy_addr,
+                                 EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                 EXT_PHY_KR_AUTO_NEG_ADVERT, &ld_pause);
+               bnx2x_mdio45_read(bp, ext_phy_addr,
+                                 EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                 EXT_PHY_KR_LP_AUTO_NEG, &lp_pause);
+               pause_result = (ld_pause &
+                               EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK) >> 8;
+               pause_result |= (lp_pause &
+                                EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_MASK) >> 10;
+               DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
+                  pause_result);
+               bnx2x_pause_resolve(bp, pause_result);
+       }
+       return ret;
+}
+
 static void bnx2x_flow_ctrl_resolve(struct bnx2x *bp, u32 gp_status)
 {
-       u32 ld_pause;   /* local driver */
-       u32 lp_pause;   /* link partner */
+       u32 ld_pause;   /* local driver */
+       u32 lp_pause;   /* link partner */
        u32 pause_result;
 
        bp->flow_ctrl = 0;
 
-       /* reolve from gp_status in case of AN complete and not sgmii */
+       /* resolve from gp_status in case of AN complete and not sgmii */
        if ((bp->req_autoneg & AUTONEG_FLOW_CTRL) &&
            (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
            (!(bp->phy_flags & PHY_SGMII_FLAG)) &&
@@ -1499,45 +1742,57 @@ static void bnx2x_flow_ctrl_resolve(struct bnx2x *bp, u32 gp_status)
                pause_result |= (lp_pause &
                                 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
                DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
+               bnx2x_pause_resolve(bp, pause_result);
+       } else if (!(bp->req_autoneg & AUTONEG_FLOW_CTRL) ||
+                  !(bnx2x_ext_phy_resove_fc(bp))) {
+               /* forced speed */
+               if (bp->req_autoneg & AUTONEG_FLOW_CTRL) {
+                       switch (bp->req_flow_ctrl) {
+                       case FLOW_CTRL_AUTO:
+                               if (bp->dev->mtu <= 4500)
+                                       bp->flow_ctrl = FLOW_CTRL_BOTH;
+                               else
+                                       bp->flow_ctrl = FLOW_CTRL_TX;
+                               break;
 
-               switch (pause_result) {                 /* ASYM P ASYM P */
-               case 0xb:                               /*   1  0   1  1 */
-                       bp->flow_ctrl = FLOW_CTRL_TX;
-                       break;
-
-               case 0xe:                               /*   1  1   1  0 */
-                       bp->flow_ctrl = FLOW_CTRL_RX;
-                       break;
+                       case FLOW_CTRL_TX:
+                               bp->flow_ctrl = FLOW_CTRL_TX;
+                               break;
 
-               case 0x5:                               /*   0  1   0  1 */
-               case 0x7:                               /*   0  1   1  1 */
-               case 0xd:                               /*   1  1   0  1 */
-               case 0xf:                               /*   1  1   1  1 */
-                       bp->flow_ctrl = FLOW_CTRL_BOTH;
-                       break;
+                       case FLOW_CTRL_RX:
+                               if (bp->dev->mtu <= 4500)
+                                       bp->flow_ctrl = FLOW_CTRL_RX;
+                               break;
 
-               default:
-                       break;
-               }
+                       case FLOW_CTRL_BOTH:
+                               if (bp->dev->mtu <= 4500)
+                                       bp->flow_ctrl = FLOW_CTRL_BOTH;
+                               else
+                                       bp->flow_ctrl = FLOW_CTRL_TX;
+                               break;
 
-       } else { /* forced mode */
-               switch (bp->req_flow_ctrl) {
-               case FLOW_CTRL_AUTO:
-                       if (bp->dev->mtu <= 4500)
-                               bp->flow_ctrl = FLOW_CTRL_BOTH;
-                       else
-                               bp->flow_ctrl = FLOW_CTRL_TX;
-                       break;
+                       case FLOW_CTRL_NONE:
+                       default:
+                               break;
+                       }
+               } else { /* forced mode */
+                       switch (bp->req_flow_ctrl) {
+                       case FLOW_CTRL_AUTO:
+                               DP(NETIF_MSG_LINK, "req_flow_ctrl 0x%x while"
+                                                  " req_autoneg 0x%x\n",
+                                  bp->req_flow_ctrl, bp->req_autoneg);
+                               break;
 
-               case FLOW_CTRL_TX:
-               case FLOW_CTRL_RX:
-               case FLOW_CTRL_BOTH:
-                       bp->flow_ctrl = bp->req_flow_ctrl;
-                       break;
+                       case FLOW_CTRL_TX:
+                       case FLOW_CTRL_RX:
+                       case FLOW_CTRL_BOTH:
+                               bp->flow_ctrl = bp->req_flow_ctrl;
+                               break;
 
-               case FLOW_CTRL_NONE:
-               default:
-                       break;
+                       case FLOW_CTRL_NONE:
+                       default:
+                               break;
+                       }
                }
        }
        DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", bp->flow_ctrl);
@@ -1548,9 +1803,9 @@ static void bnx2x_link_settings_status(struct bnx2x *bp, u32 gp_status)
        bp->link_status = 0;
 
        if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
-               DP(NETIF_MSG_LINK, "link up\n");
+               DP(NETIF_MSG_LINK, "phy link up\n");
 
-               bp->link_up = 1;
+               bp->phy_link_up = 1;
                bp->link_status |= LINK_STATUS_LINK_UP;
 
                if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
@@ -1659,20 +1914,20 @@ static void bnx2x_link_settings_status(struct bnx2x *bp, u32 gp_status)
                       bp->link_status |= LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
 
        } else { /* link_down */
-               DP(NETIF_MSG_LINK, "link down\n");
+               DP(NETIF_MSG_LINK, "phy link down\n");
 
-               bp->link_up = 0;
+               bp->phy_link_up = 0;
 
                bp->line_speed = 0;
                bp->duplex = DUPLEX_FULL;
                bp->flow_ctrl = 0;
        }
 
-       DP(NETIF_MSG_LINK, "gp_status 0x%x  link_up %d\n"
+       DP(NETIF_MSG_LINK, "gp_status 0x%x  phy_link_up %d\n"
           DP_LEVEL "  line_speed %d  duplex %d  flow_ctrl 0x%x"
                    "  link_status 0x%x\n",
-          gp_status, bp->link_up, bp->line_speed, bp->duplex, bp->flow_ctrl,
-          bp->link_status);
+          gp_status, bp->phy_link_up, bp->line_speed, bp->duplex,
+          bp->flow_ctrl, bp->link_status);
 }
 
 static void bnx2x_link_int_ack(struct bnx2x *bp, int is_10g)
@@ -1680,40 +1935,40 @@ static void bnx2x_link_int_ack(struct bnx2x *bp, int is_10g)
        int port = bp->port;
 
        /* first reset all status
-        * we asume only one line will be change at a time */
+        * we assume only one line will be change at a time */
        bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                      (NIG_XGXS0_LINK_STATUS |
-                       NIG_SERDES0_LINK_STATUS |
-                       NIG_STATUS_INTERRUPT_XGXS0_LINK10G));
-       if (bp->link_up) {
+                      (NIG_STATUS_XGXS0_LINK10G |
+                       NIG_STATUS_XGXS0_LINK_STATUS |
+                       NIG_STATUS_SERDES0_LINK_STATUS));
+       if (bp->phy_link_up) {
                if (is_10g) {
                        /* Disable the 10G link interrupt
                         * by writing 1 to the status register
                         */
-                       DP(NETIF_MSG_LINK, "10G XGXS link up\n");
+                       DP(NETIF_MSG_LINK, "10G XGXS phy link up\n");
                        bnx2x_bits_en(bp,
                                      NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     NIG_STATUS_INTERRUPT_XGXS0_LINK10G);
+                                     NIG_STATUS_XGXS0_LINK10G);
 
                } else if (bp->phy_flags & PHY_XGXS_FLAG) {
                        /* Disable the link interrupt
                         * by writing 1 to the relevant lane
                         * in the status register
                         */
-                       DP(NETIF_MSG_LINK, "1G XGXS link up\n");
+                       DP(NETIF_MSG_LINK, "1G XGXS phy link up\n");
                        bnx2x_bits_en(bp,
                                      NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
                                      ((1 << bp->ser_lane) <<
-                                      NIG_XGXS0_LINK_STATUS_SIZE));
+                                      NIG_STATUS_XGXS0_LINK_STATUS_SIZE));
 
                } else { /* SerDes */
-                       DP(NETIF_MSG_LINK, "SerDes link up\n");
+                       DP(NETIF_MSG_LINK, "SerDes phy link up\n");
                        /* Disable the link interrupt
                         * by writing 1 to the status register
                         */
                        bnx2x_bits_en(bp,
                                      NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                                     NIG_SERDES0_LINK_STATUS);
+                                     NIG_STATUS_SERDES0_LINK_STATUS);
                }
 
        } else { /* link_down */
@@ -1724,91 +1979,182 @@ static int bnx2x_ext_phy_is_link_up(struct bnx2x *bp)
 {
        u32 ext_phy_type;
        u32 ext_phy_addr;
-       u32 local_phy;
-       u32 val = 0;
+       u32 val1 = 0, val2;
        u32 rx_sd, pcs_status;
 
        if (bp->phy_flags & PHY_XGXS_FLAG) {
-               local_phy = bp->phy_addr;
                ext_phy_addr = ((bp->ext_phy_config &
                                 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
                                PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
-               bp->phy_addr = (u8)ext_phy_addr;
 
                ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
                switch (ext_phy_type) {
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
                        DP(NETIF_MSG_LINK, "XGXS Direct\n");
-                       val = 1;
+                       val1 = 1;
                        break;
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
                        DP(NETIF_MSG_LINK, "XGXS 8705\n");
-                       bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD,
-                                         EXT_PHY_OPT_LASI_STATUS, &val);
-                       DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val);
-
-                       bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD,
-                                         EXT_PHY_OPT_LASI_STATUS, &val);
-                       DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val);
-
-                       bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_WIS_DEVAD,
+                                         EXT_PHY_OPT_LASI_STATUS, &val1);
+                       DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_WIS_DEVAD,
+                                         EXT_PHY_OPT_LASI_STATUS, &val1);
+                       DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1);
+
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
                                          EXT_PHY_OPT_PMD_RX_SD, &rx_sd);
-                       val = (rx_sd & 0x1);
+                       DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
+                       val1 = (rx_sd & 0x1);
                        break;
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
                        DP(NETIF_MSG_LINK, "XGXS 8706\n");
-                       bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
-                                         EXT_PHY_OPT_LASI_STATUS, &val);
-                       DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val);
-
-                       bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
-                                         EXT_PHY_OPT_LASI_STATUS, &val);
-                       DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val);
-
-                       bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_OPT_LASI_STATUS, &val1);
+                       DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
+
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_OPT_LASI_STATUS, &val1);
+                       DP(NETIF_MSG_LINK, "8706 LASI status 0x%x\n", val1);
+
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
                                          EXT_PHY_OPT_PMD_RX_SD, &rx_sd);
-                       bnx2x_mdio45_read(bp, EXT_PHY_OPT_PCS_DEVAD,
-                                        EXT_PHY_OPT_PCS_STATUS, &pcs_status);
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PCS_DEVAD,
+                                         EXT_PHY_OPT_PCS_STATUS, &pcs_status);
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_AUTO_NEG_DEVAD,
+                                         EXT_PHY_OPT_AN_LINK_STATUS, &val2);
+
                        DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x"
-                          "  pcs_status 0x%x\n", rx_sd, pcs_status);
-                       /* link is up if both bit 0 of pmd_rx and
-                        * bit 0 of pcs_status are set
+                          "  pcs_status 0x%x 1Gbps link_status 0x%x 0x%x\n",
+                          rx_sd, pcs_status, val2, (val2 & (1<<1)));
+                       /* link is up if both bit 0 of pmd_rx_sd and
+                        * bit 0 of pcs_status are set, or if the autoneg bit
+                          1 is set
+                        */
+                       val1 = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1)));
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+                       bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+
+                       /* clear the interrupt LASI status register */
+                       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                              ext_phy_addr,
+                                              EXT_PHY_KR_PCS_DEVAD,
+                                              EXT_PHY_KR_LASI_STATUS, &val2);
+                       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                              ext_phy_addr,
+                                              EXT_PHY_KR_PCS_DEVAD,
+                                              EXT_PHY_KR_LASI_STATUS, &val1);
+                       DP(NETIF_MSG_LINK, "KR LASI status 0x%x->0x%x\n",
+                          val2, val1);
+                       /* Check the LASI */
+                       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                              ext_phy_addr,
+                                              EXT_PHY_KR_PMA_PMD_DEVAD,
+                                              0x9003, &val2);
+                       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                              ext_phy_addr,
+                                              EXT_PHY_KR_PMA_PMD_DEVAD,
+                                              0x9003, &val1);
+                       DP(NETIF_MSG_LINK, "KR 0x9003 0x%x->0x%x\n",
+                          val2, val1);
+                       /* Check the link status */
+                       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                              ext_phy_addr,
+                                              EXT_PHY_KR_PCS_DEVAD,
+                                              EXT_PHY_KR_PCS_STATUS, &val2);
+                       DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2);
+                       /* Check the link status on 1.1.2 */
+                       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                         ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_KR_STATUS, &val2);
+                       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                         ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_KR_STATUS, &val1);
+                       DP(NETIF_MSG_LINK,
+                          "KR PMA status 0x%x->0x%x\n", val2, val1);
+                       val1 = ((val1 & 4) == 4);
+                       /* If 1G was requested assume the link is up */
+                       if (!(bp->req_autoneg & AUTONEG_SPEED) &&
+                           (bp->req_line_speed == SPEED_1000))
+                               val1 = 1;
+                       bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_OPT_LASI_STATUS, &val2);
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_OPT_LASI_STATUS, &val1);
+                       DP(NETIF_MSG_LINK,
+                          "10G-base-T LASI status 0x%x->0x%x\n", val2, val1);
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_KR_STATUS, &val2);
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                         EXT_PHY_KR_STATUS, &val1);
+                       DP(NETIF_MSG_LINK,
+                          "10G-base-T PMA status 0x%x->0x%x\n", val2, val1);
+                       val1 = ((val1 & 4) == 4);
+                       /* if link is up
+                        * print the AN outcome of the SFX7101 PHY
                         */
-                       val = (rx_sd & pcs_status);
+                       if (val1) {
+                               bnx2x_mdio45_read(bp, ext_phy_addr,
+                                                 EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                                 0x21, &val2);
+                               DP(NETIF_MSG_LINK,
+                                  "SFX7101 AN status 0x%x->%s\n", val2,
+                                  (val2 & (1<<14)) ? "Master" : "Slave");
+                       }
                        break;
 
                default:
                        DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
                           bp->ext_phy_config);
-                       val = 0;
+                       val1 = 0;
                        break;
                }
-               bp->phy_addr = local_phy;
 
        } else { /* SerDes */
                ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
                switch (ext_phy_type) {
                case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
                        DP(NETIF_MSG_LINK, "SerDes Direct\n");
-                       val = 1;
+                       val1 = 1;
                        break;
 
                case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
                        DP(NETIF_MSG_LINK, "SerDes 5482\n");
-                       val = 1;
+                       val1 = 1;
                        break;
 
                default:
                        DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
                           bp->ext_phy_config);
-                       val = 0;
+                       val1 = 0;
                        break;
                }
        }
 
-       return val;
+       return val1;
 }
 
 static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb)
@@ -1819,7 +2165,7 @@ static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb)
        u32 wb_write[2];
        u32 val;
 
-       DP(NETIF_MSG_LINK, "enableing BigMAC\n");
+       DP(NETIF_MSG_LINK, "enabling BigMAC\n");
        /* reset and unreset the BigMac */
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
               (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -1933,6 +2279,35 @@ static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb)
        bp->stats_state = STATS_STATE_ENABLE;
 }
 
+static void bnx2x_bmac_rx_disable(struct bnx2x *bp)
+{
+       int port = bp->port;
+       u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
+                              NIG_REG_INGRESS_BMAC0_MEM;
+       u32 wb_write[2];
+
+       /* Only if the bmac is out of reset */
+       if (REG_RD(bp, MISC_REG_RESET_REG_2) &
+                       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)) {
+               /* Clear Rx Enable bit in BMAC_CONTROL register */
+#ifdef BNX2X_DMAE_RD
+               bnx2x_read_dmae(bp, bmac_addr +
+                               BIGMAC_REGISTER_BMAC_CONTROL, 2);
+               wb_write[0] = *bnx2x_sp(bp, wb_data[0]);
+               wb_write[1] = *bnx2x_sp(bp, wb_data[1]);
+#else
+               wb_write[0] = REG_RD(bp,
+                               bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL);
+               wb_write[1] = REG_RD(bp,
+                               bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL + 4);
+#endif
+               wb_write[0] &= ~BMAC_CONTROL_RX_ENABLE;
+               REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
+                           wb_write, 2);
+               msleep(1);
+       }
+}
+
 static void bnx2x_emac_enable(struct bnx2x *bp)
 {
        int port = bp->port;
@@ -1940,7 +2315,7 @@ static void bnx2x_emac_enable(struct bnx2x *bp)
        u32 val;
        int timeout;
 
-       DP(NETIF_MSG_LINK, "enableing EMAC\n");
+       DP(NETIF_MSG_LINK, "enabling EMAC\n");
        /* reset and unreset the emac core */
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
               (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
@@ -2033,7 +2408,7 @@ static void bnx2x_emac_enable(struct bnx2x *bp)
                                      EMAC_TX_MODE_EXT_PAUSE_EN);
        }
 
-       /* KEEP_VLAN_TAG, promiscous */
+       /* KEEP_VLAN_TAG, promiscuous */
        val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
        val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
        EMAC_WR(EMAC_REG_EMAC_RX_MODE, val);
@@ -2161,7 +2536,6 @@ static void bnx2x_pbf_update(struct bnx2x *bp)
        u32 count = 1000;
        u32 pause = 0;
 
-
        /* disable port */
        REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
 
@@ -2232,7 +2606,7 @@ static void bnx2x_pbf_update(struct bnx2x *bp)
 static void bnx2x_update_mng(struct bnx2x *bp)
 {
        if (!nomcp)
-               SHMEM_WR(bp, drv_fw_mb[bp->port].link_status,
+               SHMEM_WR(bp, port_mb[bp->port].link_status,
                         bp->link_status);
 }
 
@@ -2294,19 +2668,19 @@ static void bnx2x_link_down(struct bnx2x *bp)
                DP(BNX2X_MSG_STATS, "stats_state - STOP\n");
        }
 
-       /* indicate link down */
+       /* indicate no mac active */
        bp->phy_flags &= ~(PHY_BMAC_FLAG | PHY_EMAC_FLAG);
 
-       /* reset BigMac */
-       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
-              (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+       /* update shared memory */
+       bnx2x_update_mng(bp);
 
-       /* ignore drain flag interrupt */
        /* activate nig drain */
        NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
 
-       /* update shared memory */
-       bnx2x_update_mng(bp);
+       /* reset BigMac */
+       bnx2x_bmac_rx_disable(bp);
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+              (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
 
        /* indicate link down */
        bnx2x_link_report(bp);
@@ -2317,14 +2691,15 @@ static void bnx2x_init_mac_stats(struct bnx2x *bp);
 /* This function is called upon link interrupt */
 static void bnx2x_link_update(struct bnx2x *bp)
 {
-       u32 gp_status;
        int port = bp->port;
        int i;
+       u32 gp_status;
        int link_10g;
 
-       DP(NETIF_MSG_LINK, "port %x, is xgxs %x, stat_mask 0x%x,"
+       DP(NETIF_MSG_LINK, "port %x, %s, int_status 0x%x,"
           " int_mask 0x%x, saved_mask 0x%x, MI_INT %x, SERDES_LINK %x,"
-          " 10G %x, XGXS_LINK %x\n", port, (bp->phy_flags & PHY_XGXS_FLAG),
+          " 10G %x, XGXS_LINK %x\n", port,
+          (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes",
           REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4),
           REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), bp->nig_mask,
           REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
@@ -2336,7 +2711,7 @@ static void bnx2x_link_update(struct bnx2x *bp)
        might_sleep();
        MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_GP_STATUS);
        /* avoid fast toggling */
-       for (i = 0 ; i < 10 ; i++) {
+       for (i = 0; i < 10; i++) {
                msleep(10);
                bnx2x_mdio22_read(bp, MDIO_GP_STATUS_TOP_AN_STATUS1,
                                  &gp_status);
@@ -2351,7 +2726,8 @@ static void bnx2x_link_update(struct bnx2x *bp)
        bnx2x_link_int_ack(bp, link_10g);
 
        /* link is up only if both local phy and external phy are up */
-       if (bp->link_up && bnx2x_ext_phy_is_link_up(bp)) {
+       bp->link_up = (bp->phy_link_up && bnx2x_ext_phy_is_link_up(bp));
+       if (bp->link_up) {
                if (link_10g) {
                        bnx2x_bmac_enable(bp, 0);
                        bnx2x_leds_set(bp, SPEED_10000);
@@ -2427,7 +2803,9 @@ static void bnx2x_reset_unicore(struct bnx2x *bp)
                }
        }
 
-       BNX2X_ERR("BUG! unicore is still in reset!\n");
+       BNX2X_ERR("BUG! %s (0x%x) is still in reset!\n",
+                 (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes",
+                 bp->phy_addr);
 }
 
 static void bnx2x_set_swap_lanes(struct bnx2x *bp)
@@ -2475,12 +2853,12 @@ static void bnx2x_set_parallel_detection(struct bnx2x *bp)
                MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_10G_PARALLEL_DETECT);
 
                bnx2x_mdio22_write(bp,
-                                  MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
+                               MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
                               MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
 
                bnx2x_mdio22_read(bp,
-                                MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
-                                 &control2);
+                               MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+                               &control2);
 
                if (bp->autoneg & AUTONEG_PARALLEL) {
                        control2 |=
@@ -2490,8 +2868,14 @@ static void bnx2x_set_parallel_detection(struct bnx2x *bp)
                   ~MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
                }
                bnx2x_mdio22_write(bp,
-                                MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
-                                  control2);
+                               MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+                               control2);
+
+               /* Disable parallel detection of HiG */
+               MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2);
+               bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_UNICORE_MODE_10G,
+                               MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS |
+                               MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS);
        }
 }
 
@@ -2625,7 +3009,7 @@ static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x *bp)
        MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G);
 
        /* set extended capabilities */
-       if (bp->advertising & ADVERTISED_2500baseT_Full)
+       if (bp->advertising & ADVERTISED_2500baseX_Full)
                val |= MDIO_OVER_1G_UP1_2_5G;
        if (bp->advertising & ADVERTISED_10000baseT_Full)
                val |= MDIO_OVER_1G_UP1_10G;
@@ -2638,23 +3022,94 @@ static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x *bp)
 {
        u32 an_adv;
 
-       /* for AN, we are always publishing full duplex */
-       an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
+       /* for AN, we are always publishing full duplex */
+       an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
+
+       /* resolve pause mode and advertisement
+        * Please refer to Table 28B-3 of the 802.3ab-1999 spec */
+       if (bp->req_autoneg & AUTONEG_FLOW_CTRL) {
+               switch (bp->req_flow_ctrl) {
+               case FLOW_CTRL_AUTO:
+                       if (bp->dev->mtu <= 4500) {
+                               an_adv |=
+                                    MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+                               bp->advertising |= (ADVERTISED_Pause |
+                                                   ADVERTISED_Asym_Pause);
+                       } else {
+                               an_adv |=
+                              MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+                               bp->advertising |= ADVERTISED_Asym_Pause;
+                       }
+                       break;
+
+               case FLOW_CTRL_TX:
+                       an_adv |=
+                              MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+                       bp->advertising |= ADVERTISED_Asym_Pause;
+                       break;
+
+               case FLOW_CTRL_RX:
+                       if (bp->dev->mtu <= 4500) {
+                               an_adv |=
+                                    MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+                               bp->advertising |= (ADVERTISED_Pause |
+                                                   ADVERTISED_Asym_Pause);
+                       } else {
+                               an_adv |=
+                                    MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+                               bp->advertising &= ~(ADVERTISED_Pause |
+                                                    ADVERTISED_Asym_Pause);
+                       }
+                       break;
+
+               case FLOW_CTRL_BOTH:
+                       if (bp->dev->mtu <= 4500) {
+                               an_adv |=
+                                    MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+                               bp->advertising |= (ADVERTISED_Pause |
+                                                   ADVERTISED_Asym_Pause);
+                       } else {
+                               an_adv |=
+                              MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+                               bp->advertising |= ADVERTISED_Asym_Pause;
+                       }
+                       break;
+
+               case FLOW_CTRL_NONE:
+               default:
+                       an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+                       bp->advertising &= ~(ADVERTISED_Pause |
+                                            ADVERTISED_Asym_Pause);
+                       break;
+               }
+       } else { /* forced mode */
+               switch (bp->req_flow_ctrl) {
+               case FLOW_CTRL_AUTO:
+                       DP(NETIF_MSG_LINK, "req_flow_ctrl 0x%x while"
+                                          " req_autoneg 0x%x\n",
+                          bp->req_flow_ctrl, bp->req_autoneg);
+                       break;
+
+               case FLOW_CTRL_TX:
+                       an_adv |=
+                              MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+                       bp->advertising |= ADVERTISED_Asym_Pause;
+                       break;
 
-       /* set pause */
-       switch (bp->pause_mode) {
-       case PAUSE_SYMMETRIC:
-               an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
-               break;
-       case PAUSE_ASYMMETRIC:
-               an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
-               break;
-       case PAUSE_BOTH:
-               an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
-               break;
-       case PAUSE_NONE:
-               an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
-               break;
+               case FLOW_CTRL_RX:
+               case FLOW_CTRL_BOTH:
+                       an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+                       bp->advertising |= (ADVERTISED_Pause |
+                                           ADVERTISED_Asym_Pause);
+                       break;
+
+               case FLOW_CTRL_NONE:
+               default:
+                       an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+                       bp->advertising &= ~(ADVERTISED_Pause |
+                                            ADVERTISED_Asym_Pause);
+                       break;
+               }
        }
 
        MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
@@ -2752,47 +3207,162 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x *bp)
 static void bnx2x_link_int_enable(struct bnx2x *bp)
 {
        int port = bp->port;
+       u32 ext_phy_type;
+       u32 mask;
 
        /* setting the status to report on link up
           for either XGXS or SerDes */
        bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
-                      (NIG_XGXS0_LINK_STATUS |
-                       NIG_STATUS_INTERRUPT_XGXS0_LINK10G |
-                       NIG_SERDES0_LINK_STATUS));
+                      (NIG_STATUS_XGXS0_LINK10G |
+                       NIG_STATUS_XGXS0_LINK_STATUS |
+                       NIG_STATUS_SERDES0_LINK_STATUS));
 
        if (bp->phy_flags & PHY_XGXS_FLAG) {
-               /* TBD -
-                * in force mode (not AN) we can enable just the relevant
-                * interrupt
-                * Even in AN we might enable only one according to the AN
-                * speed mask
-                */
-               bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
-                             (NIG_MASK_XGXS0_LINK_STATUS |
-                              NIG_MASK_XGXS0_LINK10G));
-               DP(NETIF_MSG_LINK, "enable XGXS interrupt\n");
+               mask = (NIG_MASK_XGXS0_LINK10G |
+                       NIG_MASK_XGXS0_LINK_STATUS);
+               DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n");
+               ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+               if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
+                   (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+                   (ext_phy_type !=
+                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) {
+                       mask |= NIG_MASK_MI_INT;
+                       DP(NETIF_MSG_LINK, "enabled external phy int\n");
+               }
 
        } else { /* SerDes */
-               bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
-                             NIG_MASK_SERDES0_LINK_STATUS);
-               DP(NETIF_MSG_LINK, "enable SerDes interrupt\n");
+               mask = NIG_MASK_SERDES0_LINK_STATUS;
+               DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n");
+               ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
+               if ((ext_phy_type !=
+                               PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT) &&
+                   (ext_phy_type !=
+                               PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN)) {
+                       mask |= NIG_MASK_MI_INT;
+                       DP(NETIF_MSG_LINK, "enabled external phy int\n");
+               }
        }
+       bnx2x_bits_en(bp,
+                     NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+                     mask);
+       DP(NETIF_MSG_LINK, "port %x, %s, int_status 0x%x,"
+          " int_mask 0x%x, MI_INT %x, SERDES_LINK %x,"
+          " 10G %x, XGXS_LINK %x\n", port,
+          (bp->phy_flags & PHY_XGXS_FLAG)? "XGXS":"SerDes",
+          REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4),
+          REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4),
+          REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
+          REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c),
+          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
+          REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)
+       );
+}
+
+static void bnx2x_bcm8072_external_rom_boot(struct bnx2x *bp)
+{
+       u32 ext_phy_addr = ((bp->ext_phy_config &
+                            PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                           PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+       u32 fw_ver1, fw_ver2;
+
+       /* Need to wait 200ms after reset */
+       msleep(200);
+       /* Boot port from external ROM
+        * Set ser_boot_ctl bit in the MISC_CTRL1 register
+        */
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD,
+                               EXT_PHY_KR_MISC_CTRL1, 0x0001);
+
+       /* Reset internal microprocessor */
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL,
+                               EXT_PHY_KR_ROM_RESET_INTERNAL_MP);
+       /* set micro reset = 0 */
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL,
+                               EXT_PHY_KR_ROM_MICRO_RESET);
+       /* Reset internal microprocessor */
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_GEN_CTRL,
+                               EXT_PHY_KR_ROM_RESET_INTERNAL_MP);
+       /* wait for 100ms for code download via SPI port */
+       msleep(100);
+
+       /* Clear ser_boot_ctl bit */
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD,
+                               EXT_PHY_KR_MISC_CTRL1, 0x0000);
+       /* Wait 100ms */
+       msleep(100);
+
+       /* Print the PHY FW version */
+       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, ext_phy_addr,
+                              EXT_PHY_KR_PMA_PMD_DEVAD,
+                              0xca19, &fw_ver1);
+       bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0, ext_phy_addr,
+                              EXT_PHY_KR_PMA_PMD_DEVAD,
+                              0xca1a, &fw_ver2);
+       DP(NETIF_MSG_LINK,
+          "8072 FW version 0x%x:0x%x\n", fw_ver1, fw_ver2);
+}
+
+static void bnx2x_bcm8072_force_10G(struct bnx2x *bp)
+{
+       u32 ext_phy_addr = ((bp->ext_phy_config &
+                            PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                           PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+       /* Force KR or KX */
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_CTRL,
+                               0x2040);
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_CTRL2,
+                               0x000b);
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_PMA_PMD_DEVAD, EXT_PHY_KR_PMD_CTRL,
+                               0x0000);
+       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0, ext_phy_addr,
+                               EXT_PHY_KR_AUTO_NEG_DEVAD, EXT_PHY_KR_CTRL,
+                               0x0000);
 }
 
 static void bnx2x_ext_phy_init(struct bnx2x *bp)
 {
-       int port = bp->port;
        u32 ext_phy_type;
        u32 ext_phy_addr;
-       u32 local_phy;
+       u32 cnt;
+       u32 ctrl;
+       u32 val = 0;
 
        if (bp->phy_flags & PHY_XGXS_FLAG) {
-               local_phy = bp->phy_addr;
                ext_phy_addr = ((bp->ext_phy_config &
                                 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
                                PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
 
                ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+               /* Make sure that the soft reset is off (expect for the 8072:
+                * due to the lock, it will be done inside the specific
+                * handling)
+                */
+               if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) &&
+                   (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+                  (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) &&
+                   (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072)) {
+                       /* Wait for soft reset to get cleared upto 1 sec */
+                       for (cnt = 0; cnt < 1000; cnt++) {
+                               bnx2x_mdio45_read(bp, ext_phy_addr,
+                                                 EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                                 EXT_PHY_OPT_CNTL, &ctrl);
+                               if (!(ctrl & (1<<15)))
+                                       break;
+                               msleep(1);
+                       }
+                       DP(NETIF_MSG_LINK,
+                          "control reg 0x%x (after %d ms)\n", ctrl, cnt);
+               }
+
                switch (ext_phy_type) {
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
                        DP(NETIF_MSG_LINK, "XGXS Direct\n");
@@ -2800,49 +3370,235 @@ static void bnx2x_ext_phy_init(struct bnx2x *bp)
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
                        DP(NETIF_MSG_LINK, "XGXS 8705\n");
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
-                                     NIG_MASK_MI_INT);
-                       DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
 
-                       bp->phy_addr = ext_phy_type;
-                       bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                           EXT_PHY_OPT_PMA_PMD_DEVAD,
                                            EXT_PHY_OPT_PMD_MISC_CNTL,
                                            0x8288);
-                       bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                           EXT_PHY_OPT_PMA_PMD_DEVAD,
                                            EXT_PHY_OPT_PHY_IDENTIFIER,
                                            0x7fbf);
-                       bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                           EXT_PHY_OPT_PMA_PMD_DEVAD,
                                            EXT_PHY_OPT_CMU_PLL_BYPASS,
                                            0x0100);
-                       bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_WIS_DEVAD,
+                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                           EXT_PHY_OPT_WIS_DEVAD,
                                            EXT_PHY_OPT_LASI_CNTL, 0x1);
                        break;
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
                        DP(NETIF_MSG_LINK, "XGXS 8706\n");
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
-                                     NIG_MASK_MI_INT);
-                       DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
-
-                       bp->phy_addr = ext_phy_type;
-                       bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
-                                           EXT_PHY_OPT_PMD_DIGITAL_CNT,
-                                           0x400);
-                       bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+
+                       if (!(bp->req_autoneg & AUTONEG_SPEED)) {
+                               /* Force speed */
+                               if (bp->req_line_speed == SPEED_10000) {
+                                       DP(NETIF_MSG_LINK,
+                                          "XGXS 8706 force 10Gbps\n");
+                                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                               EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                               EXT_PHY_OPT_PMD_DIGITAL_CNT,
+                                               0x400);
+                               } else {
+                                       /* Force 1Gbps */
+                                       DP(NETIF_MSG_LINK,
+                                          "XGXS 8706 force 1Gbps\n");
+
+                                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                               EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                               EXT_PHY_OPT_CNTL,
+                                               0x0040);
+
+                                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                               EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                               EXT_PHY_OPT_CNTL2,
+                                               0x000D);
+                               }
+
+                               /* Enable LASI */
+                               bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                                   EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                                   EXT_PHY_OPT_LASI_CNTL,
+                                                   0x1);
+                       } else {
+                               /* AUTONEG */
+                               /* Allow CL37 through CL73 */
+                               DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n");
+                               bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                                   EXT_PHY_AUTO_NEG_DEVAD,
+                                                   EXT_PHY_OPT_AN_CL37_CL73,
+                                                   0x040c);
+
+                               /* Enable Full-Duplex advertisment on CL37 */
+                               bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                                   EXT_PHY_AUTO_NEG_DEVAD,
+                                                   EXT_PHY_OPT_AN_CL37_FD,
+                                                   0x0020);
+                               /* Enable CL37 AN */
+                               bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                                   EXT_PHY_AUTO_NEG_DEVAD,
+                                                   EXT_PHY_OPT_AN_CL37_AN,
+                                                   0x1000);
+                               /* Advertise 10G/1G support */
+                               if (bp->advertising &
+                                   ADVERTISED_1000baseT_Full)
+                                       val = (1<<5);
+                               if (bp->advertising &
+                                   ADVERTISED_10000baseT_Full)
+                                       val |= (1<<7);
+
+                               bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                                   EXT_PHY_AUTO_NEG_DEVAD,
+                                                   EXT_PHY_OPT_AN_ADV, val);
+                               /* Enable LASI */
+                               bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                                   EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                                   EXT_PHY_OPT_LASI_CNTL,
+                                                   0x1);
+
+                               /* Enable clause 73 AN */
+                               bnx2x_mdio45_write(bp, ext_phy_addr,
+                                                  EXT_PHY_AUTO_NEG_DEVAD,
+                                                  EXT_PHY_OPT_CNTL,
+                                                  0x1200);
+                       }
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+                       bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+                       /* Wait for soft reset to get cleared upto 1 sec */
+                       for (cnt = 0; cnt < 1000; cnt++) {
+                               bnx2x_mdio45_ctrl_read(bp, GRCBASE_EMAC0,
+                                               ext_phy_addr,
+                                               EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                               EXT_PHY_OPT_CNTL, &ctrl);
+                               if (!(ctrl & (1<<15)))
+                                       break;
+                               msleep(1);
+                       }
+                       DP(NETIF_MSG_LINK,
+                          "8072 control reg 0x%x (after %d ms)\n",
+                          ctrl, cnt);
+
+                       bnx2x_bcm8072_external_rom_boot(bp);
+                       DP(NETIF_MSG_LINK, "Finshed loading 8072 KR ROM\n");
+
+                       /* enable LASI */
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                               ext_phy_addr,
+                                               EXT_PHY_KR_PMA_PMD_DEVAD,
+                                               0x9000, 0x0400);
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                               ext_phy_addr,
+                                               EXT_PHY_KR_PMA_PMD_DEVAD,
+                                               EXT_PHY_KR_LASI_CNTL, 0x0004);
+
+                       /* If this is forced speed, set to KR or KX
+                        * (all other are not supported)
+                        */
+                       if (!(bp->req_autoneg & AUTONEG_SPEED)) {
+                               if (bp->req_line_speed == SPEED_10000) {
+                                       bnx2x_bcm8072_force_10G(bp);
+                                       DP(NETIF_MSG_LINK,
+                                          "Forced speed 10G on 8072\n");
+                                       /* unlock */
+                                       bnx2x_hw_unlock(bp,
+                                               HW_LOCK_RESOURCE_8072_MDIO);
+                                       break;
+                               } else
+                                       val = (1<<5);
+                       } else {
+
+                               /* Advertise 10G/1G support */
+                               if (bp->advertising &
+                                               ADVERTISED_1000baseT_Full)
+                                       val = (1<<5);
+                               if (bp->advertising &
+                                               ADVERTISED_10000baseT_Full)
+                                       val |= (1<<7);
+                       }
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                       ext_phy_addr,
+                                       EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                       0x11, val);
+                       /* Add support for CL37 ( passive mode ) I */
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                               ext_phy_addr,
+                                               EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                               0x8370, 0x040c);
+                       /* Add support for CL37 ( passive mode ) II */
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                               ext_phy_addr,
+                                               EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                               0xffe4, 0x20);
+                       /* Add support for CL37 ( passive mode ) III */
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                               ext_phy_addr,
+                                               EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                               0xffe0, 0x1000);
+                       /* Restart autoneg */
+                       msleep(500);
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                       ext_phy_addr,
+                                       EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                       EXT_PHY_KR_CTRL, 0x1200);
+                       DP(NETIF_MSG_LINK, "8072 Autoneg Restart: "
+                          "1G %ssupported  10G %ssupported\n",
+                          (val & (1<<5)) ? "" : "not ",
+                          (val & (1<<7)) ? "" : "not ");
+
+                       /* unlock */
+                       bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+                       DP(NETIF_MSG_LINK,
+                          "Setting the SFX7101 LASI indication\n");
+                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                           EXT_PHY_OPT_PMA_PMD_DEVAD,
                                            EXT_PHY_OPT_LASI_CNTL, 0x1);
+                       DP(NETIF_MSG_LINK,
+                          "Setting the SFX7101 LED to blink on traffic\n");
+                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                           EXT_PHY_OPT_PMA_PMD_DEVAD,
+                                           0xC007, (1<<3));
+
+                       /* read modify write pause advertizing */
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                         EXT_PHY_KR_AUTO_NEG_ADVERT, &val);
+                       val &= ~EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_BOTH;
+                       /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+                       if (bp->advertising & ADVERTISED_Pause)
+                               val |= EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE;
+
+                       if (bp->advertising & ADVERTISED_Asym_Pause) {
+                               val |=
+                                EXT_PHY_KR_AUTO_NEG_ADVERT_PAUSE_ASYMMETRIC;
+                       }
+                       DP(NETIF_MSG_LINK, "SFX7101 AN advertize 0x%x\n", val);
+                       bnx2x_mdio45_vwrite(bp, ext_phy_addr,
+                                           EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                           EXT_PHY_KR_AUTO_NEG_ADVERT, val);
+                       /* Restart autoneg */
+                       bnx2x_mdio45_read(bp, ext_phy_addr,
+                                         EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                         EXT_PHY_KR_CTRL, &val);
+                       val |= 0x200;
+                       bnx2x_mdio45_write(bp, ext_phy_addr,
+                                           EXT_PHY_KR_AUTO_NEG_DEVAD,
+                                           EXT_PHY_KR_CTRL, val);
                        break;
 
                default:
-                       DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
-                          bp->ext_phy_config);
+                       BNX2X_ERR("BAD XGXS ext_phy_config 0x%x\n",
+                                 bp->ext_phy_config);
                        break;
                }
-               bp->phy_addr = local_phy;
 
        } else { /* SerDes */
-/*             ext_phy_addr = ((bp->ext_phy_config &
+/*             ext_phy_addr = ((bp->ext_phy_config &
                                 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >>
                                PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT);
 */
@@ -2854,10 +3610,6 @@ static void bnx2x_ext_phy_init(struct bnx2x *bp)
 
                case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
                        DP(NETIF_MSG_LINK, "SerDes 5482\n");
-                       bnx2x_bits_en(bp,
-                                     NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
-                                     NIG_MASK_MI_INT);
-                       DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
                        break;
 
                default:
@@ -2871,8 +3623,22 @@ static void bnx2x_ext_phy_init(struct bnx2x *bp)
 static void bnx2x_ext_phy_reset(struct bnx2x *bp)
 {
        u32 ext_phy_type;
-       u32 ext_phy_addr;
-       u32 local_phy;
+       u32 ext_phy_addr = ((bp->ext_phy_config &
+                            PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+                           PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+       u32 board = (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK);
+
+       /* The PHY reset is controled by GPIO 1
+        * Give it 1ms of reset pulse
+        */
+       if ((board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G) &&
+           (board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G)) {
+               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                              MISC_REGISTERS_GPIO_OUTPUT_LOW);
+               msleep(1);
+               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                              MISC_REGISTERS_GPIO_OUTPUT_HIGH);
+       }
 
        if (bp->phy_flags & PHY_XGXS_FLAG) {
                ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
@@ -2883,15 +3649,24 @@ static void bnx2x_ext_phy_reset(struct bnx2x *bp)
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
-                       DP(NETIF_MSG_LINK, "XGXS 8705/6\n");
-                       local_phy = bp->phy_addr;
-                       ext_phy_addr = ((bp->ext_phy_config &
-                                       PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
-                                       PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
-                       bp->phy_addr = (u8)ext_phy_addr;
-                       bnx2x_mdio45_write(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+                       DP(NETIF_MSG_LINK, "XGXS 8705/8706\n");
+                       bnx2x_mdio45_write(bp, ext_phy_addr,
+                                          EXT_PHY_OPT_PMA_PMD_DEVAD,
                                           EXT_PHY_OPT_CNTL, 0xa040);
-                       bp->phy_addr = local_phy;
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
+                       DP(NETIF_MSG_LINK, "XGXS 8072\n");
+                       bnx2x_hw_lock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+                       bnx2x_mdio45_ctrl_write(bp, GRCBASE_EMAC0,
+                                               ext_phy_addr,
+                                               EXT_PHY_KR_PMA_PMD_DEVAD,
+                                               0, 1<<15);
+                       bnx2x_hw_unlock(bp, HW_LOCK_RESOURCE_8072_MDIO);
+                       break;
+
+               case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+                       DP(NETIF_MSG_LINK, "XGXS SFX7101\n");
                        break;
 
                default:
@@ -2930,6 +3705,7 @@ static void bnx2x_link_initialize(struct bnx2x *bp)
                        NIG_MASK_SERDES0_LINK_STATUS |
                        NIG_MASK_MI_INT));
 
+       /* Activate the external PHY */
        bnx2x_ext_phy_reset(bp);
 
        bnx2x_set_aer_mmd(bp);
@@ -2994,13 +3770,13 @@ static void bnx2x_link_initialize(struct bnx2x *bp)
                        /* AN enabled */
                        bnx2x_set_brcm_cl37_advertisment(bp);
 
-                       /* program duplex & pause advertisment (for aneg) */
+                       /* program duplex & pause advertisement (for aneg) */
                        bnx2x_set_ieee_aneg_advertisment(bp);
 
                        /* enable autoneg */
                        bnx2x_set_autoneg(bp);
 
-                       /* enalbe and restart AN */
+                       /* enable and restart AN */
                        bnx2x_restart_autoneg(bp);
                }
 
@@ -3010,11 +3786,11 @@ static void bnx2x_link_initialize(struct bnx2x *bp)
                bnx2x_initialize_sgmii_process(bp);
        }
 
-       /* enable the interrupt */
-       bnx2x_link_int_enable(bp);
-
        /* init ext phy and enable link state int */
        bnx2x_ext_phy_init(bp);
+
+       /* enable the interrupt */
+       bnx2x_link_int_enable(bp);
 }
 
 static void bnx2x_phy_deassert(struct bnx2x *bp)
@@ -3073,6 +3849,11 @@ static int bnx2x_phy_init(struct bnx2x *bp)
 static void bnx2x_link_reset(struct bnx2x *bp)
 {
        int port = bp->port;
+       u32 board = (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK);
+
+       /* update shared memory */
+       bp->link_status = 0;
+       bnx2x_update_mng(bp);
 
        /* disable attentions */
        bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
@@ -3081,21 +3862,45 @@ static void bnx2x_link_reset(struct bnx2x *bp)
                        NIG_MASK_SERDES0_LINK_STATUS |
                        NIG_MASK_MI_INT));
 
-       bnx2x_ext_phy_reset(bp);
+       /* activate nig drain */
+       NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+
+       /* disable nig egress interface */
+       NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0);
+       NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
+
+       /* Stop BigMac rx */
+       bnx2x_bmac_rx_disable(bp);
+
+       /* disable emac */
+       NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 0);
+
+       msleep(10);
+
+       /* The PHY reset is controled by GPIO 1
+        * Hold it as output low
+        */
+       if ((board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G) &&
+           (board != SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G)) {
+               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                              MISC_REGISTERS_GPIO_OUTPUT_LOW);
+               DP(NETIF_MSG_LINK, "reset external PHY\n");
+       }
 
        /* reset the SerDes/XGXS */
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
               (0x1ff << (port*16)));
 
-       /* reset EMAC / BMAC and disable NIG interfaces */
-       NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0);
-       NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0);
+       /* reset BigMac */
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+              (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
 
-       NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 0);
+       /* disable nig ingress interface */
+       NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0);
        NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0);
-       NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
 
-       NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+       /* set link down */
+       bp->link_up = 0;
 }
 
 #ifdef BNX2X_XGXS_LB
@@ -3158,7 +3963,7 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
        int port = bp->port;
 
        DP(NETIF_MSG_TIMER,
-          "spe (%x:%x)  command %x  hw_cid %x  data (%x:%x)  left %x\n",
+          "spe (%x:%x)  command %d  hw_cid %x  data (%x:%x)  left %x\n",
           (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) +
           (void *)bp->spq_prod_bd - (void *)bp->spq), command,
           HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
@@ -3176,6 +3981,7 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
                bnx2x_panic();
                return -EBUSY;
        }
+
        /* CID needs port number to be encoded int it */
        bp->spq_prod_bd->hdr.conn_and_cmd_data =
                        cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) |
@@ -3282,8 +4088,8 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
        u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8;
        u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
                              MISC_REG_AEU_MASK_ATTN_FUNC_0;
-       u32 nig_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
-                                  NIG_REG_MASK_INTERRUPT_PORT0;
+       u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
+                                      NIG_REG_MASK_INTERRUPT_PORT0;
 
        if (~bp->aeu_mask & (asserted & 0xff))
                BNX2X_ERR("IGU ERROR\n");
@@ -3301,15 +4107,11 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 
        if (asserted & ATTN_HARD_WIRED_MASK) {
                if (asserted & ATTN_NIG_FOR_FUNC) {
-                       u32 nig_status_port;
-                       u32 nig_int_addr = port ?
-                                       NIG_REG_STATUS_INTERRUPT_PORT1 :
-                                       NIG_REG_STATUS_INTERRUPT_PORT0;
 
-                       bp->nig_mask = REG_RD(bp, nig_mask_addr);
-                       REG_WR(bp, nig_mask_addr, 0);
+                       /* save nig interrupt mask */
+                       bp->nig_mask = REG_RD(bp, nig_int_mask_addr);
+                       REG_WR(bp, nig_int_mask_addr, 0);
 
-                       nig_status_port = REG_RD(bp, nig_int_addr);
                        bnx2x_link_update(bp);
 
                        /* handle unicore attn? */
@@ -3362,15 +4164,132 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 
        /* now set back the mask */
        if (asserted & ATTN_NIG_FOR_FUNC)
-               REG_WR(bp, nig_mask_addr, bp->nig_mask);
+               REG_WR(bp, nig_int_mask_addr, bp->nig_mask);
 }
 
-static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 {
        int port = bp->port;
-       int index;
+       int reg_offset;
+       u32 val;
+
+       if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) {
+
+               reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+                                    MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+
+               val = REG_RD(bp, reg_offset);
+               val &= ~AEU_INPUTS_ATTN_BITS_SPIO5;
+               REG_WR(bp, reg_offset, val);
+
+               BNX2X_ERR("SPIO5 hw attention\n");
+
+               switch (bp->board & SHARED_HW_CFG_BOARD_TYPE_MASK) {
+               case SHARED_HW_CFG_BOARD_TYPE_BCM957710A1022G:
+                       /* Fan failure attention */
+
+                       /* The PHY reset is controled by GPIO 1 */
+                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
+                                      MISC_REGISTERS_GPIO_OUTPUT_LOW);
+                       /* Low power mode is controled by GPIO 2 */
+                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+                                      MISC_REGISTERS_GPIO_OUTPUT_LOW);
+                       /* mark the failure */
+                       bp->ext_phy_config &=
+                                       ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+                       bp->ext_phy_config |=
+                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+                       SHMEM_WR(bp,
+                                dev_info.port_hw_config[port].
+                                                       external_phy_config,
+                                bp->ext_phy_config);
+                       /* log the failure */
+                       printk(KERN_ERR PFX "Fan Failure on Network"
+                              " Controller %s has caused the driver to"
+                              " shutdown the card to prevent permanent"
+                              " damage.  Please contact Dell Support for"
+                              " assistance\n", bp->dev->name);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+
+static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
+{
+       u32 val;
+
+       if (attn & BNX2X_DOORQ_ASSERT) {
+
+               val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
+               BNX2X_ERR("DB hw attention 0x%x\n", val);
+               /* DORQ discard attention */
+               if (val & 0x2)
+                       BNX2X_ERR("FATAL error from DORQ\n");
+       }
+}
+
+static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
+{
+       u32 val;
+
+       if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
+
+               val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
+               BNX2X_ERR("CFC hw attention 0x%x\n", val);
+               /* CFC error attention */
+               if (val & 0x2)
+                       BNX2X_ERR("FATAL error from CFC\n");
+       }
+
+       if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
+
+               val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
+               BNX2X_ERR("PXP hw attention 0x%x\n", val);
+               /* RQ_USDMDP_FIFO_OVERFLOW */
+               if (val & 0x18000)
+                       BNX2X_ERR("FATAL error from PXP\n");
+       }
+}
+
+static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
+{
+       if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) {
+
+               if (attn & BNX2X_MC_ASSERT_BITS) {
+
+                       BNX2X_ERR("MC assert!\n");
+                       REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0);
+                       REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0);
+                       REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0);
+                       REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0);
+                       bnx2x_panic();
+
+               } else if (attn & BNX2X_MCP_ASSERT) {
+
+                       BNX2X_ERR("MCP assert!\n");
+                       REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0);
+                       bnx2x_mc_assert(bp);
+
+               } else
+                       BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn);
+       }
+
+       if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
+
+               REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
+               BNX2X_ERR("LATCHED attention 0x%x (masked)\n", attn);
+       }
+}
+
+static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+{
        struct attn_route attn;
        struct attn_route group_mask;
+       int port = bp->port;
+       int index;
        u32 reg_addr;
        u32 val;
 
@@ -3391,64 +4310,14 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
                        DP(NETIF_MSG_HW, "group[%d]: %llx\n", index,
                           (unsigned long long)group_mask.sig[0]);
 
-                       if (attn.sig[3] & group_mask.sig[3] &
-                           EVEREST_GEN_ATTN_IN_USE_MASK) {
-
-                               if (attn.sig[3] & BNX2X_MC_ASSERT_BITS) {
-
-                                       BNX2X_ERR("MC assert!\n");
-                                       bnx2x_panic();
-
-                               } else if (attn.sig[3] & BNX2X_MCP_ASSERT) {
-
-                                       BNX2X_ERR("MCP assert!\n");
-                                       REG_WR(bp,
-                                            MISC_REG_AEU_GENERAL_ATTN_11, 0);
-                                       bnx2x_mc_assert(bp);
-
-                               } else {
-                                       BNX2X_ERR("UNKOWEN HW ASSERT!\n");
-                               }
-                       }
-
-                       if (attn.sig[1] & group_mask.sig[1] &
-                           BNX2X_DOORQ_ASSERT) {
-
-                               val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
-                               BNX2X_ERR("DB hw attention 0x%x\n", val);
-                               /* DORQ discard attention */
-                               if (val & 0x2)
-                                       BNX2X_ERR("FATAL error from DORQ\n");
-                       }
-
-                       if (attn.sig[2] & group_mask.sig[2] &
-                           AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
-
-                               val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
-                               BNX2X_ERR("CFC hw attention 0x%x\n", val);
-                               /* CFC error attention */
-                               if (val & 0x2)
-                                       BNX2X_ERR("FATAL error from CFC\n");
-                       }
-
-                       if (attn.sig[2] & group_mask.sig[2] &
-                           AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
-
-                               val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
-                               BNX2X_ERR("PXP hw attention 0x%x\n", val);
-                               /* RQ_USDMDP_FIFO_OVERFLOW */
-                               if (val & 0x18000)
-                                       BNX2X_ERR("FATAL error from PXP\n");
-                       }
-
-                       if (attn.sig[3] & group_mask.sig[3] &
-                           EVEREST_LATCHED_ATTN_IN_USE_MASK) {
-
-                               REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL,
-                                      0x7ff);
-                               DP(NETIF_MSG_HW, "got latched bits 0x%x\n",
-                                  attn.sig[3]);
-                       }
+                       bnx2x_attn_int_deasserted3(bp,
+                                       attn.sig[3] & group_mask.sig[3]);
+                       bnx2x_attn_int_deasserted1(bp,
+                                       attn.sig[1] & group_mask.sig[1]);
+                       bnx2x_attn_int_deasserted2(bp,
+                                       attn.sig[2] & group_mask.sig[2]);
+                       bnx2x_attn_int_deasserted0(bp,
+                                       attn.sig[0] & group_mask.sig[0]);
 
                        if ((attn.sig[0] & group_mask.sig[0] &
                                                HW_INTERRUT_ASSERT_SET_0) ||
@@ -3456,7 +4325,15 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
                                                HW_INTERRUT_ASSERT_SET_1) ||
                            (attn.sig[2] & group_mask.sig[2] &
                                                HW_INTERRUT_ASSERT_SET_2))
-                               BNX2X_ERR("FATAL HW block attention\n");
+                               BNX2X_ERR("FATAL HW block attention"
+                                         "  set0 0x%x  set1 0x%x"
+                                         "  set2 0x%x\n",
+                                         (attn.sig[0] & group_mask.sig[0] &
+                                          HW_INTERRUT_ASSERT_SET_0),
+                                         (attn.sig[1] & group_mask.sig[1] &
+                                          HW_INTERRUT_ASSERT_SET_1),
+                                         (attn.sig[2] & group_mask.sig[2] &
+                                          HW_INTERRUT_ASSERT_SET_2));
 
                        if ((attn.sig[0] & group_mask.sig[0] &
                                                HW_PRTY_ASSERT_SET_0) ||
@@ -3464,7 +4341,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
                                                HW_PRTY_ASSERT_SET_1) ||
                            (attn.sig[2] & group_mask.sig[2] &
                                                HW_PRTY_ASSERT_SET_2))
-                               BNX2X_ERR("FATAL HW block parity atention\n");
+                              BNX2X_ERR("FATAL HW block parity attention\n");
                }
        }
 
@@ -3529,7 +4406,7 @@ static void bnx2x_sp_task(struct work_struct *work)
 
        /* Return here if interrupt is disabled */
        if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-               DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+               DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n");
                return;
        }
 
@@ -3539,12 +4416,11 @@ static void bnx2x_sp_task(struct work_struct *work)
 
        DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status);
 
-       if (status & 0x1) {
-               /* HW attentions */
+       /* HW attentions */
+       if (status & 0x1)
                bnx2x_attn_int(bp);
-       }
 
-       /* CStorm events: query_stats, cfc delete ramrods */
+       /* CStorm events: query_stats, port delete ramrod */
        if (status & 0x2)
                bp->stat_pending = 0;
 
@@ -3558,6 +4434,7 @@ static void bnx2x_sp_task(struct work_struct *work)
                     IGU_INT_NOP, 1);
        bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
                     IGU_INT_ENABLE, 1);
+
 }
 
 static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
@@ -3567,11 +4444,11 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
 
        /* Return here if interrupt is disabled */
        if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
-               DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+               DP(BNX2X_MSG_SP, "called but intr_sem not 0, returning\n");
                return IRQ_HANDLED;
        }
 
-       bnx2x_ack_sb(bp, 16, XSTORM_ID, 0, IGU_INT_DISABLE, 0);
+       bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, 0, IGU_INT_DISABLE, 0);
 
 #ifdef BNX2X_STOP_ON_ERROR
        if (unlikely(bp->panic))
@@ -3906,7 +4783,7 @@ static void bnx2x_stop_stats(struct bnx2x *bp)
 
                while (bp->stats_state != STATS_STATE_DISABLE) {
                        if (!timeout) {
-                               BNX2X_ERR("timeout wating for stats stop\n");
+                               BNX2X_ERR("timeout waiting for stats stop\n");
                                break;
                        }
                        timeout--;
@@ -4173,39 +5050,37 @@ static void bnx2x_update_net_stats(struct bnx2x *bp)
 
        nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi);
 
-       nstats->tx_bytes =
-               bnx2x_hilo(&estats->total_bytes_transmitted_hi);
+       nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi);
 
-       nstats->rx_dropped = estats->checksum_discard +
-                                  estats->mac_discard;
+       nstats->rx_dropped = estats->checksum_discard + estats->mac_discard;
        nstats->tx_dropped = 0;
 
        nstats->multicast =
                bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi);
 
-       nstats->collisions =
-               estats->single_collision_transmit_frames +
-               estats->multiple_collision_transmit_frames +
-               estats->late_collision_frames +
-               estats->excessive_collision_frames;
+       nstats->collisions = estats->single_collision_transmit_frames +
+                            estats->multiple_collision_transmit_frames +
+                            estats->late_collision_frames +
+                            estats->excessive_collision_frames;
 
        nstats->rx_length_errors = estats->runt_packets_received +
                                   estats->jabber_packets_received;
-       nstats->rx_over_errors = estats->no_buff_discard;
+       nstats->rx_over_errors = estats->brb_discard +
+                                estats->brb_truncate_discard;
        nstats->rx_crc_errors = estats->crc_receive_errors;
        nstats->rx_frame_errors = estats->alignment_errors;
-       nstats->rx_fifo_errors = estats->brb_discard +
-                                      estats->brb_truncate_discard;
+       nstats->rx_fifo_errors = estats->no_buff_discard;
        nstats->rx_missed_errors = estats->xxoverflow_discard;
 
        nstats->rx_errors = nstats->rx_length_errors +
                            nstats->rx_over_errors +
                            nstats->rx_crc_errors +
                            nstats->rx_frame_errors +
-                           nstats->rx_fifo_errors;
+                           nstats->rx_fifo_errors +
+                           nstats->rx_missed_errors;
 
        nstats->tx_aborted_errors = estats->late_collision_frames +
-                                         estats->excessive_collision_frames;
+                                   estats->excessive_collision_frames;
        nstats->tx_carrier_errors = estats->false_carrier_detections;
        nstats->tx_fifo_errors = 0;
        nstats->tx_heartbeat_errors = 0;
@@ -4334,7 +5209,7 @@ static void bnx2x_timer(unsigned long data)
                return;
 
        if (atomic_read(&bp->intr_sem) != 0)
-               goto bnx2x_restart_timer;
+               goto timer_restart;
 
        if (poll) {
                struct bnx2x_fastpath *fp = &bp->fp[0];
@@ -4344,7 +5219,7 @@ static void bnx2x_timer(unsigned long data)
                rc = bnx2x_rx_int(fp, 1000);
        }
 
-       if (!nomcp && (bp->bc_ver >= 0x040003)) {
+       if (!nomcp) {
                int port = bp->port;
                u32 drv_pulse;
                u32 mcp_pulse;
@@ -4353,9 +5228,9 @@ static void bnx2x_timer(unsigned long data)
                bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
                /* TBD - add SYSTEM_TIME */
                drv_pulse = bp->fw_drv_pulse_wr_seq;
-               SHMEM_WR(bp, drv_fw_mb[port].drv_pulse_mb, drv_pulse);
+               SHMEM_WR(bp, func_mb[port].drv_pulse_mb, drv_pulse);
 
-               mcp_pulse = (SHMEM_RD(bp, drv_fw_mb[port].mcp_pulse_mb) &
+               mcp_pulse = (SHMEM_RD(bp, func_mb[port].mcp_pulse_mb) &
                             MCP_PULSE_SEQ_MASK);
                /* The delta between driver pulse and mcp response
                 * should be 1 (before mcp response) or 0 (after mcp response)
@@ -4369,11 +5244,11 @@ static void bnx2x_timer(unsigned long data)
        }
 
        if (bp->stats_state == STATS_STATE_DISABLE)
-               goto bnx2x_restart_timer;
+               goto timer_restart;
 
        bnx2x_update_stats(bp);
 
-bnx2x_restart_timer:
+timer_restart:
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 }
 
@@ -4438,6 +5313,9 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
                                            atten_status_block);
        def_sb->atten_status_block.status_block_id = id;
 
+       bp->def_att_idx = 0;
+       bp->attn_state = 0;
+
        reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
                             MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
 
@@ -4472,6 +5350,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
                                            u_def_status_block);
        def_sb->u_def_status_block.status_block_id = id;
 
+       bp->def_u_idx = 0;
+
        REG_WR(bp, BAR_USTRORM_INTMEM +
               USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
        REG_WR(bp, BAR_USTRORM_INTMEM +
@@ -4489,6 +5369,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
                                            c_def_status_block);
        def_sb->c_def_status_block.status_block_id = id;
 
+       bp->def_c_idx = 0;
+
        REG_WR(bp, BAR_CSTRORM_INTMEM +
               CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
        REG_WR(bp, BAR_CSTRORM_INTMEM +
@@ -4506,6 +5388,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
                                            t_def_status_block);
        def_sb->t_def_status_block.status_block_id = id;
 
+       bp->def_t_idx = 0;
+
        REG_WR(bp, BAR_TSTRORM_INTMEM +
               TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
        REG_WR(bp, BAR_TSTRORM_INTMEM +
@@ -4523,6 +5407,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
                                            x_def_status_block);
        def_sb->x_def_status_block.status_block_id = id;
 
+       bp->def_x_idx = 0;
+
        REG_WR(bp, BAR_XSTRORM_INTMEM +
               XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
        REG_WR(bp, BAR_XSTRORM_INTMEM +
@@ -4535,6 +5421,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
                REG_WR16(bp, BAR_XSTRORM_INTMEM +
                         XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1);
 
+       bp->stat_pending = 0;
+
        bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
 }
 
@@ -4626,7 +5514,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
                fp->rx_bd_prod = fp->rx_comp_prod = ring_prod;
                fp->rx_pkt = fp->rx_calls = 0;
 
-               /* Warning! this will genrate an interrupt (to the TSTORM) */
+               /* Warning! this will generate an interrupt (to the TSTORM) */
                /* must only be done when chip is initialized */
                REG_WR(bp, BAR_TSTRORM_INTMEM +
                       TSTORM_RCQ_PROD_OFFSET(port, j), ring_prod);
@@ -4678,7 +5566,6 @@ static void bnx2x_init_sp_ring(struct bnx2x *bp)
 
        bp->spq_left = MAX_SPQ_PENDING;
        bp->spq_prod_idx = 0;
-       bp->dsb_sp_prod_idx = 0;
        bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX;
        bp->spq_prod_bd = bp->spq;
        bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT;
@@ -4755,6 +5642,42 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
        REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
 }
 
+static void bnx2x_set_client_config(struct bnx2x *bp)
+{
+#ifdef BCM_VLAN
+       int mode = bp->rx_mode;
+#endif
+       int i, port = bp->port;
+       struct tstorm_eth_client_config tstorm_client = {0};
+
+       tstorm_client.mtu = bp->dev->mtu;
+       tstorm_client.statistics_counter_id = 0;
+       tstorm_client.config_flags =
+                               TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
+#ifdef BCM_VLAN
+       if (mode && bp->vlgrp) {
+               tstorm_client.config_flags |=
+                               TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE;
+               DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+       }
+#endif
+       if (mode != BNX2X_RX_MODE_PROMISC)
+               tstorm_client.drop_flags =
+                               TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR;
+
+       for_each_queue(bp, i) {
+               REG_WR(bp, BAR_TSTRORM_INTMEM +
+                      TSTORM_CLIENT_CONFIG_OFFSET(port, i),
+                      ((u32 *)&tstorm_client)[0]);
+               REG_WR(bp, BAR_TSTRORM_INTMEM +
+                      TSTORM_CLIENT_CONFIG_OFFSET(port, i) + 4,
+                      ((u32 *)&tstorm_client)[1]);
+       }
+
+/*     DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n",
+          ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */
+}
+
 static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
 {
        int mode = bp->rx_mode;
@@ -4794,41 +5717,9 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
 /*             DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i,
                   ((u32 *)&tstorm_mac_filter)[i]); */
        }
-}
-
-static void bnx2x_set_client_config(struct bnx2x *bp, int client_id)
-{
-#ifdef BCM_VLAN
-       int mode = bp->rx_mode;
-#endif
-       int port = bp->port;
-       struct tstorm_eth_client_config tstorm_client = {0};
-
-       tstorm_client.mtu = bp->dev->mtu;
-       tstorm_client.statistics_counter_id = 0;
-       tstorm_client.config_flags =
-               TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
-#ifdef BCM_VLAN
-       if (mode && bp->vlgrp) {
-               tstorm_client.config_flags |=
-                               TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE;
-               DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
-       }
-#endif
-       tstorm_client.drop_flags = (TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR |
-                                   TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR |
-                                   TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR |
-                                   TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR);
-
-       REG_WR(bp, BAR_TSTRORM_INTMEM +
-              TSTORM_CLIENT_CONFIG_OFFSET(port, client_id),
-              ((u32 *)&tstorm_client)[0]);
-       REG_WR(bp, BAR_TSTRORM_INTMEM +
-              TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) + 4,
-              ((u32 *)&tstorm_client)[1]);
 
-/*      DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n",
-          ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */
+       if (mode != BNX2X_RX_MODE_NONE)
+               bnx2x_set_client_config(bp);
 }
 
 static void bnx2x_init_internal(struct bnx2x *bp)
@@ -4836,7 +5727,6 @@ static void bnx2x_init_internal(struct bnx2x *bp)
        int port = bp->port;
        struct tstorm_eth_function_common_config tstorm_config = {0};
        struct stats_indication_flags stats_flags = {0};
-       int i;
 
        if (is_multi(bp)) {
                tstorm_config.config_flags = MULTI_FLAGS;
@@ -4850,13 +5740,9 @@ static void bnx2x_init_internal(struct bnx2x *bp)
 /*      DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n",
           (*(u32 *)&tstorm_config)); */
 
-       bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx untill link is up */
+       bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */
        bnx2x_set_storm_rx_mode(bp);
 
-       for_each_queue(bp, i)
-               bnx2x_set_client_config(bp, i);
-
-
        stats_flags.collect_eth = cpu_to_le32(1);
 
        REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port),
@@ -4902,7 +5788,7 @@ static void bnx2x_nic_init(struct bnx2x *bp)
        bnx2x_init_internal(bp);
        bnx2x_init_stats(bp);
        bnx2x_init_ind_table(bp);
-       bnx2x_enable_int(bp);
+       bnx2x_int_enable(bp);
 
 }
 
@@ -5265,8 +6151,10 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
        if (mode & 0x1) {       /* init common */
                DP(BNX2X_MSG_MCP, "starting common init  func %d  mode %x\n",
                   func, mode);
-               REG_WR(bp, MISC_REG_RESET_REG_1, 0xffffffff);
-               REG_WR(bp, MISC_REG_RESET_REG_2, 0xfffc);
+               REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
+                      0xffffffff);
+               REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
+                      0xfffc);
                bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END);
 
                REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100);
@@ -5359,7 +6247,7 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
                REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 8);
 #endif
                bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END);
-               /* softrest pulse */
+               /* soft reset pulse */
                REG_WR(bp, QM_REG_SOFT_RESET, 1);
                REG_WR(bp, QM_REG_SOFT_RESET, 0);
 
@@ -5413,7 +6301,7 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
                REG_WR(bp, SRC_REG_SOFT_RST, 1);
                for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) {
                        REG_WR(bp, i, 0xc0cac01a);
-                       /* TODO: repleace with something meaningfull */
+                       /* TODO: replace with something meaningful */
                }
                /* SRCH COMMON comes here */
                REG_WR(bp, SRC_REG_SOFT_RST, 0);
@@ -5486,6 +6374,28 @@ static int bnx2x_function_init(struct bnx2x *bp, int mode)
                enable_blocks_attention(bp)