Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / drivers / net / bnx2x_main.c
index 665ed36..57ff5b3 100644 (file)
@@ -1,6 +1,6 @@
 /* bnx2x_main.c: Broadcom Everest network driver.
  *
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2010 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
@@ -10,7 +10,7 @@
  * Written by: Eliezer Tamir
  * Based on code from Michael Chan's bnx2 driver
  * UDP CSUM errata workaround by Arik Gendelman
- * Slowpath rework by Vladislav Zolotarov
+ * Slowpath and fastpath rework by Vladislav Zolotarov
  * Statistics and Link management by Yitchak Gertner
  *
  */
@@ -49,6 +49,7 @@
 #include <linux/prefetch.h>
 #include <linux/zlib.h>
 #include <linux/io.h>
+#include <linux/stringify.h>
 
 
 #include "bnx2x.h"
 #include "bnx2x_init_ops.h"
 #include "bnx2x_dump.h"
 
-#define DRV_MODULE_VERSION     "1.48.114-1"
-#define DRV_MODULE_RELDATE     "2009/07/29"
+#define DRV_MODULE_VERSION     "1.52.53-1"
+#define DRV_MODULE_RELDATE     "2010/18/04"
 #define BNX2X_BC_VER           0x040200
 
 #include <linux/firmware.h>
 #include "bnx2x_fw_file_hdr.h"
 /* FW files */
-#define FW_FILE_PREFIX_E1              "bnx2x-e1-"
-#define FW_FILE_PREFIX_E1H             "bnx2x-e1h-"
+#define FW_FILE_VERSION                                        \
+       __stringify(BCM_5710_FW_MAJOR_VERSION) "."      \
+       __stringify(BCM_5710_FW_MINOR_VERSION) "."      \
+       __stringify(BCM_5710_FW_REVISION_VERSION) "."   \
+       __stringify(BCM_5710_FW_ENGINEERING_VERSION)
+#define FW_FILE_NAME_E1                "bnx2x-e1-" FW_FILE_VERSION ".fw"
+#define FW_FILE_NAME_E1H       "bnx2x-e1h-" FW_FILE_VERSION ".fw"
 
 /* Time in jiffies before concluding the transmitter is hung */
 #define TX_TIMEOUT             (5*HZ)
@@ -77,10 +83,18 @@ MODULE_AUTHOR("Eliezer Tamir");
 MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710/57711/57711E Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_FIRMWARE(FW_FILE_NAME_E1);
+MODULE_FIRMWARE(FW_FILE_NAME_E1H);
 
 static int multi_mode = 1;
 module_param(multi_mode, int, 0);
-MODULE_PARM_DESC(multi_mode, " Use per-CPU queues");
+MODULE_PARM_DESC(multi_mode, " Multi queue mode "
+                            "(0 Disable; 1 Enable (default))");
+
+static int num_queues;
+module_param(num_queues, int, 0);
+MODULE_PARM_DESC(num_queues, " Number of queues for multi_mode=1"
+                               " (default is as a number of CPUs)");
 
 static int disable_tpa;
 module_param(disable_tpa, int, 0);
@@ -88,7 +102,12 @@ MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
 
 static int int_mode;
 module_param(int_mode, int, 0);
-MODULE_PARM_DESC(int_mode, " Force interrupt mode (1 INT#x; 2 MSI)");
+MODULE_PARM_DESC(int_mode, " Force interrupt mode other then MSI-X "
+                               "(1 INT#x; 2 MSI)");
+
+static int dropless_fc;
+module_param(dropless_fc, int, 0);
+MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");
 
 static int poll;
 module_param(poll, int, 0);
@@ -122,13 +141,10 @@ static struct {
 };
 
 
-static const struct pci_device_id bnx2x_pci_tbl[] = {
-       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 },
-       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711 },
-       { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57711E,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57711E },
+static DEFINE_PCI_DEVICE_TABLE(bnx2x_pci_tbl) = {
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
+       { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
        { 0 }
 };
 
@@ -141,7 +157,7 @@ MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
 /* used only at init
  * locking is done by mcp
  */
-static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
+void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
 {
        pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
        pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
@@ -188,7 +204,7 @@ static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae,
 void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
                      u32 len32)
 {
-       struct dmae_command *dmae = &bp->init_dmae;
+       struct dmae_command dmae;
        u32 *wb_comp = bnx2x_sp(bp, wb_comp);
        int cnt = 200;
 
@@ -201,43 +217,43 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
                return;
        }
 
-       mutex_lock(&bp->dmae_mutex);
-
-       memset(dmae, 0, sizeof(struct dmae_command));
+       memset(&dmae, 0, sizeof(struct dmae_command));
 
-       dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
-                       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-                       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+       dmae.opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+                      DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+                      DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
 #ifdef __BIG_ENDIAN
-                       DMAE_CMD_ENDIANITY_B_DW_SWAP |
+                      DMAE_CMD_ENDIANITY_B_DW_SWAP |
 #else
-                       DMAE_CMD_ENDIANITY_DW_SWAP |
+                      DMAE_CMD_ENDIANITY_DW_SWAP |
 #endif
-                       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-                       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-       dmae->src_addr_lo = U64_LO(dma_addr);
-       dmae->src_addr_hi = U64_HI(dma_addr);
-       dmae->dst_addr_lo = dst_addr >> 2;
-       dmae->dst_addr_hi = 0;
-       dmae->len = len32;
-       dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
-       dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
-       dmae->comp_val = DMAE_COMP_VAL;
+                      (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+                      (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+       dmae.src_addr_lo = U64_LO(dma_addr);
+       dmae.src_addr_hi = U64_HI(dma_addr);
+       dmae.dst_addr_lo = dst_addr >> 2;
+       dmae.dst_addr_hi = 0;
+       dmae.len = len32;
+       dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
+       dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
+       dmae.comp_val = DMAE_COMP_VAL;
 
        DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
           DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
                    "dst_addr [%x:%08x (%08x)]\n"
           DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
-          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
-          dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr,
-          dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val);
+          dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
+          dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, dst_addr,
+          dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
        DP(BNX2X_MSG_OFF, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
           bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
           bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
 
+       mutex_lock(&bp->dmae_mutex);
+
        *wb_comp = 0;
 
-       bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
+       bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
 
        udelay(5);
 
@@ -261,7 +277,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
 
 void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
 {
-       struct dmae_command *dmae = &bp->init_dmae;
+       struct dmae_command dmae;
        u32 *wb_comp = bnx2x_sp(bp, wb_comp);
        int cnt = 200;
 
@@ -276,41 +292,41 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
                return;
        }
 
-       mutex_lock(&bp->dmae_mutex);
-
-       memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4);
-       memset(dmae, 0, sizeof(struct dmae_command));
+       memset(&dmae, 0, sizeof(struct dmae_command));
 
-       dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
-                       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
-                       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+       dmae.opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+                      DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+                      DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
 #ifdef __BIG_ENDIAN
-                       DMAE_CMD_ENDIANITY_B_DW_SWAP |
+                      DMAE_CMD_ENDIANITY_B_DW_SWAP |
 #else
-                       DMAE_CMD_ENDIANITY_DW_SWAP |
+                      DMAE_CMD_ENDIANITY_DW_SWAP |
 #endif
-                       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
-                       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
-       dmae->src_addr_lo = src_addr >> 2;
-       dmae->src_addr_hi = 0;
-       dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
-       dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
-       dmae->len = len32;
-       dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
-       dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
-       dmae->comp_val = DMAE_COMP_VAL;
+                      (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+                      (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+       dmae.src_addr_lo = src_addr >> 2;
+       dmae.src_addr_hi = 0;
+       dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
+       dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
+       dmae.len = len32;
+       dmae.comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
+       dmae.comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
+       dmae.comp_val = DMAE_COMP_VAL;
 
        DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
           DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
                    "dst_addr [%x:%08x (%08x)]\n"
           DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
-          dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
-          dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr,
-          dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val);
+          dmae.opcode, dmae.src_addr_hi, dmae.src_addr_lo,
+          dmae.len, dmae.dst_addr_hi, dmae.dst_addr_lo, src_addr,
+          dmae.comp_addr_hi, dmae.comp_addr_lo, dmae.comp_val);
+
+       mutex_lock(&bp->dmae_mutex);
 
+       memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4);
        *wb_comp = 0;
 
-       bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));
+       bnx2x_post_dmae(bp, &dmae, INIT_DMAE_C(bp));
 
        udelay(5);
 
@@ -334,6 +350,22 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
        mutex_unlock(&bp->dmae_mutex);
 }
 
+void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
+                              u32 addr, u32 len)
+{
+       int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
+       int offset = 0;
+
+       while (len > dmae_wr_max) {
+               bnx2x_write_dmae(bp, phys_addr + offset,
+                                addr + offset, dmae_wr_max);
+               offset += dmae_wr_max * 4;
+               len -= dmae_wr_max;
+       }
+
+       bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
+}
+
 /* used only for slowpath so not inlined */
 static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo)
 {
@@ -478,30 +510,35 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
 
 static void bnx2x_fw_dump(struct bnx2x *bp)
 {
+       u32 addr;
        u32 mark, offset;
        __be32 data[9];
        int word;
 
-       mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104);
-       mark = ((mark + 0x3) & ~0x3);
-       printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n", mark);
+       if (BP_NOMCP(bp)) {
+               BNX2X_ERR("NO MCP - can not dump\n");
+               return;
+       }
+
+       addr = bp->common.shmem_base - 0x0800 + 4;
+       mark = REG_RD(bp, addr);
+       mark = MCP_REG_MCPR_SCRATCH + ((mark + 0x3) & ~0x3) - 0x08000000;
+       pr_err("begin fw dump (mark 0x%x)\n", mark);
 
-       printk(KERN_ERR PFX);
-       for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) {
+       pr_err("");
+       for (offset = mark; offset <= bp->common.shmem_base; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
-                       data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
-                                                 offset + 4*word));
+                       data[word] = htonl(REG_RD(bp, offset + 4*word));
                data[8] = 0x0;
-               printk(KERN_CONT "%s", (char *)data);
+               pr_cont("%s", (char *)data);
        }
-       for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) {
+       for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
-                       data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
-                                                 offset + 4*word));
+                       data[word] = htonl(REG_RD(bp, offset + 4*word));
                data[8] = 0x0;
-               printk(KERN_CONT "%s", (char *)data);
+               pr_cont("%s", (char *)data);
        }
-       printk(KERN_ERR PFX "end of fw dump\n");
+       pr_err("end of fw dump\n");
 }
 
 static void bnx2x_panic_dump(struct bnx2x *bp)
@@ -516,47 +553,47 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
 
        /* Indices */
        /* Common */
-       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",
+       BNX2X_ERR("def_c_idx(0x%x)  def_u_idx(0x%x)  def_x_idx(0x%x)"
+                 "  def_t_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)"
+                 "  spq_prod_idx(0x%x)\n",
                  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);
 
        /* Rx */
-       for_each_rx_queue(bp, i) {
+       for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
-               BNX2X_ERR("fp%d: rx_bd_prod(%x)  rx_bd_cons(%x)"
-                         "  *rx_bd_cons_sb(%x)  rx_comp_prod(%x)"
-                         "  rx_comp_cons(%x)  *rx_cons_sb(%x)\n",
+               BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)"
+                         "  *rx_bd_cons_sb(0x%x)  rx_comp_prod(0x%x)"
+                         "  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
                          i, fp->rx_bd_prod, fp->rx_bd_cons,
                          le16_to_cpu(*fp->rx_bd_cons_sb), fp->rx_comp_prod,
                          fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
-               BNX2X_ERR("      rx_sge_prod(%x)  last_max_sge(%x)"
-                         "  fp_u_idx(%x) *sb_u_idx(%x)\n",
+               BNX2X_ERR("     rx_sge_prod(0x%x)  last_max_sge(0x%x)"
+                         "  fp_u_idx(0x%x) *sb_u_idx(0x%x)\n",
                          fp->rx_sge_prod, fp->last_max_sge,
                          le16_to_cpu(fp->fp_u_idx),
                          fp->status_blk->u_status_block.status_block_index);
        }
 
        /* Tx */
-       for_each_tx_queue(bp, i) {
+       for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
-               struct eth_tx_db_data *hw_prods = fp->hw_tx_prods;
 
-               BNX2X_ERR("fp%d: tx_pkt_prod(%x)  tx_pkt_cons(%x)"
-                         "  tx_bd_prod(%x)  tx_bd_cons(%x)  *tx_cons_sb(%x)\n",
+               BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)"
+                         "  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)"
+                         "  *tx_cons_sb(0x%x)\n",
                          i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
                          fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb));
-               BNX2X_ERR("      fp_c_idx(%x)  *sb_c_idx(%x)"
-                         "  bd data(%x,%x)\n", le16_to_cpu(fp->fp_c_idx),
+               BNX2X_ERR("     fp_c_idx(0x%x)  *sb_c_idx(0x%x)"
+                         "  tx_db_prod(0x%x)\n", le16_to_cpu(fp->fp_c_idx),
                          fp->status_blk->c_status_block.status_block_index,
-                         hw_prods->packets_prod, hw_prods->bds_prod);
+                         fp->tx_db.data.prod);
        }
 
        /* Rings */
        /* Rx */
-       for_each_rx_queue(bp, i) {
+       for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
                start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
@@ -590,7 +627,7 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
        }
 
        /* Tx */
-       for_each_tx_queue(bp, i) {
+       for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
                start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10);
@@ -697,7 +734,6 @@ static void bnx2x_int_disable(struct bnx2x *bp)
        REG_WR(bp, addr, val);
        if (REG_RD(bp, addr) != val)
                BNX2X_ERR("BUG! proper val not read from IGU!\n");
-
 }
 
 static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
@@ -717,6 +753,9 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
        if (msix) {
                synchronize_irq(bp->msix_table[0].vector);
                offset = 1;
+#ifdef BCM_CNIC
+               offset++;
+#endif
                for_each_queue(bp, i)
                        synchronize_irq(bp->msix_table[i + offset].vector);
        } else
@@ -733,6 +772,40 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
  * General service functions
  */
 
+/* Return true if succeeded to acquire the lock */
+static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
+{
+       u32 lock_status;
+       u32 resource_bit = (1 << resource);
+       int func = BP_FUNC(bp);
+       u32 hw_lock_control_reg;
+
+       DP(NETIF_MSG_HW, "Trying to take a lock on resource %d\n", resource);
+
+       /* 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;
+       }
+
+       if (func <= 5)
+               hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
+       else
+               hw_lock_control_reg =
+                               (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
+
+       /* Try to acquire the lock */
+       REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
+       lock_status = REG_RD(bp, hw_lock_control_reg);
+       if (lock_status & resource_bit)
+               return true;
+
+       DP(NETIF_MSG_HW, "Failed to get a lock on resource %d\n", resource);
+       return false;
+}
+
 static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
                                u8 storm, u16 index, u8 op, u8 update)
 {
@@ -756,21 +829,13 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
        barrier();
 }
 
-static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
+static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
 {
        struct host_status_block *fpsb = fp->status_blk;
-       u16 rc = 0;
 
        barrier(); /* status block is written to by the chip */
-       if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) {
-               fp->fp_c_idx = fpsb->c_status_block.status_block_index;
-               rc |= 1;
-       }
-       if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) {
-               fp->fp_u_idx = fpsb->u_status_block.status_block_index;
-               rc |= 2;
-       }
-       return rc;
+       fp->fp_c_idx = fpsb->c_status_block.status_block_index;
+       fp->fp_u_idx = fpsb->u_status_block.status_block_index;
 }
 
 static u16 bnx2x_ack_int(struct bnx2x *bp)
@@ -790,16 +855,6 @@ static u16 bnx2x_ack_int(struct bnx2x *bp)
  * fast path service functions
  */
 
-static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
-{
-       u16 tx_cons_sb;
-
-       /* Tell compiler that status block fields can change */
-       barrier();
-       tx_cons_sb = le16_to_cpu(*fp->tx_cons_sb);
-       return (fp->tx_pkt_cons != tx_cons_sb);
-}
-
 static inline int bnx2x_has_tx_work_unload(struct bnx2x_fastpath *fp)
 {
        /* Tell compiler that consumer and producer can change */
@@ -814,54 +869,53 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                             u16 idx)
 {
        struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx];
-       struct eth_tx_bd *tx_bd;
+       struct eth_tx_start_bd *tx_start_bd;
+       struct eth_tx_bd *tx_data_bd;
        struct sk_buff *skb = tx_buf->skb;
        u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
        int nbd;
 
+       /* prefetch skb end pointer to speedup dev_kfree_skb() */
+       prefetch(&skb->end);
+
        DP(BNX2X_MSG_OFF, "pkt_idx %d  buff @(%p)->skb %p\n",
           idx, tx_buf, skb);
 
        /* unmap first bd */
        DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
-       tx_bd = &fp->tx_desc_ring[bd_idx];
-       pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd),
-                        BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE);
+       tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd;
+       dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
+                        BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE);
 
-       nbd = le16_to_cpu(tx_bd->nbd) - 1;
-       new_cons = nbd + tx_buf->first_bd;
+       nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
 #ifdef BNX2X_STOP_ON_ERROR
-       if (nbd > (MAX_SKB_FRAGS + 2)) {
+       if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) {
                BNX2X_ERR("BAD nbd!\n");
                bnx2x_panic();
        }
 #endif
+       new_cons = nbd + tx_buf->first_bd;
 
-       /* Skip a parse bd and the TSO split header bd
-          since they have no mapping */
-       if (nbd)
-               bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+       /* Get the next bd */
+       bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
 
-       if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM |
-                                          ETH_TX_BD_FLAGS_TCP_CSUM |
-                                          ETH_TX_BD_FLAGS_SW_LSO)) {
-               if (--nbd)
-                       bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-               tx_bd = &fp->tx_desc_ring[bd_idx];
-               /* is this a TSO split header bd? */
-               if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) {
-                       if (--nbd)
-                               bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
-               }
+       /* Skip a parse bd... */
+       --nbd;
+       bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+
+       /* ...and the TSO split header bd since they have no mapping */
+       if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
+               --nbd;
+               bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
        }
 
        /* now free frags */
        while (nbd > 0) {
 
                DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
-               tx_bd = &fp->tx_desc_ring[bd_idx];
-               pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd),
-                              BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE);
+               tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd;
+               dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
+                              BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
                if (--nbd)
                        bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
        }
@@ -881,7 +935,6 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
        u16 prod;
        u16 cons;
 
-       barrier(); /* Tell compiler that prod and cons can change */
        prod = fp->tx_bd_prod;
        cons = fp->tx_bd_cons;
 
@@ -898,16 +951,25 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
        return (s16)(fp->bp->tx_ring_size) - used;
 }
 
-static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
+static inline int bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
+{
+       u16 hw_cons;
+
+       /* Tell compiler that status block fields can change */
+       barrier();
+       hw_cons = le16_to_cpu(*fp->tx_cons_sb);
+       return hw_cons != fp->tx_pkt_cons;
+}
+
+static int bnx2x_tx_int(struct bnx2x_fastpath *fp)
 {
        struct bnx2x *bp = fp->bp;
        struct netdev_queue *txq;
        u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons;
-       int done = 0;
 
 #ifdef BNX2X_STOP_ON_ERROR
        if (unlikely(bp->panic))
-               return;
+               return -1;
 #endif
 
        txq = netdev_get_tx_queue(bp->dev, fp->index);
@@ -931,25 +993,33 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
 */
                bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
                sw_cons++;
-               done++;
        }
 
        fp->tx_pkt_cons = sw_cons;
        fp->tx_bd_cons = bd_cons;
 
+       /* Need to make the tx_bd_cons update visible to start_xmit()
+        * before checking for netif_tx_queue_stopped().  Without the
+        * memory barrier, there is a small possibility that
+        * start_xmit() will miss it and cause the queue to be stopped
+        * forever.
+        */
+       smp_mb();
+
        /* TBD need a thresh? */
        if (unlikely(netif_tx_queue_stopped(txq))) {
+               /* Taking tx_lock() is needed to prevent reenabling the queue
+                * while it's empty. This could have happen if rx_action() gets
+                * suspended in bnx2x_tx_int() after the condition before
+                * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
+                *
+                * stops the queue->sees fresh tx_bd_cons->releases the queue->
+                * sends some packets consuming the whole queue again->
+                * stops the queue
+                */
 
                __netif_tx_lock(txq, smp_processor_id());
 
-               /* Need to make the tx_bd_cons update visible to start_xmit()
-                * before checking for netif_tx_queue_stopped().  Without the
-                * memory barrier, there is a small possibility that
-                * start_xmit() will miss it and cause the queue to be stopped
-                * forever.
-                */
-               smp_mb();
-
                if ((netif_tx_queue_stopped(txq)) &&
                    (bp->state == BNX2X_STATE_OPEN) &&
                    (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
@@ -957,8 +1027,12 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
 
                __netif_tx_unlock(txq);
        }
+       return 0;
 }
 
+#ifdef BCM_CNIC
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid);
+#endif
 
 static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
                           union eth_rx_cqe *rr_cqe)
@@ -991,7 +1065,8 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
 
                default:
                        BNX2X_ERR("unexpected MC reply (%d)  "
-                                 "fp->state is %x\n", command, fp->state);
+                                 "fp[%d] state is %x\n",
+                                 command, fp->index, fp->state);
                        break;
                }
                mb(); /* force bnx2x_wait_ramrod() to see the change */
@@ -1015,15 +1090,24 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
                bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED;
                break;
 
+#ifdef BCM_CNIC
+       case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_OPEN):
+               DP(NETIF_MSG_IFDOWN, "got delete ramrod for CID %d\n", cid);
+               bnx2x_cnic_cfc_comp(bp, cid);
+               break;
+#endif
 
        case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
        case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG):
                DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
-               bp->set_mac_pending = 0;
+               bp->set_mac_pending--;
+               smp_wmb();
                break;
 
        case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
                DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n");
+               bp->set_mac_pending--;
+               smp_wmb();
                break;
 
        default:
@@ -1045,7 +1129,7 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
        if (!page)
                return;
 
-       pci_unmap_page(bp->pdev, pci_unmap_addr(sw_buf, mapping),
+       dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
                       SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
        __free_pages(page, PAGES_PER_SGE_SHIFT);
 
@@ -1074,15 +1158,15 @@ static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
        if (unlikely(page == NULL))
                return -ENOMEM;
 
-       mapping = pci_map_page(bp->pdev, page, 0, SGE_PAGE_SIZE*PAGES_PER_SGE,
-                              PCI_DMA_FROMDEVICE);
+       mapping = dma_map_page(&bp->pdev->dev, page, 0,
+                              SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                __free_pages(page, PAGES_PER_SGE_SHIFT);
                return -ENOMEM;
        }
 
        sw_buf->page = page;
-       pci_unmap_addr_set(sw_buf, mapping, mapping);
+       dma_unmap_addr_set(sw_buf, mapping, mapping);
 
        sge->addr_hi = cpu_to_le32(U64_HI(mapping));
        sge->addr_lo = cpu_to_le32(U64_LO(mapping));
@@ -1102,15 +1186,15 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
        if (unlikely(skb == NULL))
                return -ENOMEM;
 
-       mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_size,
-                                PCI_DMA_FROMDEVICE);
+       mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_size,
+                                DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                dev_kfree_skb(skb);
                return -ENOMEM;
        }
 
        rx_buf->skb = skb;
-       pci_unmap_addr_set(rx_buf, mapping, mapping);
+       dma_unmap_addr_set(rx_buf, mapping, mapping);
 
        rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
        rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
@@ -1132,13 +1216,13 @@ static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
        struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons];
        struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
 
-       pci_dma_sync_single_for_device(bp->pdev,
-                                      pci_unmap_addr(cons_rx_buf, mapping),
-                                      RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+       dma_sync_single_for_device(&bp->pdev->dev,
+                                  dma_unmap_addr(cons_rx_buf, mapping),
+                                  RX_COPY_THRESH, DMA_FROM_DEVICE);
 
        prod_rx_buf->skb = cons_rx_buf->skb;
-       pci_unmap_addr_set(prod_rx_buf, mapping,
-                          pci_unmap_addr(cons_rx_buf, mapping));
+       dma_unmap_addr_set(prod_rx_buf, mapping,
+                          dma_unmap_addr(cons_rx_buf, mapping));
        *prod_bd = *cons_bd;
 }
 
@@ -1242,9 +1326,9 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
        /* move empty skb from pool to prod and map it */
        prod_rx_buf->skb = fp->tpa_pool[queue].skb;
-       mapping = pci_map_single(bp->pdev, fp->tpa_pool[queue].skb->data,
-                                bp->rx_buf_size, PCI_DMA_FROMDEVICE);
-       pci_unmap_addr_set(prod_rx_buf, mapping, mapping);
+       mapping = dma_map_single(&bp->pdev->dev, fp->tpa_pool[queue].skb->data,
+                                bp->rx_buf_size, DMA_FROM_DEVICE);
+       dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
 
        /* move partial skb from cons to pool (don't unmap yet) */
        fp->tpa_pool[queue] = *cons_rx_buf;
@@ -1261,7 +1345,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
 #ifdef BNX2X_STOP_ON_ERROR
        fp->tpa_queue_used |= (1 << queue);
-#ifdef __powerpc64__
+#ifdef _ASM_GENERIC_INT_L64_H
        DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
 #else
        DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
@@ -1290,8 +1374,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                                               max(frag_size, (u32)len_on_bd));
 
 #ifdef BNX2X_STOP_ON_ERROR
-       if (pages >
-           min((u32)8, (u32)MAX_SKB_FRAGS) * SGE_PAGE_SIZE * PAGES_PER_SGE) {
+       if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
                BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
                          pages, cqe_idx);
                BNX2X_ERR("fp_cqe->pkt_len = %d  fp_cqe->len_on_bd = %d\n",
@@ -1320,8 +1403,9 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 
                /* Unmap the page as we r going to pass it to the stack */
-               pci_unmap_page(bp->pdev, pci_unmap_addr(&old_rx_pg, mapping),
-                             SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
+               dma_unmap_page(&bp->pdev->dev,
+                              dma_unmap_addr(&old_rx_pg, mapping),
+                              SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
 
                /* Add one frag and update the appropriate fields in the skb */
                skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
@@ -1348,8 +1432,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        /* Unmap skb in the pool anyway, as we are going to change
           pool entry status to BNX2X_TPA_STOP even if new skb allocation
           fails. */
-       pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
-                        bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+       dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
+                        bp->rx_buf_size, DMA_FROM_DEVICE);
 
        if (likely(new_skb)) {
                /* fix ip xsum and give it to the stack */
@@ -1400,12 +1484,12 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 #ifdef BCM_VLAN
                        if ((bp->vlgrp != NULL) && is_vlan_cqe &&
                            (!is_not_hwaccel_vlan_cqe))
-                               vlan_hwaccel_receive_skb(skb, bp->vlgrp,
-                                               le16_to_cpu(cqe->fast_path_cqe.
-                                                           vlan_tag));
+                               vlan_gro_receive(&fp->napi, bp->vlgrp,
+                                                le16_to_cpu(cqe->fast_path_cqe.
+                                                            vlan_tag), skb);
                        else
 #endif
-                               netif_receive_skb(skb);
+                               napi_gro_receive(&fp->napi, skb);
                } else {
                        DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
                           " - dropping packet!\n");
@@ -1498,15 +1582,23 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                struct sw_rx_bd *rx_buf = NULL;
                struct sk_buff *skb;
                union eth_rx_cqe *cqe;
-               u8 cqe_fp_flags;
+               u8 cqe_fp_flags, cqe_fp_status_flags;
                u16 len, pad;
 
                comp_ring_cons = RCQ_BD(sw_comp_cons);
                bd_prod = RX_BD(bd_prod);
                bd_cons = RX_BD(bd_cons);
 
+               /* Prefetch the page containing the BD descriptor
+                  at producer's index. It will be needed when new skb is
+                  allocated */
+               prefetch((void *)(PAGE_ALIGN((unsigned long)
+                                            (&fp->rx_desc_ring[bd_prod])) -
+                                 PAGE_SIZE + 1));
+
                cqe = &fp->rx_comp_ring[comp_ring_cons];
                cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+               cqe_fp_status_flags = cqe->fast_path_cqe.status_flags;
 
                DP(NETIF_MSG_RX_STATUS, "CQE type %x  err %x  status %x"
                   "  queue %x  vlan %x  len %u\n", CQE_TYPE(cqe_fp_flags),
@@ -1524,6 +1616,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                } else {
                        rx_buf = &fp->rx_buf_ring[bd_cons];
                        skb = rx_buf->skb;
+                       prefetch(skb);
                        len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
                        pad = cqe->fast_path_cqe.placement_offset;
 
@@ -1570,11 +1663,10 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                                }
                        }
 
-                       pci_dma_sync_single_for_device(bp->pdev,
-                                       pci_unmap_addr(rx_buf, mapping),
-                                                      pad + RX_COPY_THRESH,
-                                                      PCI_DMA_FROMDEVICE);
-                       prefetch(skb);
+                       dma_sync_single_for_device(&bp->pdev->dev,
+                                       dma_unmap_addr(rx_buf, mapping),
+                                                  pad + RX_COPY_THRESH,
+                                                  DMA_FROM_DEVICE);
                        prefetch(((char *)(skb)) + 128);
 
                        /* is this an error packet? */
@@ -1613,11 +1705,12 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 
                                skb = new_skb;
 
-                       } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) {
-                               pci_unmap_single(bp->pdev,
-                                       pci_unmap_addr(rx_buf, mapping),
+                       } else
+                       if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
+                               dma_unmap_single(&bp->pdev->dev,
+                                       dma_unmap_addr(rx_buf, mapping),
                                                 bp->rx_buf_size,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                                skb_reserve(skb, pad);
                                skb_put(skb, len);
 
@@ -1633,6 +1726,12 @@ reuse_rx:
 
                        skb->protocol = eth_type_trans(skb, bp->dev);
 
+                       if ((bp->dev->features & NETIF_F_RXHASH) &&
+                           (cqe_fp_status_flags &
+                            ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
+                               skb->rxhash = le32_to_cpu(
+                                   cqe->fast_path_cqe.rss_hash_result);
+
                        skb->ip_summed = CHECKSUM_NONE;
                        if (bp->rx_csum) {
                                if (likely(BNX2X_RX_CSUM_OK(cqe)))
@@ -1643,15 +1742,16 @@ reuse_rx:
                }
 
                skb_record_rx_queue(skb, fp->index);
+
 #ifdef BCM_VLAN
                if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
                    (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
                     PARSING_FLAGS_VLAN))
-                       vlan_hwaccel_receive_skb(skb, bp->vlgrp,
-                               le16_to_cpu(cqe->fast_path_cqe.vlan_tag));
+                       vlan_gro_receive(&fp->napi, bp->vlgrp,
+                               le16_to_cpu(cqe->fast_path_cqe.vlan_tag), skb);
                else
 #endif
-                       netif_receive_skb(skb);
+                       napi_gro_receive(&fp->napi, skb);
 
 
 next_rx:
@@ -1688,7 +1788,6 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
 {
        struct bnx2x_fastpath *fp = fp_cookie;
        struct bnx2x *bp = fp->bp;
-       int index = fp->index;
 
        /* Return here if interrupt is disabled */
        if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
@@ -1697,7 +1796,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
        }
 
        DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB [%d:%d]\n",
-          index, fp->sb_id);
+          fp->index, fp->sb_id);
        bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
 
 #ifdef BNX2X_STOP_ON_ERROR
@@ -1705,12 +1804,12 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
                return IRQ_HANDLED;
 #endif
 
+       /* Handle Rx and Tx according to MSI-X vector */
        prefetch(fp->rx_cons_sb);
        prefetch(fp->tx_cons_sb);
-       prefetch(&fp->status_blk->c_status_block.status_block_index);
        prefetch(&fp->status_blk->u_status_block.status_block_index);
-
-       napi_schedule(&bnx2x_fp(bp, index, napi));
+       prefetch(&fp->status_blk->c_status_block.status_block_index);
+       napi_schedule(&bnx2x_fp(bp, fp->index, napi));
 
        return IRQ_HANDLED;
 }
@@ -1720,6 +1819,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
        struct bnx2x *bp = netdev_priv(dev_instance);
        u16 status = bnx2x_ack_int(bp);
        u16 mask;
+       int i;
 
        /* Return here if interrupt is shared and it's not for us */
        if (unlikely(status == 0)) {
@@ -1739,20 +1839,37 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
                return IRQ_HANDLED;
 #endif
 
-       mask = 0x2 << bp->fp[0].sb_id;
-       if (status & mask) {
-               struct bnx2x_fastpath *fp = &bp->fp[0];
+       for (i = 0; i < BNX2X_NUM_QUEUES(bp); i++) {
+               struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               mask = 0x2 << fp->sb_id;
+               if (status & mask) {
+                       /* Handle Rx and Tx according to SB id */
+                       prefetch(fp->rx_cons_sb);
+                       prefetch(&fp->status_blk->u_status_block.
+                                               status_block_index);
+                       prefetch(fp->tx_cons_sb);
+                       prefetch(&fp->status_blk->c_status_block.
+                                               status_block_index);
+                       napi_schedule(&bnx2x_fp(bp, fp->index, napi));
+                       status &= ~mask;
+               }
+       }
 
-               prefetch(fp->rx_cons_sb);
-               prefetch(fp->tx_cons_sb);
-               prefetch(&fp->status_blk->c_status_block.status_block_index);
-               prefetch(&fp->status_blk->u_status_block.status_block_index);
+#ifdef BCM_CNIC
+       mask = 0x2 << CNIC_SB_ID(bp);
+       if (status & (mask | 0x1)) {
+               struct cnic_ops *c_ops = NULL;
 
-               napi_schedule(&bnx2x_fp(bp, 0, napi));
+               rcu_read_lock();
+               c_ops = rcu_dereference(bp->cnic_ops);
+               if (c_ops)
+                       c_ops->cnic_handler(bp->cnic_data, NULL);
+               rcu_read_unlock();
 
                status &= ~mask;
        }
-
+#endif
 
        if (unlikely(status & 0x1)) {
                queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
@@ -1762,8 +1879,8 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
                        return IRQ_HANDLED;
        }
 
-       if (status)
-               DP(NETIF_MSG_INTR, "got an unknown interrupt! (status %u)\n",
+       if (unlikely(status))
+               DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
                   status);
 
        return IRQ_HANDLED;
@@ -1831,6 +1948,8 @@ static int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
        int func = BP_FUNC(bp);
        u32 hw_lock_control_reg;
 
+       DP(NETIF_MSG_HW, "Releasing a lock on resource %d\n", resource);
+
        /* Validating that the resource is within range */
        if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
                DP(NETIF_MSG_HW,
@@ -2077,34 +2196,52 @@ static void bnx2x_calc_fc_adv(struct bnx2x *bp)
 
 static void bnx2x_link_report(struct bnx2x *bp)
 {
+       if (bp->flags & MF_FUNC_DIS) {
+               netif_carrier_off(bp->dev);
+               netdev_err(bp->dev, "NIC Link is Down\n");
+               return;
+       }
+
        if (bp->link_vars.link_up) {
+               u16 line_speed;
+
                if (bp->state == BNX2X_STATE_OPEN)
                        netif_carrier_on(bp->dev);
-               printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name);
+               netdev_info(bp->dev, "NIC Link is Up, ");
 
-               printk("%d Mbps ", bp->link_vars.line_speed);
+               line_speed = bp->link_vars.line_speed;
+               if (IS_E1HMF(bp)) {
+                       u16 vn_max_rate;
+
+                       vn_max_rate =
+                               ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
+                                FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
+                       if (vn_max_rate < line_speed)
+                               line_speed = vn_max_rate;
+               }
+               pr_cont("%d Mbps ", line_speed);
 
                if (bp->link_vars.duplex == DUPLEX_FULL)
-                       printk("full duplex");
+                       pr_cont("full duplex");
                else
-                       printk("half duplex");
+                       pr_cont("half duplex");
 
                if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) {
                        if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) {
-                               printk(", receive ");
+                               pr_cont(", receive ");
                                if (bp->link_vars.flow_ctrl &
                                    BNX2X_FLOW_CTRL_TX)
-                                       printk("& transmit ");
+                                       pr_cont("& transmit ");
                        } else {
-                               printk(", transmit ");
+                               pr_cont(", transmit ");
                        }
-                       printk("flow control ON");
+                       pr_cont("flow control ON");
                }
-               printk("\n");
+               pr_cont("\n");
 
        } else { /* link_down */
                netif_carrier_off(bp->dev);
-               printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
+               netdev_err(bp->dev, "NIC Link is Down\n");
        }
 }
 
@@ -2116,9 +2253,7 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
                /* Initialize link parameters structure variables */
                /* It is recommended to turn off RX FC for jumbo frames
                   for better performance */
-               if (IS_E1HMF(bp))
-                       bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
-               else if (bp->dev->mtu > 5000)
+               if (bp->dev->mtu > 5000)
                        bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX;
                else
                        bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
@@ -2169,11 +2304,14 @@ static void bnx2x__link_reset(struct bnx2x *bp)
 
 static u8 bnx2x_link_test(struct bnx2x *bp)
 {
-       u8 rc;
+       u8 rc = 0;
 
-       bnx2x_acquire_phy_lock(bp);
-       rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
-       bnx2x_release_phy_lock(bp);
+       if (!BP_NOMCP(bp)) {
+               bnx2x_acquire_phy_lock(bp);
+               rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
+               bnx2x_release_phy_lock(bp);
+       } else
+               BNX2X_ERR("Bootcode is missing - can not test link\n");
 
        return rc;
 }
@@ -2213,6 +2351,52 @@ static void bnx2x_init_port_minmax(struct bnx2x *bp)
        bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4;
 }
 
+/* Calculates the sum of vn_min_rates.
+   It's needed for further normalizing of the min_rates.
+   Returns:
+     sum of vn_min_rates.
+       or
+     0 - if all the min_rates are 0.
+     In the later case fainess algorithm should be deactivated.
+     If not all min_rates are zero then those that are zeroes will be set to 1.
+ */
+static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
+{
+       int all_zero = 1;
+       int port = BP_PORT(bp);
+       int vn;
+
+       bp->vn_weight_sum = 0;
+       for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+               int func = 2*vn + port;
+               u32 vn_cfg = SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
+               u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
+                                  FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
+
+               /* Skip hidden vns */
+               if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE)
+                       continue;
+
+               /* If min rate is zero - set it to 1 */
+               if (!vn_min_rate)
+                       vn_min_rate = DEF_MIN_RATE;
+               else
+                       all_zero = 0;
+
+               bp->vn_weight_sum += vn_min_rate;
+       }
+
+       /* ... only if all min rates are zeros - disable fairness */
+       if (all_zero) {
+               bp->cmng.flags.cmng_enables &=
+                                       ~CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
+               DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
+                  "  fairness will be disabled\n");
+       } else
+               bp->cmng.flags.cmng_enables |=
+                                       CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
+}
+
 static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
 {
        struct rate_shaping_vars_per_vn m_rs_vn;
@@ -2229,17 +2413,14 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
        } else {
                vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
                                FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
-               /* If fairness is enabled (not all min rates are zeroes) and
-                  if current min rate is zero - set it to 1.
-                  This is a requirement of the algorithm. */
-               if (bp->vn_weight_sum && (vn_min_rate == 0))
+               /* If min rate is zero - set it to 1 */
+               if (!vn_min_rate)
                        vn_min_rate = DEF_MIN_RATE;
                vn_max_rate = ((vn_cfg & FUNC_MF_CFG_MAX_BW_MASK) >>
                                FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
        }
-
        DP(NETIF_MSG_IFUP,
-          "func %d: vn_min_rate=%d  vn_max_rate=%d  vn_weight_sum=%d\n",
+          "func %d: vn_min_rate %d  vn_max_rate %d  vn_weight_sum %d\n",
           func, vn_min_rate, vn_max_rate, bp->vn_weight_sum);
 
        memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn));
@@ -2259,10 +2440,10 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
                   T_FAIR_COEF / (8 * vn_weight_sum) will always be greater
                   than zero */
                m_fair_vn.vn_credit_delta =
-                       max((u32)(vn_min_rate * (T_FAIR_COEF /
-                                                (8 * bp->vn_weight_sum))),
-                           (u32)(bp->cmng.fair_vars.fair_threshold * 2));
-               DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta=%d\n",
+                       max_t(u32, (vn_min_rate * (T_FAIR_COEF /
+                                                  (8 * bp->vn_weight_sum))),
+                             (bp->cmng.fair_vars.fair_threshold * 2));
+               DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n",
                   m_fair_vn.vn_credit_delta);
        }
 
@@ -2282,6 +2463,7 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
 /* This function is called upon link interrupt */
 static void bnx2x_link_attn(struct bnx2x *bp)
 {
+       u32 prev_link_status = bp->link_vars.link_status;
        /* Make sure that we are synced with the current statistics */
        bnx2x_stats_handle(bp, STATS_EVENT_STOP);
 
@@ -2290,7 +2472,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
        if (bp->link_vars.link_up) {
 
                /* dropless flow control */
-               if (CHIP_IS_E1H(bp)) {
+               if (CHIP_IS_E1H(bp) && bp->dropless_fc) {
                        int port = BP_PORT(bp);
                        u32 pause_enabled = 0;
 
@@ -2298,7 +2480,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
                                pause_enabled = 1;
 
                        REG_WR(bp, BAR_USTRORM_INTMEM +
-                              USTORM_PAUSE_ENABLED_OFFSET(port),
+                              USTORM_ETH_PAUSE_ENABLED_OFFSET(port),
                               pause_enabled);
                }
 
@@ -2310,27 +2492,25 @@ static void bnx2x_link_attn(struct bnx2x *bp)
                        memset(&(pstats->mac_stx[0]), 0,
                               sizeof(struct mac_stx));
                }
-               if ((bp->state == BNX2X_STATE_OPEN) ||
-                   (bp->state == BNX2X_STATE_DISABLED))
+               if (bp->state == BNX2X_STATE_OPEN)
                        bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
        }
 
-       /* indicate link status */
-       bnx2x_link_report(bp);
+       /* indicate link status only if link status actually changed */
+       if (prev_link_status != bp->link_vars.link_status)
+               bnx2x_link_report(bp);
 
        if (IS_E1HMF(bp)) {
                int port = BP_PORT(bp);
                int func;
                int vn;
 
+               /* Set the attention towards other drivers on the same port */
                for (vn = VN_0; vn < E1HVN_MAX; vn++) {
                        if (vn == BP_E1HVN(bp))
                                continue;
 
                        func = ((vn << 1) | port);
-
-                       /* Set the attention towards other drivers
-                          on the same port */
                        REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
                               (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
                }
@@ -2356,7 +2536,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
 
 static void bnx2x__link_status_update(struct bnx2x *bp)
 {
-       if (bp->state != BNX2X_STATE_OPEN)
+       if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS))
                return;
 
        bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
@@ -2366,6 +2546,8 @@ static void bnx2x__link_status_update(struct bnx2x *bp)
        else
                bnx2x_stats_handle(bp, STATS_EVENT_STOP);
 
+       bnx2x_calc_vn_weight_sum(bp);
+
        /* indicate link status */
        bnx2x_link_report(bp);
 }
@@ -2394,64 +2576,218 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
  * General service functions
  */
 
-/* the slow path queue is odd since completions arrive on the fastpath ring */
-static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
-                        u32 data_hi, u32 data_lo, int common)
+/* send the MCP a request, block until there is a reply */
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
 {
        int func = BP_FUNC(bp);
+       u32 seq = ++bp->fw_seq;
+       u32 rc = 0;
+       u32 cnt = 1;
+       u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
 
-       DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
-          "SPQE (%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);
+       mutex_lock(&bp->fw_mb_mutex);
+       SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq));
+       DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
 
-#ifdef BNX2X_STOP_ON_ERROR
-       if (unlikely(bp->panic))
-               return -EIO;
-#endif
+       do {
+               /* let the FW do it's magic ... */
+               msleep(delay);
 
-       spin_lock_bh(&bp->spq_lock);
+               rc = SHMEM_RD(bp, func_mb[func].fw_mb_header);
 
-       if (!bp->spq_left) {
-               BNX2X_ERR("BUG! SPQ ring full!\n");
-               spin_unlock_bh(&bp->spq_lock);
-               bnx2x_panic();
-               return -EBUSY;
-       }
+               /* Give the FW up to 5 second (500*10ms) */
+       } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 500));
 
-       /* 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) |
-                                    HW_CID(bp, cid)));
-       bp->spq_prod_bd->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
-       if (common)
-               bp->spq_prod_bd->hdr.type |=
-                       cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
+       DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n",
+          cnt*delay, rc, seq);
 
-       bp->spq_prod_bd->data.mac_config_addr.hi = cpu_to_le32(data_hi);
-       bp->spq_prod_bd->data.mac_config_addr.lo = cpu_to_le32(data_lo);
+       /* is this a reply to our command? */
+       if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK))
+               rc &= FW_MSG_CODE_MASK;
+       else {
+               /* FW BUG! */
+               BNX2X_ERR("FW failed to respond!\n");
+               bnx2x_fw_dump(bp);
+               rc = 0;
+       }
+       mutex_unlock(&bp->fw_mb_mutex);
 
-       bp->spq_left--;
+       return rc;
+}
 
-       if (bp->spq_prod_bd == bp->spq_last_bd) {
-               bp->spq_prod_bd = bp->spq;
-               bp->spq_prod_idx = 0;
-               DP(NETIF_MSG_TIMER, "end of spq\n");
+static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
+static void bnx2x_set_rx_mode(struct net_device *dev);
 
-       } else {
-               bp->spq_prod_bd++;
-               bp->spq_prod_idx++;
-       }
+static void bnx2x_e1h_disable(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
 
-       /* Make sure that BD data is updated before writing the producer */
-       wmb();
+       netif_tx_disable(bp->dev);
 
-       REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
-              bp->spq_prod_idx);
+       REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
+
+       netif_carrier_off(bp->dev);
+}
+
+static void bnx2x_e1h_enable(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+
+       REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
+
+       /* Tx queue should be only reenabled */
+       netif_tx_wake_all_queues(bp->dev);
+
+       /*
+        * Should not call netif_carrier_on since it will be called if the link
+        * is up when checking for link state
+        */
+}
+
+static void bnx2x_update_min_max(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       int vn, i;
+
+       /* Init rate shaping and fairness contexts */
+       bnx2x_init_port_minmax(bp);
+
+       bnx2x_calc_vn_weight_sum(bp);
+
+       for (vn = VN_0; vn < E1HVN_MAX; vn++)
+               bnx2x_init_vn_minmax(bp, 2*vn + port);
+
+       if (bp->port.pmf) {
+               int func;
+
+               /* Set the attention towards other drivers on the same port */
+               for (vn = VN_0; vn < E1HVN_MAX; vn++) {
+                       if (vn == BP_E1HVN(bp))
+                               continue;
+
+                       func = ((vn << 1) | port);
+                       REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
+                              (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
+               }
+
+               /* Store it to internal memory */
+               for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
+                       REG_WR(bp, BAR_XSTRORM_INTMEM +
+                              XSTORM_CMNG_PER_PORT_VARS_OFFSET(port) + i*4,
+                              ((u32 *)(&bp->cmng))[i]);
+       }
+}
+
+static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
+{
+       DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
+
+       if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) {
+
+               /*
+                * This is the only place besides the function initialization
+                * where the bp->flags can change so it is done without any
+                * locks
+                */
+               if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
+                       DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n");
+                       bp->flags |= MF_FUNC_DIS;
+
+                       bnx2x_e1h_disable(bp);
+               } else {
+                       DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n");
+                       bp->flags &= ~MF_FUNC_DIS;
+
+                       bnx2x_e1h_enable(bp);
+               }
+               dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF;
+       }
+       if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) {
+
+               bnx2x_update_min_max(bp);
+               dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION;
+       }
+
+       /* Report results to MCP */
+       if (dcc_event)
+               bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE);
+       else
+               bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK);
+}
+
+/* must be called under the spq lock */
+static inline struct eth_spe *bnx2x_sp_get_next(struct bnx2x *bp)
+{
+       struct eth_spe *next_spe = bp->spq_prod_bd;
+
+       if (bp->spq_prod_bd == bp->spq_last_bd) {
+               bp->spq_prod_bd = bp->spq;
+               bp->spq_prod_idx = 0;
+               DP(NETIF_MSG_TIMER, "end of spq\n");
+       } else {
+               bp->spq_prod_bd++;
+               bp->spq_prod_idx++;
+       }
+       return next_spe;
+}
+
+/* must be called under the spq lock */
+static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
+{
+       int func = BP_FUNC(bp);
+
+       /* Make sure that BD data is updated before writing the producer */
+       wmb();
 
+       REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
+              bp->spq_prod_idx);
        mmiowb();
+}
+
+/* the slow path queue is odd since completions arrive on the fastpath ring */
+static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+                        u32 data_hi, u32 data_lo, int common)
+{
+       struct eth_spe *spe;
+
+#ifdef BNX2X_STOP_ON_ERROR
+       if (unlikely(bp->panic))
+               return -EIO;
+#endif
+
+       spin_lock_bh(&bp->spq_lock);
+
+       if (!bp->spq_left) {
+               BNX2X_ERR("BUG! SPQ ring full!\n");
+               spin_unlock_bh(&bp->spq_lock);
+               bnx2x_panic();
+               return -EBUSY;
+       }
+
+       spe = bnx2x_sp_get_next(bp);
+
+       /* CID needs port number to be encoded int it */
+       spe->hdr.conn_and_cmd_data =
+                       cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
+                                   HW_CID(bp, cid));
+       spe->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
+       if (common)
+               spe->hdr.type |=
+                       cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
+
+       spe->data.mac_config_addr.hi = cpu_to_le32(data_hi);
+       spe->data.mac_config_addr.lo = cpu_to_le32(data_lo);
+
+       bp->spq_left--;
+
+       DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
+          "SPQE[%x] (%x:%x)  command %d  hw_cid %x  data (%x:%x)  left %x\n",
+          bp->spq_prod_idx, (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);
 
+       bnx2x_sp_prod_update(bp);
        spin_unlock_bh(&bp->spq_lock);
        return 0;
 }
@@ -2459,12 +2795,11 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 /* acquire split MCP access lock register */
 static int bnx2x_acquire_alr(struct bnx2x *bp)
 {
-       u32 i, j, val;
+       u32 j, val;
        int rc = 0;
 
        might_sleep();
-       i = 100;
-       for (j = 0; j < i*10; j++) {
+       for (j = 0; j < 1000; j++) {
                val = (1UL << 31);
                REG_WR(bp, GRCBASE_MCP + 0x9c, val);
                val = REG_RD(bp, GRCBASE_MCP + 0x9c);
@@ -2484,9 +2819,7 @@ static int bnx2x_acquire_alr(struct bnx2x *bp)
 /* release split MCP access lock register */
 static void bnx2x_release_alr(struct bnx2x *bp)
 {
-       u32 val = 0;
-
-       REG_WR(bp, GRCBASE_MCP + 0x9c, val);
+       REG_WR(bp, GRCBASE_MCP + 0x9c, 0);
 }
 
 static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
@@ -2542,7 +2875,7 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 
        DP(NETIF_MSG_HW, "aeu_mask %x  newly asserted %x\n",
           aeu_mask, asserted);
-       aeu_mask &= ~(asserted & 0xff);
+       aeu_mask &= ~(asserted & 0x3ff);
        DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
 
        REG_WR(bp, aeu_addr, aeu_mask);
@@ -2629,11 +2962,11 @@ static inline void bnx2x_fan_failure(struct bnx2x *bp)
                 bp->link_params.ext_phy_config);
 
        /* log the failure */
-       printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused"
+       netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
               " the driver to shutdown the card to prevent permanent"
-              " damage.  Please contact Dell Support for assistance\n",
-              bp->dev->name);
+              " damage.  Please contact OEM Support for assistance\n");
 }
+
 static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
 {
        int port = BP_PORT(bp);
@@ -2693,7 +3026,7 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
                REG_WR(bp, reg_offset, val);
 
                BNX2X_ERR("FATAL HW block attention set0 0x%x\n",
-                         (attn & HW_INTERRUT_ASSERT_SET_0));
+                         (u32)(attn & HW_INTERRUT_ASSERT_SET_0));
                bnx2x_panic();
        }
 }
@@ -2724,7 +3057,7 @@ static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn)
                REG_WR(bp, reg_offset, val);
 
                BNX2X_ERR("FATAL HW block attention set1 0x%x\n",
-                         (attn & HW_INTERRUT_ASSERT_SET_1));
+                         (u32)(attn & HW_INTERRUT_ASSERT_SET_1));
                bnx2x_panic();
        }
 }
@@ -2764,7 +3097,7 @@ static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn)
                REG_WR(bp, reg_offset, val);
 
                BNX2X_ERR("FATAL HW block attention set2 0x%x\n",
-                         (attn & HW_INTERRUT_ASSERT_SET_2));
+                         (u32)(attn & HW_INTERRUT_ASSERT_SET_2));
                bnx2x_panic();
        }
 }
@@ -2779,9 +3112,14 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
                        int func = BP_FUNC(bp);
 
                        REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
+                       bp->mf_config = SHMEM_RD(bp,
+                                          mf_cfg.func_mf_config[func].config);
+                       val = SHMEM_RD(bp, func_mb[func].drv_status);
+                       if (val & DRV_STATUS_DCC_EVENT_MASK)
+                               bnx2x_dcc_event(bp,
+                                           (val & DRV_STATUS_DCC_EVENT_MASK));
                        bnx2x__link_status_update(bp);
-                       if (SHMEM_RD(bp, func_mb[func].drv_status) &
-                                                       DRV_STATUS_PMF)
+                       if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
                                bnx2x_pmf_update(bp);
 
                } else if (attn & BNX2X_MC_ASSERT_BITS) {
@@ -2819,10 +3157,311 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
        }
 }
 
-static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
+static int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
+
+
+#define BNX2X_MISC_GEN_REG      MISC_REG_GENERIC_POR_1
+#define LOAD_COUNTER_BITS      16 /* Number of bits for load counter */
+#define LOAD_COUNTER_MASK      (((u32)0x1 << LOAD_COUNTER_BITS) - 1)
+#define RESET_DONE_FLAG_MASK   (~LOAD_COUNTER_MASK)
+#define RESET_DONE_FLAG_SHIFT  LOAD_COUNTER_BITS
+#define CHIP_PARITY_SUPPORTED(bp)   (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp))
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_set_reset_done(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       val &= ~(1 << RESET_DONE_FLAG_SHIFT);
+       REG_WR(bp, BNX2X_MISC_GEN_REG, val);
+       barrier();
+       mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_set_reset_in_progress(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       val |= (1 << 16);
+       REG_WR(bp, BNX2X_MISC_GEN_REG, val);
+       barrier();
+       mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline bool bnx2x_reset_is_done(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val);
+       return (val & RESET_DONE_FLAG_MASK) ? false : true;
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_inc_load_cnt(struct bnx2x *bp)
+{
+       u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+
+       DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
+
+       val1 = ((val & LOAD_COUNTER_MASK) + 1) & LOAD_COUNTER_MASK;
+       REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
+       barrier();
+       mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline u32 bnx2x_dec_load_cnt(struct bnx2x *bp)
+{
+       u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+
+       DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
+
+       val1 = ((val & LOAD_COUNTER_MASK) - 1) & LOAD_COUNTER_MASK;
+       REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
+       barrier();
+       mmiowb();
+
+       return val1;
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline u32 bnx2x_get_load_cnt(struct bnx2x *bp)
+{
+       return REG_RD(bp, BNX2X_MISC_GEN_REG) & LOAD_COUNTER_MASK;
+}
+
+static inline void bnx2x_clear_load_cnt(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       REG_WR(bp, BNX2X_MISC_GEN_REG, val & (~LOAD_COUNTER_MASK));
+}
+
+static inline void _print_next_block(int idx, const char *blk)
+{
+       if (idx)
+               pr_cont(", ");
+       pr_cont("%s", blk);
+}
+
+static inline int bnx2x_print_blocks_with_parity0(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
+                               _print_next_block(par_num++, "BRB");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
+                               _print_next_block(par_num++, "PARSER");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "TSDM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
+                               _print_next_block(par_num++, "SEARCHER");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "TSEMI");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity1(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
+                               _print_next_block(par_num++, "PBCLIENT");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR:
+                               _print_next_block(par_num++, "QM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "XSDM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "XSEMI");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR:
+                               _print_next_block(par_num++, "DOORBELLQ");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR:
+                               _print_next_block(par_num++, "VAUX PCI CORE");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR:
+                               _print_next_block(par_num++, "DEBUG");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "USDM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "USEMI");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR:
+                               _print_next_block(par_num++, "UPB");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "CSDM");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity2(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "CSEMI");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
+                               _print_next_block(par_num++, "PXP");
+                               break;
+                       case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
+                               _print_next_block(par_num++,
+                                       "PXPPCICLOCKCLIENT");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
+                               _print_next_block(par_num++, "CFC");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
+                               _print_next_block(par_num++, "CDU");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
+                               _print_next_block(par_num++, "IGU");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
+                               _print_next_block(par_num++, "MISC");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity3(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY:
+                               _print_next_block(par_num++, "MCP ROM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
+                               _print_next_block(par_num++, "MCP UMP RX");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
+                               _print_next_block(par_num++, "MCP UMP TX");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
+                               _print_next_block(par_num++, "MCP SCPAD");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline bool bnx2x_parity_attn(struct bnx2x *bp, u32 sig0, u32 sig1,
+                                    u32 sig2, u32 sig3)
+{
+       if ((sig0 & HW_PRTY_ASSERT_SET_0) || (sig1 & HW_PRTY_ASSERT_SET_1) ||
+           (sig2 & HW_PRTY_ASSERT_SET_2) || (sig3 & HW_PRTY_ASSERT_SET_3)) {
+               int par_num = 0;
+               DP(NETIF_MSG_HW, "Was parity error: HW block parity attention: "
+                       "[0]:0x%08x [1]:0x%08x "
+                       "[2]:0x%08x [3]:0x%08x\n",
+                         sig0 & HW_PRTY_ASSERT_SET_0,
+                         sig1 & HW_PRTY_ASSERT_SET_1,
+                         sig2 & HW_PRTY_ASSERT_SET_2,
+                         sig3 & HW_PRTY_ASSERT_SET_3);
+               printk(KERN_ERR"%s: Parity errors detected in blocks: ",
+                      bp->dev->name);
+               par_num = bnx2x_print_blocks_with_parity0(
+                       sig0 & HW_PRTY_ASSERT_SET_0, par_num);
+               par_num = bnx2x_print_blocks_with_parity1(
+                       sig1 & HW_PRTY_ASSERT_SET_1, par_num);
+               par_num = bnx2x_print_blocks_with_parity2(
+                       sig2 & HW_PRTY_ASSERT_SET_2, par_num);
+               par_num = bnx2x_print_blocks_with_parity3(
+                       sig3 & HW_PRTY_ASSERT_SET_3, par_num);
+               printk("\n");
+               return true;
+       } else
+               return false;
+}
+
+static bool bnx2x_chk_parity_attn(struct bnx2x *bp)
 {
        struct attn_route attn;
-       struct attn_route group_mask;
+       int port = BP_PORT(bp);
+
+       attn.sig[0] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 +
+                            port*4);
+       attn.sig[1] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 +
+                            port*4);
+       attn.sig[2] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 +
+                            port*4);
+       attn.sig[3] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
+                            port*4);
+
+       return bnx2x_parity_attn(bp, attn.sig[0], attn.sig[1], attn.sig[2],
+                                       attn.sig[3]);
+}
+
+static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+{
+       struct attn_route attn, *group_mask;
        int port = BP_PORT(bp);
        int index;
        u32 reg_addr;
@@ -2833,6 +3472,19 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
           try to handle this event */
        bnx2x_acquire_alr(bp);
 
+       if (bnx2x_chk_parity_attn(bp)) {
+               bp->recovery_state = BNX2X_RECOVERY_INIT;
+               bnx2x_set_reset_in_progress(bp);
+               schedule_delayed_work(&bp->reset_task, 0);
+               /* Disable HW interrupts */
+               bnx2x_int_disable(bp);
+               bnx2x_release_alr(bp);
+               /* In case of parity errors don't handle attentions so that
+                * other function would "see" parity errors.
+                */
+               return;
+       }
+
        attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
        attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
        attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
@@ -2842,28 +3494,20 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
 
        for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
                if (deasserted & (1 << index)) {
-                       group_mask = bp->attn_group[index];
+                       group_mask = &bp->attn_group[index];
 
                        DP(NETIF_MSG_HW, "group[%d]: %08x %08x %08x %08x\n",
-                          index, group_mask.sig[0], group_mask.sig[1],
-                          group_mask.sig[2], group_mask.sig[3]);
+                          index, group_mask->sig[0], group_mask->sig[1],
+                          group_mask->sig[2], group_mask->sig[3]);
 
                        bnx2x_attn_int_deasserted3(bp,
-                                       attn.sig[3] & group_mask.sig[3]);
+                                       attn.sig[3] & group_mask->sig[3]);
                        bnx2x_attn_int_deasserted1(bp,
-                                       attn.sig[1] & group_mask.sig[1]);
+                                       attn.sig[1] & group_mask->sig[1]);
                        bnx2x_attn_int_deasserted2(bp,
-                                       attn.sig[2] & group_mask.sig[2]);
+                                       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_PRTY_ASSERT_SET_0) ||
-                           (attn.sig[1] & group_mask.sig[1] &
-                                               HW_PRTY_ASSERT_SET_1) ||
-                           (attn.sig[2] & group_mask.sig[2] &
-                                               HW_PRTY_ASSERT_SET_2))
-                               BNX2X_ERR("FATAL HW block parity attention\n");
+                                       attn.sig[0] & group_mask->sig[0]);
                }
        }
 
@@ -2887,7 +3531,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
 
        DP(NETIF_MSG_HW, "aeu_mask %x  newly deasserted %x\n",
           aeu_mask, deasserted);
-       aeu_mask |= (deasserted & 0xff);
+       aeu_mask |= (deasserted & 0x3ff);
        DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
 
        REG_WR(bp, reg_addr, aeu_mask);
@@ -2931,7 +3575,6 @@ static void bnx2x_sp_task(struct work_struct *work)
        struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
        u16 status;
 
-
        /* 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");
@@ -2942,11 +3585,23 @@ static void bnx2x_sp_task(struct work_struct *work)
 /*     if (status == 0)                                     */
 /*             BNX2X_ERR("spurious slowpath interrupt!\n"); */
 
-       DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status);
+       DP(NETIF_MSG_INTR, "got a slowpath interrupt (status 0x%x)\n", status);
 
        /* HW attentions */
-       if (status & 0x1)
+       if (status & 0x1) {
                bnx2x_attn_int(bp);
+               status &= ~0x1;
+       }
+
+       /* CStorm events: STAT_QUERY */
+       if (status & 0x2) {
+               DP(BNX2X_MSG_SP, "CStorm events: STAT_QUERY\n");
+               status &= ~0x2;
+       }
+
+       if (unlikely(status))
+               DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
+                  status);
 
        bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, le16_to_cpu(bp->def_att_idx),
                     IGU_INT_NOP, 1);
@@ -2958,7 +3613,6 @@ 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)
@@ -2979,6 +3633,17 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
                return IRQ_HANDLED;
 #endif
 
+#ifdef BCM_CNIC
+       {
+               struct cnic_ops *c_ops;
+
+               rcu_read_lock();
+               c_ops = rcu_dereference(bp->cnic_ops);
+               if (c_ops)
+                       c_ops->cnic_handler(bp->cnic_data, NULL);
+               rcu_read_unlock();
+       }
+#endif
        queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
 
        return IRQ_HANDLED;
@@ -3140,57 +3805,10 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
        }
 }
 
-static void bnx2x_stats_init(struct bnx2x *bp)
+static void bnx2x_hw_stats_post(struct bnx2x *bp)
 {
-       int port = BP_PORT(bp);
-       int i;
-
-       bp->stats_pending = 0;
-       bp->executer_idx = 0;
-       bp->stats_counter = 0;
-
-       /* port stats */
-       if (!BP_NOMCP(bp))
-               bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx);
-       else
-               bp->port.port_stx = 0;
-       DP(BNX2X_MSG_STATS, "port_stx 0x%x\n", bp->port.port_stx);
-
-       memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats));
-       bp->port.old_nig_stats.brb_discard =
-                       REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38);
-       bp->port.old_nig_stats.brb_truncate =
-                       REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38);
-       REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50,
-                   &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2);
-       REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50,
-                   &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2);
-
-       /* function stats */
-       for_each_queue(bp, i) {
-               struct bnx2x_fastpath *fp = &bp->fp[i];
-
-               memset(&fp->old_tclient, 0,
-                      sizeof(struct tstorm_per_client_stats));
-               memset(&fp->old_uclient, 0,
-                      sizeof(struct ustorm_per_client_stats));
-               memset(&fp->old_xclient, 0,
-                      sizeof(struct xstorm_per_client_stats));
-               memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
-       }
-
-       memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
-       memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats));
-
-       bp->stats_state = STATS_STATE_DISABLED;
-       if (IS_E1HMF(bp) && bp->port.pmf && bp->port.port_stx)
-               bnx2x_stats_handle(bp, STATS_EVENT_PMF);
-}
-
-static void bnx2x_hw_stats_post(struct bnx2x *bp)
-{
-       struct dmae_command *dmae = &bp->stats_dmae;
-       u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+       struct dmae_command *dmae = &bp->stats_dmae;
+       u32 *stats_comp = bnx2x_sp(bp, stats_comp);
 
        *stats_comp = DMAE_COMP_VAL;
        if (CHIP_REV_IS_SLOW(bp))
@@ -3698,7 +4316,6 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
                u32 lo;
                u32 hi;
        } diff;
-       u32 nig_timer_max;
 
        if (bp->link_vars.mac_type == MAC_TYPE_BMAC)
                bnx2x_bmac_stats_update(bp);
@@ -3729,10 +4346,14 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
 
        pstats->host_port_stats_start = ++pstats->host_port_stats_end;
 
-       nig_timer_max = SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
-       if (nig_timer_max != estats->nig_timer_max) {
-               estats->nig_timer_max = nig_timer_max;
-               BNX2X_ERR("NIG timer max (%u)\n", estats->nig_timer_max);
+       if (!BP_NOMCP(bp)) {
+               u32 nig_timer_max =
+                       SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
+               if (nig_timer_max != estats->nig_timer_max) {
+                       estats->nig_timer_max = nig_timer_max;
+                       BNX2X_ERR("NIG timer max (%u)\n",
+                                 estats->nig_timer_max);
+               }
        }
 
        return 0;
@@ -3747,7 +4368,8 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
        struct bnx2x_eth_stats *estats = &bp->eth_stats;
        int i;
 
-       memset(&(fstats->total_bytes_received_hi), 0,
+       memcpy(&(fstats->total_bytes_received_hi),
+              &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
               sizeof(struct host_func_stats) - 2*sizeof(u32));
        estats->error_bytes_received_hi = 0;
        estats->error_bytes_received_lo = 0;
@@ -3775,31 +4397,59 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
                if ((u16)(le16_to_cpu(xclient->stats_counter) + 1) !=
                                                        bp->stats_counter) {
                        DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
-                          "  xstorm counter (%d) != stats_counter (%d)\n",
+                          "  xstorm counter (0x%x) != stats_counter (0x%x)\n",
                           i, xclient->stats_counter, bp->stats_counter);
                        return -1;
                }
                if ((u16)(le16_to_cpu(tclient->stats_counter) + 1) !=
                                                        bp->stats_counter) {
                        DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
-                          "  tstorm counter (%d) != stats_counter (%d)\n",
+                          "  tstorm counter (0x%x) != stats_counter (0x%x)\n",
                           i, tclient->stats_counter, bp->stats_counter);
                        return -2;
                }
                if ((u16)(le16_to_cpu(uclient->stats_counter) + 1) !=
                                                        bp->stats_counter) {
                        DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
-                          "  ustorm counter (%d) != stats_counter (%d)\n",
+                          "  ustorm counter (0x%x) != stats_counter (0x%x)\n",
                           i, uclient->stats_counter, bp->stats_counter);
                        return -4;
                }
 
                qstats->total_bytes_received_hi =
-               qstats->valid_bytes_received_hi =
-                               le32_to_cpu(tclient->total_rcv_bytes.hi);
+                       le32_to_cpu(tclient->rcv_broadcast_bytes.hi);
                qstats->total_bytes_received_lo =
+                       le32_to_cpu(tclient->rcv_broadcast_bytes.lo);
+
+               ADD_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(tclient->rcv_multicast_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(tclient->rcv_multicast_bytes.lo));
+
+               ADD_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(tclient->rcv_unicast_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(tclient->rcv_unicast_bytes.lo));
+
+               SUB_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(uclient->bcast_no_buff_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(uclient->bcast_no_buff_bytes.lo));
+
+               SUB_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(uclient->mcast_no_buff_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(uclient->mcast_no_buff_bytes.lo));
+
+               SUB_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(uclient->ucast_no_buff_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(uclient->ucast_no_buff_bytes.lo));
+
+               qstats->valid_bytes_received_hi =
+                                       qstats->total_bytes_received_hi;
                qstats->valid_bytes_received_lo =
-                               le32_to_cpu(tclient->total_rcv_bytes.lo);
+                                       qstats->total_bytes_received_lo;
 
                qstats->error_bytes_received_hi =
                                le32_to_cpu(tclient->rcv_error_bytes.hi);
@@ -3832,9 +4482,19 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
                UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard);
 
                qstats->total_bytes_transmitted_hi =
-                               le32_to_cpu(xclient->total_sent_bytes.hi);
+                               le32_to_cpu(xclient->unicast_bytes_sent.hi);
                qstats->total_bytes_transmitted_lo =
-                               le32_to_cpu(xclient->total_sent_bytes.lo);
+                               le32_to_cpu(xclient->unicast_bytes_sent.lo);
+
+               ADD_64(qstats->total_bytes_transmitted_hi,
+                      le32_to_cpu(xclient->multicast_bytes_sent.hi),
+                      qstats->total_bytes_transmitted_lo,
+                      le32_to_cpu(xclient->multicast_bytes_sent.lo));
+
+               ADD_64(qstats->total_bytes_transmitted_hi,
+                      le32_to_cpu(xclient->broadcast_bytes_sent.hi),
+                      qstats->total_bytes_transmitted_lo,
+                      le32_to_cpu(xclient->broadcast_bytes_sent.lo));
 
                UPDATE_EXTEND_XSTAT(unicast_pkts_sent,
                                        total_unicast_packets_transmitted);
@@ -4033,46 +4693,44 @@ static void bnx2x_stats_update(struct bnx2x *bp)
        bnx2x_net_stats_update(bp);
        bnx2x_drv_stats_update(bp);
 
-       if (bp->msglevel & NETIF_MSG_TIMER) {
-               struct tstorm_per_client_stats *old_tclient =
-                                                       &bp->fp->old_tclient;
-               struct bnx2x_eth_q_stats *qstats = &bp->fp->eth_q_stats;
+       if (netif_msg_timer(bp)) {
                struct bnx2x_eth_stats *estats = &bp->eth_stats;
-               struct net_device_stats *nstats = &bp->dev->stats;
                int i;
 
-               printk(KERN_DEBUG "%s:\n", bp->dev->name);
-               printk(KERN_DEBUG "  tx avail (%4x)  tx hc idx (%x)"
-                                 "  tx pkt (%lx)\n",
-                      bnx2x_tx_avail(bp->fp),
-                      le16_to_cpu(*bp->fp->tx_cons_sb), nstats->tx_packets);
-               printk(KERN_DEBUG "  rx usage (%4x)  rx hc idx (%x)"
-                                 "  rx pkt (%lx)\n",
-                      (u16)(le16_to_cpu(*bp->fp->rx_cons_sb) -
-                            bp->fp->rx_comp_cons),
-                      le16_to_cpu(*bp->fp->rx_cons_sb), nstats->rx_packets);
-               printk(KERN_DEBUG "  %s (Xoff events %u)  brb drops %u  "
-                                 "brb truncate %u\n",
-                      (netif_queue_stopped(bp->dev) ? "Xoff" : "Xon"),
-                      qstats->driver_xoff,
+               printk(KERN_DEBUG "%s: brb drops %u  brb truncate %u\n",
+                      bp->dev->name,
                       estats->brb_drop_lo, estats->brb_truncate_lo);
-               printk(KERN_DEBUG "tstats: checksum_discard %u  "
-                       "packets_too_big_discard %lu  no_buff_discard %lu  "
-                       "mac_discard %u  mac_filter_discard %u  "
-                       "xxovrflow_discard %u  brb_truncate_discard %u  "
-                       "ttl0_discard %u\n",
-                      le32_to_cpu(old_tclient->checksum_discard),
-                      bnx2x_hilo(&qstats->etherstatsoverrsizepkts_hi),
-                      bnx2x_hilo(&qstats->no_buff_discard_hi),
-                      estats->mac_discard, estats->mac_filter_discard,
-                      estats->xxoverflow_discard, estats->brb_truncate_discard,
-                      le32_to_cpu(old_tclient->ttl0_discard));
 
                for_each_queue(bp, i) {
-                       printk(KERN_DEBUG "[%d]: %lu\t%lu\t%lu\n", i,
-                              bnx2x_fp(bp, i, tx_pkt),
-                              bnx2x_fp(bp, i, rx_pkt),
-                              bnx2x_fp(bp, i, rx_calls));
+                       struct bnx2x_fastpath *fp = &bp->fp[i];
+                       struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+
+                       printk(KERN_DEBUG "%s: rx usage(%4u)  *rx_cons_sb(%u)"
+                                         "  rx pkt(%lu)  rx calls(%lu %lu)\n",
+                              fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
+                              fp->rx_comp_cons),
+                              le16_to_cpu(*fp->rx_cons_sb),
+                              bnx2x_hilo(&qstats->
+                                         total_unicast_packets_received_hi),
+                              fp->rx_calls, fp->rx_pkt);
+               }
+
+               for_each_queue(bp, i) {
+                       struct bnx2x_fastpath *fp = &bp->fp[i];
+                       struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+                       struct netdev_queue *txq =
+                               netdev_get_tx_queue(bp->dev, i);
+
+                       printk(KERN_DEBUG "%s: tx avail(%4u)  *tx_cons_sb(%u)"
+                                         "  tx pkt(%lu) tx calls (%lu)"
+                                         "  %s (Xoff events %u)\n",
+                              fp->name, bnx2x_tx_avail(fp),
+                              le16_to_cpu(*fp->tx_cons_sb),
+                              bnx2x_hilo(&qstats->
+                                         total_unicast_packets_transmitted_hi),
+                              fp->tx_pkt,
+                              (netif_tx_queue_stopped(txq) ? "Xoff" : "Xon"),
+                              qstats->driver_xoff);
                }
        }
 
@@ -4193,14 +4851,187 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
 {
        enum bnx2x_stats_state state = bp->stats_state;
 
+       if (unlikely(bp->panic))
+               return;
+
        bnx2x_stats_stm[state][event].action(bp);
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
 
-       if ((event != STATS_EVENT_UPDATE) || (bp->msglevel & NETIF_MSG_TIMER))
+       /* Make sure the state has been "changed" */
+       smp_wmb();
+
+       if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
                   state, event, bp->stats_state);
 }
 
+static void bnx2x_port_stats_base_init(struct bnx2x *bp)
+{
+       struct dmae_command *dmae;
+       u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+       /* sanity */
+       if (!bp->port.pmf || !bp->port.port_stx) {
+               BNX2X_ERR("BUG!\n");
+               return;
+       }
+
+       bp->executer_idx = 0;
+
+       dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+       dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+                       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+                       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+                       DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+                       DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+                       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+                       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+       dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats));
+       dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
+       dmae->dst_addr_lo = bp->port.port_stx >> 2;
+       dmae->dst_addr_hi = 0;
+       dmae->len = sizeof(struct host_port_stats) >> 2;
+       dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+       dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+       dmae->comp_val = DMAE_COMP_VAL;
+
+       *stats_comp = 0;
+       bnx2x_hw_stats_post(bp);
+       bnx2x_stats_comp(bp);
+}
+
+static void bnx2x_func_stats_base_init(struct bnx2x *bp)
+{
+       int vn, vn_max = IS_E1HMF(bp) ? E1HVN_MAX : E1VN_MAX;
+       int port = BP_PORT(bp);
+       int func;
+       u32 func_stx;
+
+       /* sanity */
+       if (!bp->port.pmf || !bp->func_stx) {
+               BNX2X_ERR("BUG!\n");
+               return;
+       }
+
+       /* save our func_stx */
+       func_stx = bp->func_stx;
+
+       for (vn = VN_0; vn < vn_max; vn++) {
+               func = 2*vn + port;
+
+               bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+               bnx2x_func_stats_init(bp);
+               bnx2x_hw_stats_post(bp);
+               bnx2x_stats_comp(bp);
+       }
+
+       /* restore our func_stx */
+       bp->func_stx = func_stx;
+}
+
+static void bnx2x_func_stats_base_update(struct bnx2x *bp)
+{
+       struct dmae_command *dmae = &bp->stats_dmae;
+       u32 *stats_comp = bnx2x_sp(bp, stats_comp);
+
+       /* sanity */
+       if (!bp->func_stx) {
+               BNX2X_ERR("BUG!\n");
+               return;
+       }
+
+       bp->executer_idx = 0;
+       memset(dmae, 0, sizeof(struct dmae_command));
+
+       dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+                       DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+                       DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+                       DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+                       DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+                       (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0) |
+                       (BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT));
+       dmae->src_addr_lo = bp->func_stx >> 2;
+       dmae->src_addr_hi = 0;
+       dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base));
+       dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base));
+       dmae->len = sizeof(struct host_func_stats) >> 2;
+       dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
+       dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
+       dmae->comp_val = DMAE_COMP_VAL;
+
+       *stats_comp = 0;
+       bnx2x_hw_stats_post(bp);
+       bnx2x_stats_comp(bp);
+}
+
+static void bnx2x_stats_init(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       int func = BP_FUNC(bp);
+       int i;
+
+       bp->stats_pending = 0;
+       bp->executer_idx = 0;
+       bp->stats_counter = 0;
+
+       /* port and func stats for management */
+       if (!BP_NOMCP(bp)) {
+               bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx);
+               bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
+
+       } else {
+               bp->port.port_stx = 0;
+               bp->func_stx = 0;
+       }
+       DP(BNX2X_MSG_STATS, "port_stx 0x%x  func_stx 0x%x\n",
+          bp->port.port_stx, bp->func_stx);
+
+       /* port stats */
+       memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats));
+       bp->port.old_nig_stats.brb_discard =
+                       REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38);
+       bp->port.old_nig_stats.brb_truncate =
+                       REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38);
+       REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50,
+                   &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2);
+       REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50,
+                   &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2);
+
+       /* function stats */
+       for_each_queue(bp, i) {
+               struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               memset(&fp->old_tclient, 0,
+                      sizeof(struct tstorm_per_client_stats));
+               memset(&fp->old_uclient, 0,
+                      sizeof(struct ustorm_per_client_stats));
+               memset(&fp->old_xclient, 0,
+                      sizeof(struct xstorm_per_client_stats));
+               memset(&fp->eth_q_stats, 0, sizeof(struct bnx2x_eth_q_stats));
+       }
+
+       memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
+       memset(&bp->eth_stats, 0, sizeof(struct bnx2x_eth_stats));
+
+       bp->stats_state = STATS_STATE_DISABLED;
+
+       if (bp->port.pmf) {
+               if (bp->port.port_stx)
+                       bnx2x_port_stats_base_init(bp);
+
+               if (bp->func_stx)
+                       bnx2x_func_stats_base_init(bp);
+
+       } else if (bp->func_stx)
+               bnx2x_func_stats_base_update(bp);
+}
+
 static void bnx2x_timer(unsigned long data)
 {
        struct bnx2x *bp = (struct bnx2x *) data;
@@ -4243,8 +5074,7 @@ static void bnx2x_timer(unsigned long data)
                }
        }
 
-       if ((bp->state == BNX2X_STATE_OPEN) ||
-           (bp->state == BNX2X_STATE_DISABLED))
+       if (bp->state == BNX2X_STATE_OPEN)
                bnx2x_stats_handle(bp, STATS_EVENT_UPDATE);
 
 timer_restart:
@@ -4263,12 +5093,13 @@ static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id)
 {
        int port = BP_PORT(bp);
 
-       bnx2x_init_fill(bp, USTORM_INTMEM_ADDR +
-                       USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0,
-                       sizeof(struct ustorm_status_block)/4);
-       bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR +
-                       CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0,
-                       sizeof(struct cstorm_status_block)/4);
+       /* "CSTORM" */
+       bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+                       CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), 0,
+                       CSTORM_SB_STATUS_BLOCK_U_SIZE / 4);
+       bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+                       CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), 0,
+                       CSTORM_SB_STATUS_BLOCK_C_SIZE / 4);
 }
 
 static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
@@ -4284,17 +5115,17 @@ static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
                                            u_status_block);
        sb->u_status_block.status_block_id = sb_id;
 
-       REG_WR(bp, BAR_USTRORM_INTMEM +
-              USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section));
-       REG_WR(bp, BAR_USTRORM_INTMEM +
-              ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4),
+       REG_WR(bp, BAR_CSTRORM_INTMEM +
+              CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id), U64_LO(section));
+       REG_WR(bp, BAR_CSTRORM_INTMEM +
+              ((CSTORM_SB_HOST_SB_ADDR_U_OFFSET(port, sb_id)) + 4),
               U64_HI(section));
-       REG_WR8(bp, BAR_USTRORM_INTMEM + FP_USB_FUNC_OFF +
-               USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func);
+       REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_USB_FUNC_OFF +
+               CSTORM_SB_HOST_STATUS_BLOCK_U_OFFSET(port, sb_id), func);
 
        for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++)
-               REG_WR16(bp, BAR_USTRORM_INTMEM +
-                        USTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1);
+               REG_WR16(bp, BAR_CSTRORM_INTMEM +
+                        CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id, index), 1);
 
        /* CSTORM */
        section = ((u64)mapping) + offsetof(struct host_status_block,
@@ -4302,16 +5133,16 @@ static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
        sb->c_status_block.status_block_id = sb_id;
 
        REG_WR(bp, BAR_CSTRORM_INTMEM +
-              CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id), U64_LO(section));
+              CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id), U64_LO(section));
        REG_WR(bp, BAR_CSTRORM_INTMEM +
-              ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, sb_id)) + 4),
+              ((CSTORM_SB_HOST_SB_ADDR_C_OFFSET(port, sb_id)) + 4),
               U64_HI(section));
        REG_WR8(bp, BAR_CSTRORM_INTMEM + FP_CSB_FUNC_OFF +
-               CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), func);
+               CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id), func);
 
        for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++)
                REG_WR16(bp, BAR_CSTRORM_INTMEM +
-                        CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id, index), 1);
+                        CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id, index), 1);
 
        bnx2x_ack_sb(bp, sb_id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
 }
@@ -4320,16 +5151,16 @@ static void bnx2x_zero_def_sb(struct bnx2x *bp)
 {
        int func = BP_FUNC(bp);
 
-       bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR +
+       bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY +
                        TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
                        sizeof(struct tstorm_def_status_block)/4);
-       bnx2x_init_fill(bp, USTORM_INTMEM_ADDR +
-                       USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
-                       sizeof(struct ustorm_def_status_block)/4);
-       bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR +
-                       CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
-                       sizeof(struct cstorm_def_status_block)/4);
-       bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR +
+       bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+                       CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), 0,
+                       sizeof(struct cstorm_def_status_block_u)/4);
+       bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY +
+                       CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), 0,
+                       sizeof(struct cstorm_def_status_block_c)/4);
+       bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY +
                        XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
                        sizeof(struct xstorm_def_status_block)/4);
 }
@@ -4381,17 +5212,17 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
                                            u_def_status_block);
        def_sb->u_def_status_block.status_block_id = sb_id;
 
-       REG_WR(bp, BAR_USTRORM_INTMEM +
-              USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
-       REG_WR(bp, BAR_USTRORM_INTMEM +
-              ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
+       REG_WR(bp, BAR_CSTRORM_INTMEM +
+              CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func), U64_LO(section));
+       REG_WR(bp, BAR_CSTRORM_INTMEM +
+              ((CSTORM_DEF_SB_HOST_SB_ADDR_U_OFFSET(func)) + 4),
               U64_HI(section));
-       REG_WR8(bp, BAR_USTRORM_INTMEM + DEF_USB_FUNC_OFF +
-               USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
+       REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_USB_FUNC_OFF +
+               CSTORM_DEF_SB_HOST_STATUS_BLOCK_U_OFFSET(func), func);
 
        for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++)
-               REG_WR16(bp, BAR_USTRORM_INTMEM +
-                        USTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
+               REG_WR16(bp, BAR_CSTRORM_INTMEM +
+                        CSTORM_DEF_SB_HC_DISABLE_U_OFFSET(func, index), 1);
 
        /* CSTORM */
        section = ((u64)mapping) + offsetof(struct host_def_status_block,
@@ -4399,16 +5230,16 @@ static void bnx2x_init_def_sb(struct bnx2x *bp,
        def_sb->c_def_status_block.status_block_id = sb_id;
 
        REG_WR(bp, BAR_CSTRORM_INTMEM +
-              CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func), U64_LO(section));
+              CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func), U64_LO(section));
        REG_WR(bp, BAR_CSTRORM_INTMEM +
-              ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(func)) + 4),
+              ((CSTORM_DEF_SB_HOST_SB_ADDR_C_OFFSET(func)) + 4),
               U64_HI(section));
        REG_WR8(bp, BAR_CSTRORM_INTMEM + DEF_CSB_FUNC_OFF +
-               CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), func);
+               CSTORM_DEF_SB_HOST_STATUS_BLOCK_C_OFFSET(func), func);
 
        for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++)
                REG_WR16(bp, BAR_CSTRORM_INTMEM +
-                        CSTORM_DEF_SB_HC_DISABLE_OFFSET(func, index), 1);
+                        CSTORM_DEF_SB_HC_DISABLE_C_OFFSET(func, index), 1);
 
        /* TSTORM */
        section = ((u64)mapping) + offsetof(struct host_def_status_block,
@@ -4459,24 +5290,24 @@ static void bnx2x_update_coalesce(struct bnx2x *bp)
                int sb_id = bp->fp[i].sb_id;
 
                /* HC_INDEX_U_ETH_RX_CQ_CONS */
-               REG_WR8(bp, BAR_USTRORM_INTMEM +
-                       USTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id,
-                                                   U_SB_ETH_RX_CQ_INDEX),
-                       bp->rx_ticks/12);
-               REG_WR16(bp, BAR_USTRORM_INTMEM +
-                        USTORM_SB_HC_DISABLE_OFFSET(port, sb_id,
-                                                    U_SB_ETH_RX_CQ_INDEX),
-                        (bp->rx_ticks/12) ? 0 : 1);
+               REG_WR8(bp, BAR_CSTRORM_INTMEM +
+                       CSTORM_SB_HC_TIMEOUT_U_OFFSET(port, sb_id,
+                                                     U_SB_ETH_RX_CQ_INDEX),
+                       bp->rx_ticks/(4 * BNX2X_BTR));
+               REG_WR16(bp, BAR_CSTRORM_INTMEM +
+                        CSTORM_SB_HC_DISABLE_U_OFFSET(port, sb_id,
+                                                      U_SB_ETH_RX_CQ_INDEX),
+                        (bp->rx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
 
                /* HC_INDEX_C_ETH_TX_CQ_CONS */
                REG_WR8(bp, BAR_CSTRORM_INTMEM +
-                       CSTORM_SB_HC_TIMEOUT_OFFSET(port, sb_id,
-                                                   C_SB_ETH_TX_CQ_INDEX),
-                       bp->tx_ticks/12);
+                       CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id,
+                                                     C_SB_ETH_TX_CQ_INDEX),
+                       bp->tx_ticks/(4 * BNX2X_BTR));
                REG_WR16(bp, BAR_CSTRORM_INTMEM +
-                        CSTORM_SB_HC_DISABLE_OFFSET(port, sb_id,
-                                                    C_SB_ETH_TX_CQ_INDEX),
-                        (bp->tx_ticks/12) ? 0 : 1);
+                        CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id,
+                                                      C_SB_ETH_TX_CQ_INDEX),
+                        (bp->tx_ticks/(4 * BNX2X_BTR)) ? 0 : 1);
        }
 }
 
@@ -4495,9 +5326,9 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
                }
 
                if (fp->tpa_state[i] == BNX2X_TPA_START)
-                       pci_unmap_single(bp->pdev,
-                                        pci_unmap_addr(rx_buf, mapping),
-                                        bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+                       dma_unmap_single(&bp->pdev->dev,
+                                        dma_unmap_addr(rx_buf, mapping),
+                                        bp->rx_buf_size, DMA_FROM_DEVICE);
 
                dev_kfree_skb(skb);
                rx_buf->skb = NULL;
@@ -4518,7 +5349,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
 
        if (bp->flags & TPA_ENABLE_FLAG) {
 
-               for_each_rx_queue(bp, j) {
+               for_each_queue(bp, j) {
                        struct bnx2x_fastpath *fp = &bp->fp[j];
 
                        for (i = 0; i < max_agg_queues; i++) {
@@ -4533,7 +5364,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
                                        fp->disable_tpa = 1;
                                        break;
                                }
-                               pci_unmap_addr_set((struct sw_rx_bd *)
+                               dma_unmap_addr_set((struct sw_rx_bd *)
                                                        &bp->fp->tpa_pool[i],
                                                   mapping, 0);
                                fp->tpa_state[i] = BNX2X_TPA_STOP;
@@ -4541,7 +5372,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
                }
        }
 
-       for_each_rx_queue(bp, j) {
+       for_each_queue(bp, j) {
                struct bnx2x_fastpath *fp = &bp->fp[j];
 
                fp->rx_bd_cons = 0;
@@ -4627,8 +5458,8 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
 
                fp->rx_bd_prod = ring_prod;
                /* must not have more available CQEs than BDs */
-               fp->rx_comp_prod = min((u16)(NUM_RCQ_RINGS*RCQ_DESC_CNT),
-                                      cqe_ring_prod);
+               fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
+                                        cqe_ring_prod);
                fp->rx_pkt = fp->rx_calls = 0;
 
                /* Warning!
@@ -4653,21 +5484,25 @@ static void bnx2x_init_tx_ring(struct bnx2x *bp)
 {
        int i, j;
 
-       for_each_tx_queue(bp, j) {
+       for_each_queue(bp, j) {
                struct bnx2x_fastpath *fp = &bp->fp[j];
 
                for (i = 1; i <= NUM_TX_RINGS; i++) {
-                       struct eth_tx_bd *tx_bd =
-                               &fp->tx_desc_ring[TX_DESC_CNT * i - 1];
+                       struct eth_tx_next_bd *tx_next_bd =
+                               &fp->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd;
 
-                       tx_bd->addr_hi =
+                       tx_next_bd->addr_hi =
                                cpu_to_le32(U64_HI(fp->tx_desc_mapping +
                                            BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
-                       tx_bd->addr_lo =
+                       tx_next_bd->addr_lo =
                                cpu_to_le32(U64_LO(fp->tx_desc_mapping +
                                            BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
                }
 
+               fp->tx_db.data.header.header = DOORBELL_HDR_DB_TYPE;
+               fp->tx_db.data.zero_fill1 = 0;
+               fp->tx_db.data.prod = 0;
+
                fp->tx_pkt_prod = 0;
                fp->tx_pkt_cons = 0;
                fp->tx_bd_prod = 0;
@@ -4703,16 +5538,16 @@ static void bnx2x_init_context(struct bnx2x *bp)
 {
        int i;
 
+       /* Rx */
        for_each_queue(bp, i) {
                struct eth_context *context = bnx2x_sp(bp, context[i].eth);
                struct bnx2x_fastpath *fp = &bp->fp[i];
                u8 cl_id = fp->cl_id;
-               u8 sb_id = fp->sb_id;
 
                context->ustorm_st_context.common.sb_index_numbers =
                                                BNX2X_RX_SB_INDEX_NUM;
                context->ustorm_st_context.common.clientId = cl_id;
-               context->ustorm_st_context.common.status_block_id = sb_id;
+               context->ustorm_st_context.common.status_block_id = fp->sb_id;
                context->ustorm_st_context.common.flags =
                        (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_MC_ALIGNMENT |
                         USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS);
@@ -4728,15 +5563,21 @@ static void bnx2x_init_context(struct bnx2x *bp)
                                                U64_LO(fp->rx_desc_mapping);
                if (!fp->disable_tpa) {
                        context->ustorm_st_context.common.flags |=
-                               (USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA |
-                                USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_SGE_RING);
+                               USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA;
                        context->ustorm_st_context.common.sge_buff_size =
-                               (u16)min((u32)SGE_PAGE_SIZE*PAGES_PER_SGE,
-                                        (u32)0xffff);
+                               (u16)min_t(u32, SGE_PAGE_SIZE*PAGES_PER_SGE,
+                                          0xffff);
                        context->ustorm_st_context.common.sge_page_base_hi =
                                                U64_HI(fp->rx_sge_mapping);
                        context->ustorm_st_context.common.sge_page_base_lo =
                                                U64_LO(fp->rx_sge_mapping);
+
+                       context->ustorm_st_context.common.max_sges_for_packet =
+                               SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
+                       context->ustorm_st_context.common.max_sges_for_packet =
+                               ((context->ustorm_st_context.common.
+                                 max_sges_for_packet + PAGES_PER_SGE - 1) &
+                                (~(PAGES_PER_SGE - 1))) >> PAGES_PER_SGE_SHIFT;
                }
 
                context->ustorm_ag_context.cdu_usage =
@@ -4744,24 +5585,28 @@ static void bnx2x_init_context(struct bnx2x *bp)
                                               CDU_REGION_NUMBER_UCM_AG,
                                               ETH_CONNECTION_TYPE);
 
+               context->xstorm_ag_context.cdu_reserved =
+                       CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
+                                              CDU_REGION_NUMBER_XCM_AG,
+                                              ETH_CONNECTION_TYPE);
+       }
+
+       /* Tx */
+       for_each_queue(bp, i) {
+               struct bnx2x_fastpath *fp = &bp->fp[i];
+               struct eth_context *context =
+                       bnx2x_sp(bp, context[i].eth);
+
+               context->cstorm_st_context.sb_index_number =
+                                               C_SB_ETH_TX_CQ_INDEX;
+               context->cstorm_st_context.status_block_id = fp->sb_id;
+
                context->xstorm_st_context.tx_bd_page_base_hi =
                                                U64_HI(fp->tx_desc_mapping);
                context->xstorm_st_context.tx_bd_page_base_lo =
                                                U64_LO(fp->tx_desc_mapping);
-               context->xstorm_st_context.db_data_addr_hi =
-                                               U64_HI(fp->tx_prods_mapping);
-               context->xstorm_st_context.db_data_addr_lo =
-                                               U64_LO(fp->tx_prods_mapping);
-               context->xstorm_st_context.statistics_data = (cl_id |
+               context->xstorm_st_context.statistics_data = (fp->cl_id |
                                XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE);
-               context->cstorm_st_context.sb_index_number =
-                                               C_SB_ETH_TX_CQ_INDEX;
-               context->cstorm_st_context.status_block_id = sb_id;
-
-               context->xstorm_ag_context.cdu_reserved =
-                       CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
-                                              CDU_REGION_NUMBER_XCM_AG,
-                                              ETH_CONNECTION_TYPE);
        }
 }
 
@@ -4778,7 +5623,7 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
        for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++)
                REG_WR8(bp, BAR_TSTRORM_INTMEM +
                        TSTORM_INDIRECTION_TABLE_OFFSET(func) + i,
-                       bp->fp->cl_id + (i % bp->num_rx_queues));
+                       bp->fp->cl_id + (i % bp->num_queues));
 }
 
 static void bnx2x_set_client_config(struct bnx2x *bp)
@@ -4799,18 +5644,6 @@ static void bnx2x_set_client_config(struct bnx2x *bp)
        }
 #endif
 
-       if (bp->flags & TPA_ENABLE_FLAG) {
-               tstorm_client.max_sges_for_packet =
-                       SGE_PAGE_ALIGN(tstorm_client.mtu) >> SGE_PAGE_SHIFT;
-               tstorm_client.max_sges_for_packet =
-                       ((tstorm_client.max_sges_for_packet +
-                         PAGES_PER_SGE - 1) & (~(PAGES_PER_SGE - 1))) >>
-                       PAGES_PER_SGE_SHIFT;
-
-               tstorm_client.config_flags |=
-                               TSTORM_ETH_CLIENT_CONFIG_ENABLE_SGE_RING;
-       }
-
        for_each_queue(bp, i) {
                tstorm_client.statistics_counter_id = bp->fp[i].cl_id;
 
@@ -4830,7 +5663,7 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
 {
        struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0};
        int mode = bp->rx_mode;
-       int mask = (1 << BP_L_ID(bp));
+       int mask = bp->rx_mode_cl_mask;
        int func = BP_FUNC(bp);
        int port = BP_PORT(bp);
        int i;
@@ -4893,17 +5726,6 @@ static void bnx2x_init_internal_common(struct bnx2x *bp)
 {
        int i;
 
-       if (bp->flags & TPA_ENABLE_FLAG) {
-               struct tstorm_eth_tpa_exist tpa = {0};
-
-               tpa.tpa_exist = 1;
-
-               REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET,
-                      ((u32 *)&tpa)[0]);
-               REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_TPA_EXIST_OFFSET + 4,
-                      ((u32 *)&tpa)[1]);
-       }
-
        /* Zero this manually as its initialization is
           currently missing in the initTool */
        for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
@@ -4915,53 +5737,14 @@ static void bnx2x_init_internal_port(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
 
-       REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
-       REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
-       REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
+       REG_WR(bp,
+              BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_U_OFFSET(port), BNX2X_BTR);
+       REG_WR(bp,
+              BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_C_OFFSET(port), BNX2X_BTR);
+       REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
        REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), BNX2X_BTR);
 }
 
-/* Calculates the sum of vn_min_rates.
-   It's needed for further normalizing of the min_rates.
-   Returns:
-     sum of vn_min_rates.
-       or
-     0 - if all the min_rates are 0.
-     In the later case fainess algorithm should be deactivated.
-     If not all min_rates are zero then those that are zeroes will be set to 1.
- */
-static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
-{
-       int all_zero = 1;
-       int port = BP_PORT(bp);
-       int vn;
-
-       bp->vn_weight_sum = 0;
-       for (vn = VN_0; vn < E1HVN_MAX; vn++) {
-               int func = 2*vn + port;
-               u32 vn_cfg =
-                       SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
-               u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >>
-                                  FUNC_MF_CFG_MIN_BW_SHIFT) * 100;
-
-               /* Skip hidden vns */
-               if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE)
-                       continue;
-
-               /* If min rate is zero - set it to 1 */
-               if (!vn_min_rate)
-                       vn_min_rate = DEF_MIN_RATE;
-               else
-                       all_zero = 0;
-
-               bp->vn_weight_sum += vn_min_rate;
-       }
-
-       /* ... only if all min rates are zeros - disable fairness */
-       if (all_zero)
-               bp->vn_weight_sum = 0;
-}
-
 static void bnx2x_init_internal_func(struct bnx2x *bp)
 {
        struct tstorm_eth_function_common_config tstorm_config = {0};
@@ -4972,10 +5755,16 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
        u32 offset;
        u16 max_agg_size;
 
-       if (is_multi(bp)) {
-               tstorm_config.config_flags = MULTI_FLAGS(bp);
+       tstorm_config.config_flags = RSS_FLAGS(bp);
+
+       if (is_multi(bp))
                tstorm_config.rss_result_mask = MULTI_MASK;
-       }
+
+       /* Enable TPA if needed */
+       if (bp->flags & TPA_ENABLE_FLAG)
+               tstorm_config.config_flags |=
+                       TSTORM_ETH_FUNCTION_COMMON_CONFIG_ENABLE_TPA;
+
        if (IS_E1HMF(bp))
                tstorm_config.config_flags |=
                                TSTORM_ETH_FUNCTION_COMMON_CONFIG_E1HOV_IN_CAM;
@@ -4987,6 +5776,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
               (*(u32 *)&tstorm_config));
 
        bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */
+       bp->rx_mode_cl_mask = (1 << BP_L_ID(bp));
        bnx2x_set_storm_rx_mode(bp);
 
        for_each_queue(bp, i) {
@@ -5073,11 +5863,9 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
        }
 
        /* Init CQ ring mapping and aggregation size, the FW limit is 8 frags */
-       max_agg_size =
-               min((u32)(min((u32)8, (u32)MAX_SKB_FRAGS) *
-                         SGE_PAGE_SIZE * PAGES_PER_SGE),
-                   (u32)0xffff);
-       for_each_rx_queue(bp, i) {
+       max_agg_size = min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) *
+                                  SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
+       for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
                REG_WR(bp, BAR_USTRORM_INTMEM +
@@ -5087,6 +5875,14 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
                       USTORM_CQE_PAGE_BASE_OFFSET(port, fp->cl_id) + 4,
                       U64_HI(fp->rx_comp_mapping));
 
+               /* Next page */
+               REG_WR(bp, BAR_USTRORM_INTMEM +
+                      USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id),
+                      U64_LO(fp->rx_comp_mapping + BCM_PAGE_SIZE));
+               REG_WR(bp, BAR_USTRORM_INTMEM +
+                      USTORM_CQE_PAGE_NEXT_OFFSET(port, fp->cl_id) + 4,
+                      U64_HI(fp->rx_comp_mapping + BCM_PAGE_SIZE));
+
                REG_WR16(bp, BAR_USTRORM_INTMEM +
                         USTORM_MAX_AGG_SIZE_OFFSET(port, fp->cl_id),
                         max_agg_size);
@@ -5104,7 +5900,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
                rx_pause.cqe_thr_high = 350;
                rx_pause.sge_thr_high = 0;
 
-               for_each_rx_queue(bp, i) {
+               for_each_queue(bp, i) {
                        struct bnx2x_fastpath *fp = &bp->fp[i];
 
                        if (!fp->disable_tpa) {
@@ -5135,20 +5931,18 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
                bp->link_vars.line_speed = SPEED_10000;
                bnx2x_init_port_minmax(bp);
 
+               if (!BP_NOMCP(bp))
+                       bp->mf_config =
+                             SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
                bnx2x_calc_vn_weight_sum(bp);
 
                for (vn = VN_0; vn < E1HVN_MAX; vn++)
                        bnx2x_init_vn_minmax(bp, 2*vn + port);
 
                /* Enable rate shaping and fairness */
-               bp->cmng.flags.cmng_enables =
+               bp->cmng.flags.cmng_enables |=
                                        CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN;
-               if (bp->vn_weight_sum)
-                       bp->cmng.flags.cmng_enables |=
-                                       CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
-               else
-                       DP(NETIF_MSG_IFUP, "All MIN values are zeroes"
-                          "  fairness will be disabled\n");
+
        } else {
                /* rate shaping and fairness are disabled */
                DP(NETIF_MSG_IFUP,
@@ -5156,7 +5950,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
        }
 
 
-       /* Store it to internal memory */
+       /* Store cmng structures to internal memory */
        if (bp->port.pmf)
                for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
                        REG_WR(bp, BAR_XSTRORM_INTMEM +
@@ -5196,7 +5990,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
                fp->state = BNX2X_FP_STATE_CLOSED;
                fp->index = i;
                fp->cl_id = BP_L_ID(bp) + i;
+#ifdef BCM_CNIC
+               fp->sb_id = fp->cl_id + 1;
+#else
                fp->sb_id = fp->cl_id;
+#endif
                DP(NETIF_MSG_IFUP,
                   "queue[%d]:  bnx2x_init_sb(%p,%p)  cl_id %d  sb %d\n",
                   i, bp, fp->status_blk, fp->cl_id, fp->sb_id);
@@ -5244,8 +6042,8 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
 
 static int bnx2x_gunzip_init(struct bnx2x *bp)
 {
-       bp->gunzip_buf = pci_alloc_consistent(bp->pdev, FW_BUF_SIZE,
-                                             &bp->gunzip_mapping);
+       bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE,
+                                           &bp->gunzip_mapping, GFP_KERNEL);
        if (bp->gunzip_buf  == NULL)
                goto gunzip_nomem1;
 
@@ -5265,13 +6063,13 @@ gunzip_nomem3:
        bp->strm = NULL;
 
 gunzip_nomem2:
-       pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf,
-                           bp->gunzip_mapping);
+       dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
+                         bp->gunzip_mapping);
        bp->gunzip_buf = NULL;
 
 gunzip_nomem1:
-       printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for"
-              " un-compression\n", bp->dev->name);
+       netdev_err(bp->dev, "Cannot allocate firmware buffer for"
+              " un-compression\n");
        return -ENOMEM;
 }
 
@@ -5283,8 +6081,8 @@ static void bnx2x_gunzip_end(struct bnx2x *bp)
        bp->strm = NULL;
 
        if (bp->gunzip_buf) {
-               pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf,
-                                   bp->gunzip_mapping);
+               dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
+                                 bp->gunzip_mapping);
                bp->gunzip_buf = NULL;
        }
 }
@@ -5317,14 +6115,14 @@ static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len)
 
        rc = zlib_inflate(bp->strm, Z_FINISH);
        if ((rc != Z_OK) && (rc != Z_STREAM_END))
-               printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
-                      bp->dev->name, bp->strm->msg);
+               netdev_err(bp->dev, "Firmware decompression error: %s\n",
+                          bp->strm->msg);
 
        bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out);
        if (bp->gunzip_outlen & 0x3)
-               printk(KERN_ERR PFX "%s: Firmware decompression error:"
+               netdev_err(bp->dev, "Firmware decompression error:"
                                    " gunzip_outlen (%d) not aligned\n",
-                      bp->dev->name, bp->gunzip_outlen);
+                               bp->gunzip_outlen);
        bp->gunzip_outlen >>= 2;
 
        zlib_inflateEnd(bp->strm);
@@ -5495,7 +6293,7 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
        msleep(50);
        bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
        bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
-#ifndef BCM_ISCSI
+#ifndef BCM_CNIC
        /* set NIC mode */
        REG_WR(bp, PRS_REG_NIC_MODE, 1);
 #endif
@@ -5550,6 +6348,50 @@ static void enable_blocks_attention(struct bnx2x *bp)
        REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18);         /* bit 3,4 masked */
 }
 
+static const struct {
+       u32 addr;
+       u32 mask;
+} bnx2x_parity_mask[] = {
+       {PXP_REG_PXP_PRTY_MASK, 0xffffffff},
+       {PXP2_REG_PXP2_PRTY_MASK_0, 0xffffffff},
+       {PXP2_REG_PXP2_PRTY_MASK_1, 0xffffffff},
+       {HC_REG_HC_PRTY_MASK, 0xffffffff},
+       {MISC_REG_MISC_PRTY_MASK, 0xffffffff},
+       {QM_REG_QM_PRTY_MASK, 0x0},
+       {DORQ_REG_DORQ_PRTY_MASK, 0x0},
+       {GRCBASE_UPB + PB_REG_PB_PRTY_MASK, 0x0},
+       {GRCBASE_XPB + PB_REG_PB_PRTY_MASK, 0x0},
+       {SRC_REG_SRC_PRTY_MASK, 0x4}, /* bit 2 */
+       {CDU_REG_CDU_PRTY_MASK, 0x0},
+       {CFC_REG_CFC_PRTY_MASK, 0x0},
+       {DBG_REG_DBG_PRTY_MASK, 0x0},
+       {DMAE_REG_DMAE_PRTY_MASK, 0x0},
+       {BRB1_REG_BRB1_PRTY_MASK, 0x0},
+       {PRS_REG_PRS_PRTY_MASK, (1<<6)},/* bit 6 */
+       {TSDM_REG_TSDM_PRTY_MASK, 0x18},/* bit 3,4 */
+       {CSDM_REG_CSDM_PRTY_MASK, 0x8}, /* bit 3 */
+       {USDM_REG_USDM_PRTY_MASK, 0x38},/* bit 3,4,5 */
+       {XSDM_REG_XSDM_PRTY_MASK, 0x8}, /* bit 3 */
+       {TSEM_REG_TSEM_PRTY_MASK_0, 0x0},
+       {TSEM_REG_TSEM_PRTY_MASK_1, 0x0},
+       {USEM_REG_USEM_PRTY_MASK_0, 0x0},
+       {USEM_REG_USEM_PRTY_MASK_1, 0x0},
+       {CSEM_REG_CSEM_PRTY_MASK_0, 0x0},
+       {CSEM_REG_CSEM_PRTY_MASK_1, 0x0},
+       {XSEM_REG_XSEM_PRTY_MASK_0, 0x0},
+       {XSEM_REG_XSEM_PRTY_MASK_1, 0x0}
+};
+
+static void enable_blocks_parity(struct bnx2x *bp)
+{
+       int i, mask_arr_len =
+               sizeof(bnx2x_parity_mask)/(sizeof(bnx2x_parity_mask[0]));
+
+       for (i = 0; i < mask_arr_len; i++)
+               REG_WR(bp, bnx2x_parity_mask[i].addr,
+                       bnx2x_parity_mask[i].mask);
+}
+
 
 static void bnx2x_reset_common(struct bnx2x *bp)
 {
@@ -5559,13 +6401,35 @@ static void bnx2x_reset_common(struct bnx2x *bp)
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
 }
 
+static void bnx2x_init_pxp(struct bnx2x *bp)
+{
+       u16 devctl;
+       int r_order, w_order;
+
+       pci_read_config_word(bp->pdev,
+                            bp->pcie_cap + PCI_EXP_DEVCTL, &devctl);
+       DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl);
+       w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
+       if (bp->mrrs == -1)
+               r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12);
+       else {
+               DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs);
+               r_order = bp->mrrs;
+       }
+
+       bnx2x_init_pxp_arb(bp, r_order, w_order);
+}
 
 static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
 {
+       int is_required;
        u32 val;
-       u8 port;
-       u8 is_required = 0;
+       int port;
+
+       if (BP_NOMCP(bp))
+               return;
 
+       is_required = 0;
        val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
              SHARED_HW_CFG_FAN_FAILURE_MASK;
 
@@ -5604,7 +6468,7 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
        /* set to active low mode */
        val = REG_RD(bp, MISC_REG_SPIO_INT);
        val |= ((1 << MISC_REGISTERS_SPIO_5) <<
-                               MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+                                       MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
        REG_WR(bp, MISC_REG_SPIO_INT, val);
 
        /* enable interrupt to signal the IGU */
@@ -5616,6 +6480,9 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
 static int bnx2x_init_common(struct bnx2x *bp)
 {
        u32 val, i;
+#ifdef BCM_CNIC
+       u32 wb_write[2];
+#endif
 
        DP(BNX2X_MSG_MCP, "starting common init  func %d\n", BP_FUNC(bp));
 
@@ -5658,7 +6525,7 @@ static int bnx2x_init_common(struct bnx2x *bp)
 #endif
 
        REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2);
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
        REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5);
        REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5);
        REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5);
@@ -5701,11 +6568,26 @@ static int bnx2x_init_common(struct bnx2x *bp)
        bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3);
 
        bnx2x_init_block(bp, QM_BLOCK, COMMON_STAGE);
+
+#ifdef BCM_CNIC
+       wb_write[0] = 0;
+       wb_write[1] = 0;
+       for (i = 0; i < 64; i++) {
+               REG_WR(bp, QM_REG_BASEADDR + i*4, 1024 * 4 * (i%16));
+               bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8, wb_write, 2);
+
+               if (CHIP_IS_E1H(bp)) {
+                       REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4, 1024*4*(i%16));
+                       bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8,
+                                         wb_write, 2);
+               }
+       }
+#endif
        /* soft reset pulse */
        REG_WR(bp, QM_REG_SOFT_RESET, 1);
        REG_WR(bp, QM_REG_SOFT_RESET, 0);
 
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
        bnx2x_init_block(bp, TIMERS_BLOCK, COMMON_STAGE);
 #endif
 
@@ -5719,8 +6601,10 @@ static int bnx2x_init_common(struct bnx2x *bp)
        bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
        bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
        REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
+#ifndef BCM_CNIC
        /* set NIC mode */
        REG_WR(bp, PRS_REG_NIC_MODE, 1);
+#endif
        if (CHIP_IS_E1H(bp))
                REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp));
 
@@ -5729,10 +6613,10 @@ static int bnx2x_init_common(struct bnx2x *bp)
        bnx2x_init_block(bp, USDM_BLOCK, COMMON_STAGE);
        bnx2x_init_block(bp, XSDM_BLOCK, COMMON_STAGE);
 
-       bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
-       bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
-       bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
-       bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
+       bnx2x_init_fill(bp, TSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
+       bnx2x_init_fill(bp, USEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
+       bnx2x_init_fill(bp, CSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
+       bnx2x_init_fill(bp, XSEM_REG_FAST_MEMORY, 0, STORM_INTMEM_SIZE(bp));
 
        bnx2x_init_block(bp, TSEM_BLOCK, COMMON_STAGE);
        bnx2x_init_block(bp, USEM_BLOCK, COMMON_STAGE);
@@ -5750,26 +6634,32 @@ static int bnx2x_init_common(struct bnx2x *bp)
        bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE);
 
        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: replace with something meaningful */
-       }
+       for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4)
+               REG_WR(bp, i, random32());
        bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE);
+#ifdef BCM_CNIC
+       REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672);
+       REG_WR(bp, SRC_REG_KEYSEARCH_1, 0x24b8f2cc);
+       REG_WR(bp, SRC_REG_KEYSEARCH_2, 0x223aef9b);
+       REG_WR(bp, SRC_REG_KEYSEARCH_3, 0x26001e3a);
+       REG_WR(bp, SRC_REG_KEYSEARCH_4, 0x7ae91116);
+       REG_WR(bp, SRC_REG_KEYSEARCH_5, 0x5ce5230b);
+       REG_WR(bp, SRC_REG_KEYSEARCH_6, 0x298d8adf);
+       REG_WR(bp, SRC_REG_KEYSEARCH_7, 0x6eb0ff09);
+       REG_WR(bp, SRC_REG_KEYSEARCH_8, 0x1830f82f);
+       REG_WR(bp, SRC_REG_KEYSEARCH_9, 0x01e46be7);
+#endif
        REG_WR(bp, SRC_REG_SOFT_RST, 0);
 
        if (sizeof(union cdu_context) != 1024)
                /* we currently assume that a context is 1024 bytes */
-               printk(KERN_ALERT PFX "please adjust the size of"
-                      " cdu_context(%ld)\n", (long)sizeof(union cdu_context));
+               dev_alert(&bp->pdev->dev, "please adjust the size "
+                                         "of cdu_context(%ld)\n",
+                        (long)sizeof(union cdu_context));
 
        bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE);
        val = (4 << 24) + (0 << 12) + 1024;
        REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val);
-       if (CHIP_IS_E1(bp)) {
-               /* !!! fix pxp client crdit until excel update */
-               REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264);
-               REG_WR(bp, CDU_REG_CDU_DEBUG, 0);
-       }
 
        bnx2x_init_block(bp, CFC_BLOCK, COMMON_STAGE);
        REG_WR(bp, CFC_REG_INIT_REG, 0x7FF);
@@ -5782,19 +6672,14 @@ static int bnx2x_init_common(struct bnx2x *bp)
        bnx2x_init_block(bp, HC_BLOCK, COMMON_STAGE);
        bnx2x_init_block(bp, MISC_AEU_BLOCK, COMMON_STAGE);
 
-       /* PXPCS COMMON comes here */
        bnx2x_init_block(bp, PXPCS_BLOCK, COMMON_STAGE);
        /* Reset PCIE errors for debug */
        REG_WR(bp, 0x2814, 0xffffffff);
        REG_WR(bp, 0x3820, 0xffffffff);
 
-       /* EMAC0 COMMON comes here */
        bnx2x_init_block(bp, EMAC0_BLOCK, COMMON_STAGE);
-       /* EMAC1 COMMON comes here */
        bnx2x_init_block(bp, EMAC1_BLOCK, COMMON_STAGE);
-       /* DBU COMMON comes here */
        bnx2x_init_block(bp, DBU_BLOCK, COMMON_STAGE);
-       /* DBG COMMON comes here */
        bnx2x_init_block(bp, DBG_BLOCK, COMMON_STAGE);
 
        bnx2x_init_block(bp, NIG_BLOCK, COMMON_STAGE);
@@ -5853,6 +6738,8 @@ static int bnx2x_init_common(struct bnx2x *bp)
        REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
 
        enable_blocks_attention(bp);
+       if (CHIP_PARITY_SUPPORTED(bp))
+               enable_blocks_parity(bp);
 
        if (!BP_NOMCP(bp)) {
                bnx2x_acquire_phy_lock(bp);
@@ -5871,50 +6758,26 @@ static int bnx2x_init_port(struct bnx2x *bp)
        u32 low, high;
        u32 val;
 
-       DP(BNX2X_MSG_MCP, "starting port init  port %x\n", port);
+       DP(BNX2X_MSG_MCP, "starting port init  port %d\n", port);
 
        REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0);
 
-       /* Port PXP comes here */
        bnx2x_init_block(bp, PXP_BLOCK, init_stage);
-       /* Port PXP2 comes here */
        bnx2x_init_block(bp, PXP2_BLOCK, init_stage);
-#ifdef BCM_ISCSI
-       /* Port0  1
-        * Port1  385 */
-       i++;
-       wb_write[0] = ONCHIP_ADDR1(bp->timers_mapping);
-       wb_write[1] = ONCHIP_ADDR2(bp->timers_mapping);
-       REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
-       REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
-
-       /* Port0  2
-        * Port1  386 */
-       i++;
-       wb_write[0] = ONCHIP_ADDR1(bp->qm_mapping);
-       wb_write[1] = ONCHIP_ADDR2(bp->qm_mapping);
-       REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
-       REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
 
-       /* Port0  3
-        * Port1  387 */
-       i++;
-       wb_write[0] = ONCHIP_ADDR1(bp->t1_mapping);
-       wb_write[1] = ONCHIP_ADDR2(bp->t1_mapping);
-       REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
-       REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
-#endif
-       /* Port CMs come here */
+       bnx2x_init_block(bp, TCM_BLOCK, init_stage);
+       bnx2x_init_block(bp, UCM_BLOCK, init_stage);
+       bnx2x_init_block(bp, CCM_BLOCK, init_stage);
        bnx2x_init_block(bp, XCM_BLOCK, init_stage);
 
-       /* Port QM comes here */
-#ifdef BCM_ISCSI
-       REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20);
-       REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31);
+#ifdef BCM_CNIC
+       REG_WR(bp, QM_REG_CONNNUM_0 + port*4, 1024/16 - 1);
 
        bnx2x_init_block(bp, TIMERS_BLOCK, init_stage);
+       REG_WR(bp, TM_REG_LIN0_SCAN_TIME + port*4, 20);
+       REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + port*4, 31);
 #endif
-       /* Port DQ comes here */
+
        bnx2x_init_block(bp, DQ_BLOCK, init_stage);
 
        bnx2x_init_block(bp, BRB1_BLOCK, init_stage);
@@ -5941,15 +6804,11 @@ static int bnx2x_init_port(struct bnx2x *bp)
        REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high);
 
 
-       /* Port PRS comes here */
        bnx2x_init_block(bp, PRS_BLOCK, init_stage);
-       /* Port TSDM comes here */
+
        bnx2x_init_block(bp, TSDM_BLOCK, init_stage);
-       /* Port CSDM comes here */
        bnx2x_init_block(bp, CSDM_BLOCK, init_stage);
-       /* Port USDM comes here */
        bnx2x_init_block(bp, USDM_BLOCK, init_stage);
-       /* Port XSDM comes here */
        bnx2x_init_block(bp, XSDM_BLOCK, init_stage);
 
        bnx2x_init_block(bp, TSEM_BLOCK, init_stage);
@@ -5957,9 +6816,7 @@ static int bnx2x_init_port(struct bnx2x *bp)
        bnx2x_init_block(bp, CSEM_BLOCK, init_stage);
        bnx2x_init_block(bp, XSEM_BLOCK, init_stage);
 
-       /* Port UPB comes here */
        bnx2x_init_block(bp, UPB_BLOCK, init_stage);
-       /* Port XPB comes here */
        bnx2x_init_block(bp, XPB_BLOCK, init_stage);
 
        bnx2x_init_block(bp, PBF_BLOCK, init_stage);
@@ -5977,23 +6834,10 @@ static int bnx2x_init_port(struct bnx2x *bp)
        msleep(5);
        REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0);
 
-#ifdef BCM_ISCSI
-       /* tell the searcher where the T2 table is */
-       REG_WR(bp, SRC_REG_COUNTFREE0 + func*4, 16*1024/64);
-
-       wb_write[0] = U64_LO(bp->t2_mapping);
-       wb_write[1] = U64_HI(bp->t2_mapping);
-       REG_WR_DMAE(bp, SRC_REG_FIRSTFREE0 + func*4, wb_write, 2);
-       wb_write[0] = U64_LO((u64)bp->t2_mapping + 16*1024 - 64);
-       wb_write[1] = U64_HI((u64)bp->t2_mapping + 16*1024 - 64);
-       REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2);
-
-       REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10);
-       /* Port SRCH comes here */
+#ifdef BCM_CNIC
+       bnx2x_init_block(bp, SRCH_BLOCK, init_stage);
 #endif
-       /* Port CDU comes here */
        bnx2x_init_block(bp, CDU_BLOCK, init_stage);
-       /* Port CFC comes here */
        bnx2x_init_block(bp, CFC_BLOCK, init_stage);
 
        if (CHIP_IS_E1(bp)) {
@@ -6010,15 +6854,10 @@ static int bnx2x_init_port(struct bnx2x *bp)
        REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4,
               (IS_E1HMF(bp) ? 0xF7 : 0x7));
 
-       /* Port PXPCS comes here */
        bnx2x_init_block(bp, PXPCS_BLOCK, init_stage);
-       /* Port EMAC0 comes here */
        bnx2x_init_block(bp, EMAC0_BLOCK, init_stage);
-       /* Port EMAC1 comes here */
        bnx2x_init_block(bp, EMAC1_BLOCK, init_stage);
-       /* Port DBU comes here */
        bnx2x_init_block(bp, DBU_BLOCK, init_stage);
-       /* Port DBG comes here */
        bnx2x_init_block(bp, DBG_BLOCK, init_stage);
 
        bnx2x_init_block(bp, NIG_BLOCK, init_stage);
@@ -6030,9 +6869,6 @@ static int bnx2x_init_port(struct bnx2x *bp)
                REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4,
                       (IS_E1HMF(bp) ? 0x1 : 0x2));
 
-               /* support pause requests from USDM, TSDM and BRB */
-               REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0 + port*4, 0x7);
-
                {
                        REG_WR(bp, NIG_REG_LLFC_ENABLE_0 + port*4, 0);
                        REG_WR(bp, NIG_REG_LLFC_OUT_EN_0 + port*4, 0);
@@ -6040,9 +6876,7 @@ static int bnx2x_init_port(struct bnx2x *bp)
                }
        }
 
-       /* Port MCP comes here */
        bnx2x_init_block(bp, MCP_BLOCK, init_stage);
-       /* Port DMAE comes here */
        bnx2x_init_block(bp, DMAE_BLOCK, init_stage);
 
        switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
@@ -6110,7 +6944,12 @@ static int bnx2x_init_port(struct bnx2x *bp)
 #define PXP_ONE_ILT(x)         (((x) << 10) | x)
 #define PXP_ILT_RANGE(f, l)    (((l) << 10) | f)
 
+#ifdef BCM_CNIC
+#define CNIC_ILT_LINES         127
+#define CNIC_CTX_PER_ILT       16
+#else
 #define CNIC_ILT_LINES         0
+#endif
 
 static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
 {
@@ -6131,7 +6970,7 @@ static int bnx2x_init_func(struct bnx2x *bp)
        u32 addr, val;
        int i;
 
-       DP(BNX2X_MSG_MCP, "starting func init  func %x\n", func);
+       DP(BNX2X_MSG_MCP, "starting func init  func %d\n", func);
 
        /* set MSI reconfigure capability */
        addr = (port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0);
@@ -6149,11 +6988,57 @@ static int bnx2x_init_func(struct bnx2x *bp)
                REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4,
                       PXP_ILT_RANGE(i, i + CNIC_ILT_LINES));
 
+#ifdef BCM_CNIC
+       i += 1 + CNIC_ILT_LINES;
+       bnx2x_ilt_wr(bp, i, bp->timers_mapping);
+       if (CHIP_IS_E1(bp))
+               REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
+       else {
+               REG_WR(bp, PXP2_REG_RQ_TM_FIRST_ILT, i);
+               REG_WR(bp, PXP2_REG_RQ_TM_LAST_ILT, i);
+       }
+
+       i++;
+       bnx2x_ilt_wr(bp, i, bp->qm_mapping);
+       if (CHIP_IS_E1(bp))
+               REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
+       else {
+               REG_WR(bp, PXP2_REG_RQ_QM_FIRST_ILT, i);
+               REG_WR(bp, PXP2_REG_RQ_QM_LAST_ILT, i);
+       }
+
+       i++;
+       bnx2x_ilt_wr(bp, i, bp->t1_mapping);
+       if (CHIP_IS_E1(bp))
+               REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
+       else {
+               REG_WR(bp, PXP2_REG_RQ_SRC_FIRST_ILT, i);
+               REG_WR(bp, PXP2_REG_RQ_SRC_LAST_ILT, i);
+       }
+
+       /* tell the searcher where the T2 table is */
+       REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, 16*1024/64);
+
+       bnx2x_wb_wr(bp, SRC_REG_FIRSTFREE0 + port*16,
+                   U64_LO(bp->t2_mapping), U64_HI(bp->t2_mapping));
+
+       bnx2x_wb_wr(bp, SRC_REG_LASTFREE0 + port*16,
+                   U64_LO((u64)bp->t2_mapping + 16*1024 - 64),
+                   U64_HI((u64)bp->t2_mapping + 16*1024 - 64));
+
+       REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, 10);
+#endif
 
        if (CHIP_IS_E1H(bp)) {
-               for (i = 0; i < 9; i++)
-                       bnx2x_init_block(bp,
-                                        cm_blocks[i], FUNC0_STAGE + func);
+               bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, TCM_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, UCM_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, CCM_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, XCM_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, TSEM_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, USEM_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, CSEM_BLOCK, FUNC0_STAGE + func);
+               bnx2x_init_block(bp, XSEM_BLOCK, FUNC0_STAGE + func);
 
                REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
                REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->e1hov);
@@ -6184,7 +7069,9 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
 
        bp->dmae_ready = 0;
        mutex_init(&bp->dmae_mutex);
-       bnx2x_gunzip_init(bp);
+       rc = bnx2x_gunzip_init(bp);
+       if (rc)
+               return rc;
 
        switch (load_code) {
        case FW_MSG_CODE_DRV_LOAD_COMMON:
@@ -6218,16 +7105,16 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
                bp->fw_drv_pulse_wr_seq =
                                (SHMEM_RD(bp, func_mb[func].drv_pulse_mb) &
                                 DRV_PULSE_SEQ_MASK);
-               bp->func_stx = SHMEM_RD(bp, func_mb[func].fw_mb_param);
-               DP(BNX2X_MSG_MCP, "drv_pulse 0x%x  func_stx 0x%x\n",
-                  bp->fw_drv_pulse_wr_seq, bp->func_stx);
-       } else
-               bp->func_stx = 0;
+               DP(BNX2X_MSG_MCP, "drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
+       }
 
        /* this needs to be done before gunzip end */
        bnx2x_zero_def_sb(bp);
        for_each_queue(bp, i)
                bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
+#ifdef BCM_CNIC
+       bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
+#endif
 
 init_hw_err:
        bnx2x_gunzip_end(bp);
@@ -6235,51 +7122,13 @@ init_hw_err:
        return rc;
 }
 
-/* send the MCP a request, block until there is a reply */
-u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
-{
-       int func = BP_FUNC(bp);
-       u32 seq = ++bp->fw_seq;
-       u32 rc = 0;
-       u32 cnt = 1;
-       u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
-
-       SHMEM_WR(bp, func_mb[func].drv_mb_header, (command | seq));
-       DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", (command | seq));
-
-       do {
-               /* let the FW do it's magic ... */
-               msleep(delay);
-
-               rc = SHMEM_RD(bp, func_mb[func].fw_mb_header);
-
-               /* Give the FW up to 2 second (200*10ms) */
-       } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 200));
-
-       DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n",
-          cnt*delay, rc, seq);
-
-       /* is this a reply to our command? */
-       if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) {
-               rc &= FW_MSG_CODE_MASK;
-
-       } else {
-               /* FW BUG! */
-               BNX2X_ERR("FW failed to respond!\n");
-               bnx2x_fw_dump(bp);
-               rc = 0;
-       }
-
-       return rc;
-}
-
 static void bnx2x_free_mem(struct bnx2x *bp)
 {
 
 #define BNX2X_PCI_FREE(x, y, size) \
        do { \
                if (x) { \
-                       pci_free_consistent(bp->pdev, size, x, y); \
+                       dma_free_coherent(&bp->pdev->dev, size, x, y); \
                        x = NULL; \
                        y = 0; \
                } \
@@ -6302,11 +7151,10 @@ static void bnx2x_free_mem(struct bnx2x *bp)
                /* status blocks */
                BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk),
                               bnx2x_fp(bp, i, status_blk_mapping),
-                              sizeof(struct host_status_block) +
-                              sizeof(struct eth_tx_db_data));
+                              sizeof(struct host_status_block));
        }
        /* Rx */
-       for_each_rx_queue(bp, i) {
+       for_each_queue(bp, i) {
 
                /* fastpath rx rings: rx_buf rx_desc rx_comp */
                BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring));
@@ -6326,13 +7174,13 @@ static void bnx2x_free_mem(struct bnx2x *bp)
                               BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
        }
        /* Tx */
-       for_each_tx_queue(bp, i) {
+       for_each_queue(bp, i) {
 
                /* fastpath tx rings: tx_buf tx_desc */
                BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring));
                BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring),
                               bnx2x_fp(bp, i, tx_desc_mapping),
-                              sizeof(struct eth_tx_bd) * NUM_TX_BD);
+                              sizeof(union eth_tx_bd_types) * NUM_TX_BD);
        }
        /* end of fastpath */
 
@@ -6342,11 +7190,13 @@ static void bnx2x_free_mem(struct bnx2x *bp)
        BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
                       sizeof(struct bnx2x_slowpath));
 
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
        BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024);
        BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024);
        BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024);
        BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024);
+       BNX2X_PCI_FREE(bp->cnic_sb, bp->cnic_sb_mapping,
+                      sizeof(struct host_status_block));
 #endif
        BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE);
 
@@ -6359,7 +7209,7 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
 
 #define BNX2X_PCI_ALLOC(x, y, size) \
        do { \
-               x = pci_alloc_consistent(bp->pdev, size, y); \
+               x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
                if (x == NULL) \
                        goto alloc_mem_err; \
                memset(x, 0, size); \
@@ -6383,11 +7233,10 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
                /* status blocks */
                BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk),
                                &bnx2x_fp(bp, i, status_blk_mapping),
-                               sizeof(struct host_status_block) +
-                               sizeof(struct eth_tx_db_data));
+                               sizeof(struct host_status_block));
        }
        /* Rx */
-       for_each_rx_queue(bp, i) {
+       for_each_queue(bp, i) {
 
                /* fastpath rx rings: rx_buf rx_desc rx_comp */
                BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring),
@@ -6409,21 +7258,14 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
                                BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
        }
        /* Tx */
-       for_each_tx_queue(bp, i) {
-
-               bnx2x_fp(bp, i, hw_tx_prods) =
-                               (void *)(bnx2x_fp(bp, i, status_blk) + 1);
-
-               bnx2x_fp(bp, i, tx_prods_mapping) =
-                               bnx2x_fp(bp, i, status_blk_mapping) +
-                               sizeof(struct host_status_block);
+       for_each_queue(bp, i) {
 
                /* fastpath tx rings: tx_buf tx_desc */
                BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring),
                                sizeof(struct sw_tx_bd) * NUM_TX_BD);
                BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring),
                                &bnx2x_fp(bp, i, tx_desc_mapping),
-                               sizeof(struct eth_tx_bd) * NUM_TX_BD);
+                               sizeof(union eth_tx_bd_types) * NUM_TX_BD);
        }
        /* end of fastpath */
 
@@ -6433,32 +7275,26 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
        BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
                        sizeof(struct bnx2x_slowpath));
 
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
        BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024);
 
-       /* Initialize T1 */
-       for (i = 0; i < 64*1024; i += 64) {
-               *(u64 *)((char *)bp->t1 + i + 56) = 0x0UL;
-               *(u64 *)((char *)bp->t1 + i + 3) = 0x0UL;
-       }
-
        /* allocate searcher T2 table
           we allocate 1/4 of alloc num for T2
          (which is not entered into the ILT) */
        BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024);
 
-       /* Initialize T2 */
+       /* Initialize T2 (for 1024 connections) */
        for (i = 0; i < 16*1024; i += 64)
-               * (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
-
-       /* now fixup the last line in the block to point to the next block */
-       *(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping;
+               *(u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
 
-       /* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */
+       /* Timer block array (8*MAX_CONN) phys uncached for now 1024 conns */
        BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024);
 
        /* QM queues (128*MAX_CONN) */
        BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024);
+
+       BNX2X_PCI_ALLOC(bp->cnic_sb, &bp->cnic_sb_mapping,
+                       sizeof(struct host_status_block));
 #endif
 
        /* Slow path ring */
@@ -6478,7 +7314,7 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
 {
        int i;
 
-       for_each_tx_queue(bp, i) {
+       for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
                u16 bd_cons = fp->tx_bd_cons;
@@ -6496,7 +7332,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
 {
        int i, j;
 
-       for_each_rx_queue(bp, j) {
+       for_each_queue(bp, j) {
                struct bnx2x_fastpath *fp = &bp->fp[j];
 
                for (i = 0; i < NUM_RX_BD; i++) {
@@ -6506,9 +7342,9 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
                        if (skb == NULL)
                                continue;
 
-                       pci_unmap_single(bp->pdev,
-                                        pci_unmap_addr(rx_buf, mapping),
-                                        bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+                       dma_unmap_single(&bp->pdev->dev,
+                                        dma_unmap_addr(rx_buf, mapping),
+                                        bp->rx_buf_size, DMA_FROM_DEVICE);
 
                        rx_buf->skb = NULL;
                        dev_kfree_skb(skb);
@@ -6534,6 +7370,9 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
        DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
           bp->msix_table[0].vector);
 
+#ifdef BCM_CNIC
+       offset++;
+#endif
        for_each_queue(bp, i) {
                DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq  "
                   "state %x\n", i, bp->msix_table[i + offset].vector,
@@ -6543,19 +7382,21 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
        }
 }
 
-static void bnx2x_free_irq(struct bnx2x *bp)
+static void bnx2x_free_irq(struct bnx2x *bp, bool disable_only)
 {
        if (bp->flags & USING_MSIX_FLAG) {
-               bnx2x_free_msix_irqs(bp);
+               if (!disable_only)
+                       bnx2x_free_msix_irqs(bp);
                pci_disable_msix(bp->pdev);
                bp->flags &= ~USING_MSIX_FLAG;
 
        } else if (bp->flags & USING_MSI_FLAG) {
-               free_irq(bp->pdev->irq, bp->dev);
+               if (!disable_only)
+                       free_irq(bp->pdev->irq, bp->dev);
                pci_disable_msi(bp->pdev);
                bp->flags &= ~USING_MSI_FLAG;
 
-       } else
+       } else if (!disable_only)
                free_irq(bp->pdev->irq, bp->dev);
 }
 
@@ -6567,6 +7408,12 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
        bp->msix_table[0].entry = igu_vec;
        DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_vec);
 
+#ifdef BCM_CNIC
+       igu_vec = BP_L_ID(bp) + offset;
+       bp->msix_table[1].entry = igu_vec;
+       DP(NETIF_MSG_IFUP, "msix_table[1].entry = %d (CNIC)\n", igu_vec);
+       offset++;
+#endif
        for_each_queue(bp, i) {
                igu_vec = BP_L_ID(bp) + offset + i;
                bp->msix_table[i + offset].entry = igu_vec;
@@ -6576,7 +7423,31 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
 
        rc = pci_enable_msix(bp->pdev, &bp->msix_table[0],
                             BNX2X_NUM_QUEUES(bp) + offset);
-       if (rc) {
+
+       /*
+        * reconfigure number of tx/rx queues according to available
+        * MSI-X vectors
+        */
+       if (rc >= BNX2X_MIN_MSIX_VEC_CNT) {
+               /* vectors available for FP */
+               int fp_vec = rc - BNX2X_MSIX_VEC_FP_START;
+
+               DP(NETIF_MSG_IFUP,
+                  "Trying to use less MSI-X vectors: %d\n", rc);
+
+               rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
+
+               if (rc) {
+                       DP(NETIF_MSG_IFUP,
+                          "MSI-X is not attainable  rc %d\n", rc);
+                       return rc;
+               }
+
+               bp->num_queues = min(bp->num_queues, fp_vec);
+
+               DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n",
+                                 bp->num_queues);
+       } else if (rc) {
                DP(NETIF_MSG_IFUP, "MSI-X is not attainable  rc %d\n", rc);
                return rc;
        }
@@ -6597,10 +7468,14 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
                return -EBUSY;
        }
 
+#ifdef BCM_CNIC
+       offset++;
+#endif
        for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
+               snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
+                        bp->dev->name, i);
 
-               sprintf(fp->name, "%s.fp%d", bp->dev->name, i);
                rc = request_irq(bp->msix_table[i + offset].vector,
                                 bnx2x_msix_fp_int, 0, fp->name, fp);
                if (rc) {
@@ -6613,16 +7488,11 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
        }
 
        i = BNX2X_NUM_QUEUES(bp);
-       if (is_multi(bp))
-               printk(KERN_INFO PFX
-                      "%s: using MSI-X  IRQs: sp %d  fp %d - %d\n",
-                      bp->dev->name, bp->msix_table[0].vector,
-                      bp->msix_table[offset].vector,
-                      bp->msix_table[offset + i - 1].vector);
-       else
-               printk(KERN_INFO PFX "%s: using MSI-X  IRQs: sp %d  fp %d\n",
-                      bp->dev->name, bp->msix_table[0].vector,
-                      bp->msix_table[offset + i - 1].vector);
+       netdev_info(bp->dev, "using MSI-X  IRQs: sp %d  fp[%d] %d"
+              " ... fp[%d] %d\n",
+              bp->msix_table[0].vector,
+              0, bp->msix_table[offset].vector,
+              i - 1, bp->msix_table[offset + i - 1].vector);
 
        return 0;
 }
@@ -6663,7 +7533,7 @@ static void bnx2x_napi_enable(struct bnx2x *bp)
 {
        int i;
 
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                napi_enable(&bnx2x_fp(bp, i, napi));
 }
 
@@ -6671,7 +7541,7 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
 {
        int i;
 
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                napi_disable(&bnx2x_fp(bp, i, napi));
 }
 
@@ -6697,14 +7567,25 @@ static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
        bnx2x_int_disable_sync(bp, disable_hw);
        bnx2x_napi_disable(bp);
        netif_tx_disable(bp->dev);
-       bp->dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 /*
  * Init service functions
  */
 
-static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
+/**
+ * Sets a MAC in a CAM for a few L2 Clients for E1 chip
+ *
+ * @param bp driver descriptor
+ * @param set set or clear an entry (1 or 0)
+ * @param mac pointer to a buffer containing a MAC
+ * @param cl_bit_vec bit vector of clients to register a MAC for
+ * @param cam_offset offset in a CAM to use
+ * @param with_bcast set broadcast MAC as well
+ */
+static void bnx2x_set_mac_addr_e1_gen(struct bnx2x *bp, int set, u8 *mac,
+                                     u32 cl_bit_vec, u8 cam_offset,
+                                     u8 with_bcast)
 {
        struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
        int port = BP_PORT(bp);
@@ -6713,24 +7594,25 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
         * unicasts 0-31:port0 32-63:port1
         * multicast 64-127:port0 128-191:port1
         */
-       config->hdr.length = 2;
-       config->hdr.offset = port ? 32 : 0;
-       config->hdr.client_id = bp->fp->cl_id;
+       config->hdr.length = 1 + (with_bcast ? 1 : 0);
+       config->hdr.offset = cam_offset;
+       config->hdr.client_id = 0xff;
        config->hdr.reserved1 = 0;
 
        /* primary MAC */
        config->config_table[0].cam_entry.msb_mac_addr =
-                                       swab16(*(u16 *)&bp->dev->dev_addr[0]);
+                                       swab16(*(u16 *)&mac[0]);
        config->config_table[0].cam_entry.middle_mac_addr =
-                                       swab16(*(u16 *)&bp->dev->dev_addr[2]);
+                                       swab16(*(u16 *)&mac[2]);
        config->config_table[0].cam_entry.lsb_mac_addr =
-                                       swab16(*(u16 *)&bp->dev->dev_addr[4]);
+                                       swab16(*(u16 *)&mac[4]);
        config->config_table[0].cam_entry.flags = cpu_to_le16(port);
        if (set)
                config->config_table[0].target_table_entry.flags = 0;
        else
                CAM_INVALIDATE(config->config_table[0]);
-       config->config_table[0].target_table_entry.client_id = 0;
+       config->config_table[0].target_table_entry.clients_bit_vector =
+                                               cpu_to_le32(cl_bit_vec);
        config->config_table[0].target_table_entry.vlan_id = 0;
 
        DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n",
@@ -6740,50 +7622,58 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
           config->config_table[0].cam_entry.lsb_mac_addr);
 
        /* broadcast */
-       config->config_table[1].cam_entry.msb_mac_addr = cpu_to_le16(0xffff);
-       config->config_table[1].cam_entry.middle_mac_addr = cpu_to_le16(0xffff);
-       config->config_table[1].cam_entry.lsb_mac_addr = cpu_to_le16(0xffff);
-       config->config_table[1].cam_entry.flags = cpu_to_le16(port);
-       if (set)
-               config->config_table[1].target_table_entry.flags =
-                               TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
-       else
-               CAM_INVALIDATE(config->config_table[1]);
-       config->config_table[1].target_table_entry.client_id = 0;
-       config->config_table[1].target_table_entry.vlan_id = 0;
+       if (with_bcast) {
+               config->config_table[1].cam_entry.msb_mac_addr =
+                       cpu_to_le16(0xffff);
+               config->config_table[1].cam_entry.middle_mac_addr =
+                       cpu_to_le16(0xffff);
+               config->config_table[1].cam_entry.lsb_mac_addr =
+                       cpu_to_le16(0xffff);
+               config->config_table[1].cam_entry.flags = cpu_to_le16(port);
+               if (set)
+                       config->config_table[1].target_table_entry.flags =
+                                       TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
+               else
+                       CAM_INVALIDATE(config->config_table[1]);
+               config->config_table[1].target_table_entry.clients_bit_vector =
+                                                       cpu_to_le32(cl_bit_vec);
+               config->config_table[1].target_table_entry.vlan_id = 0;
+       }
 
        bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
                      U64_HI(bnx2x_sp_mapping(bp, mac_config)),
                      U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
 }
 
-static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set)
+/**
+ * Sets a MAC in a CAM for a few L2 Clients for E1H chip
+ *
+ * @param bp driver descriptor
+ * @param set set or clear an entry (1 or 0)
+ * @param mac pointer to a buffer containing a MAC
+ * @param cl_bit_vec bit vector of clients to register a MAC for
+ * @param cam_offset offset in a CAM to use
+ */
+static void bnx2x_set_mac_addr_e1h_gen(struct bnx2x *bp, int set, u8 *mac,
+                                      u32 cl_bit_vec, u8 cam_offset)
 {
        struct mac_configuration_cmd_e1h *config =
                (struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config);
 
-       if (set && (bp->state != BNX2X_STATE_OPEN)) {
-               DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
-               return;
-       }
-
-       /* CAM allocation for E1H
-        * unicasts: by func number
-        * multicast: 20+FUNC*20, 20 each
-        */
        config->hdr.length = 1;
-       config->hdr.offset = BP_FUNC(bp);
-       config->hdr.client_id = bp->fp->cl_id;
+       config->hdr.offset = cam_offset;
+       config->hdr.client_id = 0xff;
        config->hdr.reserved1 = 0;
 
        /* primary MAC */
        config->config_table[0].msb_mac_addr =
-                                       swab16(*(u16 *)&bp->dev->dev_addr[0]);
+                                       swab16(*(u16 *)&mac[0]);
        config->config_table[0].middle_mac_addr =
-                                       swab16(*(u16 *)&bp->dev->dev_addr[2]);
+                                       swab16(*(u16 *)&mac[2]);
        config->config_table[0].lsb_mac_addr =
-                                       swab16(*(u16 *)&bp->dev->dev_addr[4]);
-       config->config_table[0].client_id = BP_L_ID(bp);
+                                       swab16(*(u16 *)&mac[4]);
+       config->config_table[0].clients_bit_vector =
+                                       cpu_to_le32(cl_bit_vec);
        config->config_table[0].vlan_id = 0;
        config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov);
        if (set)
@@ -6792,11 +7682,11 @@ static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set)
                config->config_table[0].flags =
                                MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE;
 
-       DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)  E1HOV %d  CLID %d\n",
+       DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)  E1HOV %d  CLID mask %d\n",
           (set ? "setting" : "clearing"),
           config->config_table[0].msb_mac_addr,
           config->config_table[0].middle_mac_addr,
-          config->config_table[0].lsb_mac_addr, bp->e1hov, BP_L_ID(bp));
+          config->config_table[0].lsb_mac_addr, bp->e1hov, cl_bit_vec);
 
        bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
                      U64_HI(bnx2x_sp_mapping(bp, mac_config)),
@@ -6833,6 +7723,9 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
                }
 
                msleep(1);
+
+               if (bp->panic)
+                       return -EIO;
        }
 
        /* timeout! */
@@ -6845,6 +7738,69 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
        return -EBUSY;
 }
 
+static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
+{
+       bp->set_mac_pending++;
+       smp_wmb();
+
+       bnx2x_set_mac_addr_e1h_gen(bp, set, bp->dev->dev_addr,
+                                  (1 << bp->fp->cl_id), BP_FUNC(bp));
+
+       /* Wait for a completion */
+       bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
+static void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
+{
+       bp->set_mac_pending++;
+       smp_wmb();
+
+       bnx2x_set_mac_addr_e1_gen(bp, set, bp->dev->dev_addr,
+                                 (1 << bp->fp->cl_id), (BP_PORT(bp) ? 32 : 0),
+                                 1);
+
+       /* Wait for a completion */
+       bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
+#ifdef BCM_CNIC
+/**
+ * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
+ * MAC(s). This function will wait until the ramdord completion
+ * returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
+{
+       u32 cl_bit_vec = (1 << BCM_ISCSI_ETH_CL_ID);
+
+       bp->set_mac_pending++;
+       smp_wmb();
+
+       /* Send a SET_MAC ramrod */
+       if (CHIP_IS_E1(bp))
+               bnx2x_set_mac_addr_e1_gen(bp, set, bp->iscsi_mac,
+                                 cl_bit_vec, (BP_PORT(bp) ? 32 : 0) + 2,
+                                 1);
+       else
+               /* CAM allocation for E1H
+               * unicasts: by func number
+               * multicast: 20+FUNC*20, 20 each
+               */
+               bnx2x_set_mac_addr_e1h_gen(bp, set, bp->iscsi_mac,
+                                  cl_bit_vec, E1H_FUNC_MAX + BP_FUNC(bp));
+
+       /* Wait for a completion when setting */
+       bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+
+       return 0;
+}
+#endif
+
 static int bnx2x_setup_leading(struct bnx2x *bp)
 {
        int rc;
@@ -6880,113 +7836,118 @@ static int bnx2x_setup_multi(struct bnx2x *bp, int index)
 
 static int bnx2x_poll(struct napi_struct *napi, int budget);
 
-static void bnx2x_set_int_mode(struct bnx2x *bp)
+static void bnx2x_set_num_queues_msix(struct bnx2x *bp)
+{
+
+       switch (bp->multi_mode) {
+       case ETH_RSS_MODE_DISABLED:
+               bp->num_queues = 1;
+               break;
+
+       case ETH_RSS_MODE_REGULAR:
+               if (num_queues)
+                       bp->num_queues = min_t(u32, num_queues,
+                                                 BNX2X_MAX_QUEUES(bp));
+               else
+                       bp->num_queues = min_t(u32, num_online_cpus(),
+                                                 BNX2X_MAX_QUEUES(bp));
+               break;
+
+
+       default:
+               bp->num_queues = 1;
+               break;
+       }
+}
+
+static int bnx2x_set_num_queues(struct bnx2x *bp)
 {
-       int num_queues;
+       int rc = 0;
 
        switch (int_mode) {
        case INT_MODE_INTx:
        case INT_MODE_MSI:
-               num_queues = 1;
-               bp->num_rx_queues = num_queues;
-               bp->num_tx_queues = num_queues;
-               DP(NETIF_MSG_IFUP,
-                  "set number of queues to %d\n", num_queues);
+               bp->num_queues = 1;
+               DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
                break;
-
-       case INT_MODE_MSIX:
        default:
-               if (bp->multi_mode == ETH_RSS_MODE_REGULAR)
-                       num_queues = min_t(u32, num_online_cpus(),
-                                          BNX2X_MAX_QUEUES(bp));
-               else
-                       num_queues = 1;
-               bp->num_rx_queues = num_queues;
-               bp->num_tx_queues = num_queues;
-               DP(NETIF_MSG_IFUP, "set number of rx queues to %d"
-                  "  number of tx queues to %d\n",
-                  bp->num_rx_queues, bp->num_tx_queues);
+               /* Set number of queues according to bp->multi_mode value */
+               bnx2x_set_num_queues_msix(bp);
+
+               DP(NETIF_MSG_IFUP, "set number of queues to %d\n",
+                  bp->num_queues);
+
                /* if we can't use MSI-X we only need one fp,
                 * so try to enable MSI-X with the requested number of fp's
                 * and fallback to MSI or legacy INTx with one fp
                 */
-               if (bnx2x_enable_msix(bp)) {
+               rc = bnx2x_enable_msix(bp);
+               if (rc)
                        /* failed to enable MSI-X */
-                       num_queues = 1;
-                       bp->num_rx_queues = num_queues;
-                       bp->num_tx_queues = num_queues;
-                       if (bp->multi_mode)
-                               BNX2X_ERR("Multi requested but failed to "
-                                         "enable MSI-X  set number of "
-                                         "queues to %d\n", num_queues);
-               }
+                       bp->num_queues = 1;
                break;
        }
-       bp->dev->real_num_tx_queues = bp->num_tx_queues;
+       bp->dev->real_num_tx_queues = bp->num_queues;
+       return rc;
 }
 
-static void bnx2x_set_rx_mode(struct net_device *dev);
+#ifdef BCM_CNIC
+static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
+static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
+#endif
 
 /* must be called with rtnl_lock */
 static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 {
        u32 load_code;
-       int i, rc = 0;
+       int i, rc;
+
 #ifdef BNX2X_STOP_ON_ERROR
-       DP(NETIF_MSG_IFUP, "enter  load_mode %d\n", load_mode);
        if (unlikely(bp->panic))
                return -EPERM;
 #endif
 
        bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
 
-       bnx2x_set_int_mode(bp);
+       rc = bnx2x_set_num_queues(bp);
 
-       if (bnx2x_alloc_mem(bp))
+       if (bnx2x_alloc_mem(bp)) {
+               bnx2x_free_irq(bp, true);
                return -ENOMEM;
+       }
 
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                bnx2x_fp(bp, i, disable_tpa) =
                                        ((bp->flags & TPA_ENABLE_FLAG) == 0);
 
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
                               bnx2x_poll, 128);
 
-#ifdef BNX2X_STOP_ON_ERROR
-       for_each_rx_queue(bp, i) {
-               struct bnx2x_fastpath *fp = &bp->fp[i];
-
-               fp->poll_no_work = 0;
-               fp->poll_calls = 0;
-               fp->poll_max_calls = 0;
-               fp->poll_complete = 0;
-               fp->poll_exit = 0;
-       }
-#endif
        bnx2x_napi_enable(bp);
 
        if (bp->flags & USING_MSIX_FLAG) {
                rc = bnx2x_req_msix_irqs(bp);
                if (rc) {
-                       pci_disable_msix(bp->pdev);
+                       bnx2x_free_irq(bp, true);
                        goto load_error1;
                }
        } else {
+               /* Fall to INTx if failed to enable MSI-X due to lack of
+                  memory (in bnx2x_set_num_queues()) */
                if ((rc != -ENOMEM) && (int_mode != INT_MODE_INTx))
                        bnx2x_enable_msi(bp);
                bnx2x_ack_int(bp);
                rc = bnx2x_req_irq(bp);
                if (rc) {
                        BNX2X_ERR("IRQ request failed  rc %d, aborting\n", rc);
-                       if (bp->flags & USING_MSI_FLAG)
-                               pci_disable_msi(bp->pdev);
+                       bnx2x_free_irq(bp, true);
                        goto load_error1;
                }
                if (bp->flags & USING_MSI_FLAG) {
                        bp->dev->irq = bp->pdev->irq;
-                       printk(KERN_INFO PFX "%s: using MSI  IRQ %d\n",
-                              bp->dev->name, bp->pdev->irq);
+                       netdev_info(bp->dev, "using MSI  IRQ %d\n",
+                                   bp->pdev->irq);
                }
        }
 
@@ -7035,12 +7996,21 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        rc = bnx2x_init_hw(bp, load_code);
        if (rc) {
                BNX2X_ERR("HW init failed, aborting\n");
+               bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP);
+               bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
                goto load_error2;
        }
 
        /* Setup NIC internals and enable interrupts */
        bnx2x_nic_init(bp, load_code);
 
+       if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) &&
+           (bp->common.shmem2_base))
+               SHMEM2_WR(bp, dcc_support,
+                         (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV |
+                          SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV));
+
        /* Send LOAD_DONE command to MCP */
        if (!BP_NOMCP(bp)) {
                load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
@@ -7056,26 +8026,51 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        rc = bnx2x_setup_leading(bp);
        if (rc) {
                BNX2X_ERR("Setup leading failed!\n");
+#ifndef BNX2X_STOP_ON_ERROR
                goto load_error3;
+#else
+               bp->panic = 1;
+               return -EBUSY;
+#endif
        }
 
        if (CHIP_IS_E1H(bp))
                if (bp->mf_config & FUNC_MF_CFG_FUNC_DISABLED) {
                        DP(NETIF_MSG_IFUP, "mf_cfg function disabled\n");
-                       bp->state = BNX2X_STATE_DISABLED;
+                       bp->flags |= MF_FUNC_DIS;
                }
 
-       if (bp->state == BNX2X_STATE_OPEN)
+       if (bp->state == BNX2X_STATE_OPEN) {
+#ifdef BCM_CNIC
+               /* Enable Timer scan */
+               REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
+#endif
                for_each_nondefault_queue(bp, i) {
                        rc = bnx2x_setup_multi(bp, i);
                        if (rc)
+#ifdef BCM_CNIC
+                               goto load_error4;
+#else
                                goto load_error3;
+#endif
                }
 
-       if (CHIP_IS_E1(bp))
-               bnx2x_set_mac_addr_e1(bp, 1);
-       else
-               bnx2x_set_mac_addr_e1h(bp, 1);
+               if (CHIP_IS_E1(bp))
+                       bnx2x_set_eth_mac_addr_e1(bp, 1);
+               else
+                       bnx2x_set_eth_mac_addr_e1h(bp, 1);
+#ifdef BCM_CNIC
+               /* Set iSCSI L2 MAC */
+               mutex_lock(&bp->cnic_mutex);
+               if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) {
+                       bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+                       bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+                       bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping,
+                                     CNIC_SB_ID(bp));
+               }
+               mutex_unlock(&bp->cnic_mutex);
+#endif
+       }
 
        if (bp->port.pmf)
                bnx2x_initial_phy_init(bp, load_mode);
@@ -7083,14 +8078,18 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        /* Start fast path */
        switch (load_mode) {
        case LOAD_NORMAL:
-               /* Tx queue should be only reenabled */
-               netif_tx_wake_all_queues(bp->dev);
+               if (bp->state == BNX2X_STATE_OPEN) {
+                       /* Tx queue should be only reenabled */
+                       netif_tx_wake_all_queues(bp->dev);
+               }
                /* Initialize the receive filter. */
                bnx2x_set_rx_mode(bp->dev);
                break;
 
        case LOAD_OPEN:
                netif_tx_start_all_queues(bp->dev);
+               if (bp->state != BNX2X_STATE_OPEN)
+                       netif_tx_disable(bp->dev);
                /* Initialize the receive filter. */
                bnx2x_set_rx_mode(bp->dev);
                break;
@@ -7111,9 +8110,20 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        /* start the timer */
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 
+#ifdef BCM_CNIC
+       bnx2x_setup_cnic_irq_info(bp);
+       if (bp->state == BNX2X_STATE_OPEN)
+               bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
+#endif
+       bnx2x_inc_load_cnt(bp);
 
        return 0;
 
+#ifdef BCM_CNIC
+load_error4:
+       /* Disable Timer scan */
+       REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 0);
+#endif
 load_error3:
        bnx2x_int_disable_sync(bp, 1);
        if (!BP_NOMCP(bp)) {
@@ -7123,14 +8133,14 @@ load_error3:
        bp->port.pmf = 0;
        /* Free SKBs, SGEs, TPA pool and driver internals */
        bnx2x_free_skbs(bp);
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
 load_error2:
        /* Release IRQs */
-       bnx2x_free_irq(bp);
+       bnx2x_free_irq(bp, false);
 load_error1:
        bnx2x_napi_disable(bp);
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                netif_napi_del(&bnx2x_fp(bp, i, napi));
        bnx2x_free_mem(bp);
 
@@ -7221,6 +8231,19 @@ static void bnx2x_reset_func(struct bnx2x *bp)
        REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
        REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
 
+#ifdef BCM_CNIC
+       /* Disable Timer scan */
+       REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0);
+       /*
+        * Wait for at least 10ms and up to 2 second for the timers scan to
+        * complete
+        */
+       for (i = 0; i < 200; i++) {
+               msleep(10);
+               if (!REG_RD(bp, TM_REG_LIN0_SCAN_ON + port*4))
+                       break;
+       }
+#endif
        /* Clear ILT */
        base = FUNC_ILT_BASE(func);
        for (i = base; i < base + ILT_PER_FUNC; i++)
@@ -7280,30 +8303,14 @@ static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
        }
 }
 
-/* must be called with rtnl_lock */
-static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
+static void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
 {
        int port = BP_PORT(bp);
        u32 reset_code = 0;
        int i, cnt, rc;
 
-       bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
-
-       bp->rx_mode = BNX2X_RX_MODE_NONE;
-       bnx2x_set_storm_rx_mode(bp);
-
-       bnx2x_netif_stop(bp, 1);
-
-       del_timer_sync(&bp->timer);
-       SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
-                (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
-       bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-       /* Release IRQs */
-       bnx2x_free_irq(bp);
-
        /* Wait until tx fastpath tasks complete */
-       for_each_tx_queue(bp, i) {
+       for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
                cnt = 1000;
@@ -7331,7 +8338,7 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
                struct mac_configuration_cmd *config =
                                                bnx2x_sp(bp, mcast_config);
 
-               bnx2x_set_mac_addr_e1(bp, 0);
+               bnx2x_set_eth_mac_addr_e1(bp, 0);
 
                for (i = 0; i < config->hdr.length; i++)
                        CAM_INVALIDATE(config->config_table[i]);
@@ -7344,6 +8351,9 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
                config->hdr.client_id = bp->fp->cl_id;
                config->hdr.reserved1 = 0;
 
+               bp->set_mac_pending++;
+               smp_wmb();
+
                bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
                              U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
                              U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0);
@@ -7351,13 +8361,22 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
        } else { /* E1H */
                REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
 
-               bnx2x_set_mac_addr_e1h(bp, 0);
+               bnx2x_set_eth_mac_addr_e1h(bp, 0);
 
                for (i = 0; i < MC_HASH_SIZE; i++)
                        REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
 
                REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
        }
+#ifdef BCM_CNIC
+       /* Clear iSCSI L2 MAC */
+       mutex_lock(&bp->cnic_mutex);
+       if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+               bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+               bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+       }
+       mutex_unlock(&bp->cnic_mutex);
+#endif
 
        if (unload_mode == UNLOAD_NORMAL)
                reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
@@ -7430,31 +8449,524 @@ unload_error:
        if (!BP_NOMCP(bp))
                bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
 
+}
+
+static inline void bnx2x_disable_close_the_gate(struct bnx2x *bp)
+{
+       u32 val;
+
+       DP(NETIF_MSG_HW, "Disabling \"close the gates\"\n");
+
+       if (CHIP_IS_E1(bp)) {
+               int port = BP_PORT(bp);
+               u32 addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+                       MISC_REG_AEU_MASK_ATTN_FUNC_0;
+
+               val = REG_RD(bp, addr);
+               val &= ~(0x300);
+               REG_WR(bp, addr, val);
+       } else if (CHIP_IS_E1H(bp)) {
+               val = REG_RD(bp, MISC_REG_AEU_GENERAL_MASK);
+               val &= ~(MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK |
+                        MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK);
+               REG_WR(bp, MISC_REG_AEU_GENERAL_MASK, val);
+       }
+}
+
+/* must be called with rtnl_lock */
+static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
+{
+       int i;
+
+       if (bp->state == BNX2X_STATE_CLOSED) {
+               /* Interface has been removed - nothing to recover */
+               bp->recovery_state = BNX2X_RECOVERY_DONE;
+               bp->is_leader = 0;
+               bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
+               smp_wmb();
+
+               return -EINVAL;
+       }
+
+#ifdef BCM_CNIC
+       bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
+#endif
+       bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
+
+       /* Set "drop all" */
+       bp->rx_mode = BNX2X_RX_MODE_NONE;
+       bnx2x_set_storm_rx_mode(bp);
+
+       /* Disable HW interrupts, NAPI and Tx */
+       bnx2x_netif_stop(bp, 1);
+       netif_carrier_off(bp->dev);
+
+       del_timer_sync(&bp->timer);
+       SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
+                (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
+       bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+       /* Release IRQs */
+       bnx2x_free_irq(bp, false);
+
+       /* Cleanup the chip if needed */
+       if (unload_mode != UNLOAD_RECOVERY)
+               bnx2x_chip_cleanup(bp, unload_mode);
+
        bp->port.pmf = 0;
 
        /* Free SKBs, SGEs, TPA pool and driver internals */
        bnx2x_free_skbs(bp);
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                netif_napi_del(&bnx2x_fp(bp, i, napi));
        bnx2x_free_mem(bp);
 
        bp->state = BNX2X_STATE_CLOSED;
 
-       netif_carrier_off(bp->dev);
+       /* The last driver must disable a "close the gate" if there is no
+        * parity attention or "process kill" pending.
+        */
+       if ((!bnx2x_dec_load_cnt(bp)) && (!bnx2x_chk_parity_attn(bp)) &&
+           bnx2x_reset_is_done(bp))
+               bnx2x_disable_close_the_gate(bp);
+
+       /* Reset MCP mail box sequence if there is on going recovery */
+       if (unload_mode == UNLOAD_RECOVERY)
+               bp->fw_seq = 0;
+
+       return 0;
+}
+
+/* Close gates #2, #3 and #4: */
+static void bnx2x_set_234_gates(struct bnx2x *bp, bool close)
+{
+       u32 val, addr;
+
+       /* Gates #2 and #4a are closed/opened for "not E1" only */
+       if (!CHIP_IS_E1(bp)) {
+               /* #4 */
+               val = REG_RD(bp, PXP_REG_HST_DISCARD_DOORBELLS);
+               REG_WR(bp, PXP_REG_HST_DISCARD_DOORBELLS,
+                      close ? (val | 0x1) : (val & (~(u32)1)));
+               /* #2 */
+               val = REG_RD(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES);
+               REG_WR(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES,
+                      close ? (val | 0x1) : (val & (~(u32)1)));
+       }
+
+       /* #3 */
+       addr = BP_PORT(bp) ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+       val = REG_RD(bp, addr);
+       REG_WR(bp, addr, (!close) ? (val | 0x1) : (val & (~(u32)1)));
+
+       DP(NETIF_MSG_HW, "%s gates #2, #3 and #4\n",
+               close ? "closing" : "opening");
+       mmiowb();
+}
+
+#define SHARED_MF_CLP_MAGIC  0x80000000 /* `magic' bit */
+
+static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val)
+{
+       /* Do some magic... */
+       u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
+       *magic_val = val & SHARED_MF_CLP_MAGIC;
+       MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC);
+}
+
+/* Restore the value of the `magic' bit.
+ *
+ * @param pdev Device handle.
+ * @param magic_val Old value of the `magic' bit.
+ */
+static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val)
+{
+       /* Restore the `magic' bit value... */
+       /* u32 val = SHMEM_RD(bp, mf_cfg.shared_mf_config.clp_mb);
+       SHMEM_WR(bp, mf_cfg.shared_mf_config.clp_mb,
+               (val & (~SHARED_MF_CLP_MAGIC)) | magic_val); */
+       u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
+       MF_CFG_WR(bp, shared_mf_config.clp_mb,
+               (val & (~SHARED_MF_CLP_MAGIC)) | magic_val);
+}
+
+/* Prepares for MCP reset: takes care of CLP configurations.
+ *
+ * @param bp
+ * @param magic_val Old value of 'magic' bit.
+ */
+static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val)
+{
+       u32 shmem;
+       u32 validity_offset;
+
+       DP(NETIF_MSG_HW, "Starting\n");
+
+       /* Set `magic' bit in order to save MF config */
+       if (!CHIP_IS_E1(bp))
+               bnx2x_clp_reset_prep(bp, magic_val);
+
+       /* Get shmem offset */
+       shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+       validity_offset = offsetof(struct shmem_region, validity_map[0]);
+
+       /* Clear validity map flags */
+       if (shmem > 0)
+               REG_WR(bp, shmem + validity_offset, 0);
+}
+
+#define MCP_TIMEOUT      5000   /* 5 seconds (in ms) */
+#define MCP_ONE_TIMEOUT  100    /* 100 ms */
+
+/* Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10,
+ * depending on the HW type.
+ *
+ * @param bp
+ */
+static inline void bnx2x_mcp_wait_one(struct bnx2x *bp)
+{
+       /* special handling for emulation and FPGA,
+          wait 10 times longer */
+       if (CHIP_REV_IS_SLOW(bp))
+               msleep(MCP_ONE_TIMEOUT*10);
+       else
+               msleep(MCP_ONE_TIMEOUT);
+}
+
+static int bnx2x_reset_mcp_comp(struct bnx2x *bp, u32 magic_val)
+{
+       u32 shmem, cnt, validity_offset, val;
+       int rc = 0;
+
+       msleep(100);
+
+       /* Get shmem offset */
+       shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+       if (shmem == 0) {
+               BNX2X_ERR("Shmem 0 return failure\n");
+               rc = -ENOTTY;
+               goto exit_lbl;
+       }
+
+       validity_offset = offsetof(struct shmem_region, validity_map[0]);
+
+       /* Wait for MCP to come up */
+       for (cnt = 0; cnt < (MCP_TIMEOUT / MCP_ONE_TIMEOUT); cnt++) {
+               /* TBD: its best to check validity map of last port.
+                * currently checks on port 0.
+                */
+               val = REG_RD(bp, shmem + validity_offset);
+               DP(NETIF_MSG_HW, "shmem 0x%x validity map(0x%x)=0x%x\n", shmem,
+                  shmem + validity_offset, val);
+
+               /* check that shared memory is valid. */
+               if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+                   == (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+                       break;
+
+               bnx2x_mcp_wait_one(bp);
+       }
+
+       DP(NETIF_MSG_HW, "Cnt=%d Shmem validity map 0x%x\n", cnt, val);
+
+       /* Check that shared memory is valid. This indicates that MCP is up. */
+       if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) !=
+           (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) {
+               BNX2X_ERR("Shmem signature not present. MCP is not up !!\n");
+               rc = -ENOTTY;
+               goto exit_lbl;
+       }
+
+exit_lbl:
+       /* Restore the `magic' bit value */
+       if (!CHIP_IS_E1(bp))
+               bnx2x_clp_reset_done(bp, magic_val);
+
+       return rc;
+}
+
+static void bnx2x_pxp_prep(struct bnx2x *bp)
+{
+       if (!CHIP_IS_E1(bp)) {
+               REG_WR(bp, PXP2_REG_RD_START_INIT, 0);
+               REG_WR(bp, PXP2_REG_RQ_RBC_DONE, 0);
+               REG_WR(bp, PXP2_REG_RQ_CFG_DONE, 0);
+               mmiowb();
+       }
+}
+
+/*
+ * Reset the whole chip except for:
+ *      - PCIE core
+ *      - PCI Glue, PSWHST, PXP/PXP2 RF (all controlled by
+ *              one reset bit)
+ *      - IGU
+ *      - MISC (including AEU)
+ *      - GRC
+ *      - RBCN, RBCP
+ */
+static void bnx2x_process_kill_chip_reset(struct bnx2x *bp)
+{
+       u32 not_reset_mask1, reset_mask1, not_reset_mask2, reset_mask2;
+
+       not_reset_mask1 =
+               MISC_REGISTERS_RESET_REG_1_RST_HC |
+               MISC_REGISTERS_RESET_REG_1_RST_PXPV |
+               MISC_REGISTERS_RESET_REG_1_RST_PXP;
+
+       not_reset_mask2 =
+               MISC_REGISTERS_RESET_REG_2_RST_MDIO |
+               MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_RBCN |
+               MISC_REGISTERS_RESET_REG_2_RST_GRC  |
+               MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B;
+
+       reset_mask1 = 0xffffffff;
+
+       if (CHIP_IS_E1(bp))
+               reset_mask2 = 0xffff;
+       else
+               reset_mask2 = 0x1ffff;
+
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+              reset_mask1 & (~not_reset_mask1));
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+              reset_mask2 & (~not_reset_mask2));
+
+       barrier();
+       mmiowb();
+
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, reset_mask1);
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, reset_mask2);
+       mmiowb();
+}
+
+static int bnx2x_process_kill(struct bnx2x *bp)
+{
+       int cnt = 1000;
+       u32 val = 0;
+       u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2;
+
+
+       /* Empty the Tetris buffer, wait for 1s */
+       do {
+               sr_cnt  = REG_RD(bp, PXP2_REG_RD_SR_CNT);
+               blk_cnt = REG_RD(bp, PXP2_REG_RD_BLK_CNT);
+               port_is_idle_0 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_0);
+               port_is_idle_1 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_1);
+               pgl_exp_rom2 = REG_RD(bp, PXP2_REG_PGL_EXP_ROM2);
+               if ((sr_cnt == 0x7e) && (blk_cnt == 0xa0) &&
+                   ((port_is_idle_0 & 0x1) == 0x1) &&
+                   ((port_is_idle_1 & 0x1) == 0x1) &&
+                   (pgl_exp_rom2 == 0xffffffff))
+                       break;
+               msleep(1);
+       } while (cnt-- > 0);
+
+       if (cnt <= 0) {
+               DP(NETIF_MSG_HW, "Tetris buffer didn't get empty or there"
+                         " are still"
+                         " outstanding read requests after 1s!\n");
+               DP(NETIF_MSG_HW, "sr_cnt=0x%08x, blk_cnt=0x%08x,"
+                         " port_is_idle_0=0x%08x,"
+                         " port_is_idle_1=0x%08x, pgl_exp_rom2=0x%08x\n",
+                         sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1,
+                         pgl_exp_rom2);
+               return -EAGAIN;
+       }
+
+       barrier();
+
+       /* Close gates #2, #3 and #4 */
+       bnx2x_set_234_gates(bp, true);
+
+       /* TBD: Indicate that "process kill" is in progress to MCP */
+
+       /* Clear "unprepared" bit */
+       REG_WR(bp, MISC_REG_UNPREPARED, 0);
+       barrier();
+
+       /* Make sure all is written to the chip before the reset */
+       mmiowb();
+
+       /* Wait for 1ms to empty GLUE and PCI-E core queues,
+        * PSWHST, GRC and PSWRD Tetris buffer.
+        */
+       msleep(1);
+
+       /* Prepare to chip reset: */
+       /* MCP */
+       bnx2x_reset_mcp_prep(bp, &val);
+
+       /* PXP */
+       bnx2x_pxp_prep(bp);
+       barrier();
+
+       /* reset the chip */
+       bnx2x_process_kill_chip_reset(bp);
+       barrier();
+
+       /* Recover after reset: */
+       /* MCP */
+       if (bnx2x_reset_mcp_comp(bp, val))
+               return -EAGAIN;
+
+       /* PXP */
+       bnx2x_pxp_prep(bp);
+
+       /* Open the gates #2, #3 and #4 */
+       bnx2x_set_234_gates(bp, false);
+
+       /* TBD: IGU/AEU preparation bring back the AEU/IGU to a
+        * reset state, re-enable attentions. */
+
+       return 0;
+}
+
+static int bnx2x_leader_reset(struct bnx2x *bp)
+{
+       int rc = 0;
+       /* Try to recover after the failure */
+       if (bnx2x_process_kill(bp)) {
+               printk(KERN_ERR "%s: Something bad had happen! Aii!\n",
+                      bp->dev->name);
+               rc = -EAGAIN;
+               goto exit_leader_reset;
+       }
+
+       /* Clear "reset is in progress" bit and update the driver state */
+       bnx2x_set_reset_done(bp);
+       bp->recovery_state = BNX2X_RECOVERY_DONE;
+
+exit_leader_reset:
+       bp->is_leader = 0;
+       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
+       smp_wmb();
+       return rc;
+}
+
+static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
+
+/* Assumption: runs under rtnl lock. This together with the fact
+ * that it's called only from bnx2x_reset_task() ensure that it
+ * will never be called when netif_running(bp->dev) is false.
+ */
+static void bnx2x_parity_recover(struct bnx2x *bp)
+{
+       DP(NETIF_MSG_HW, "Handling parity\n");
+       while (1) {
+               switch (bp->recovery_state) {
+               case BNX2X_RECOVERY_INIT:
+                       DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_INIT\n");
+                       /* Try to get a LEADER_LOCK HW lock */
+                       if (bnx2x_trylock_hw_lock(bp,
+                               HW_LOCK_RESOURCE_RESERVED_08))
+                               bp->is_leader = 1;
+
+                       /* Stop the driver */
+                       /* If interface has been removed - break */
+                       if (bnx2x_nic_unload(bp, UNLOAD_RECOVERY))
+                               return;
+
+                       bp->recovery_state = BNX2X_RECOVERY_WAIT;
+                       /* Ensure "is_leader" and "recovery_state"
+                        *  update values are seen on other CPUs
+                        */
+                       smp_wmb();
+                       break;
+
+               case BNX2X_RECOVERY_WAIT:
+                       DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_WAIT\n");
+                       if (bp->is_leader) {
+                               u32 load_counter = bnx2x_get_load_cnt(bp);
+                               if (load_counter) {
+                                       /* Wait until all other functions get
+                                        * down.
+                                        */
+                                       schedule_delayed_work(&bp->reset_task,
+                                                               HZ/10);
+                                       return;
+                               } else {
+                                       /* If all other functions got down -
+                                        * try to bring the chip back to
+                                        * normal. In any case it's an exit
+                                        * point for a leader.
+                                        */
+                                       if (bnx2x_leader_reset(bp) ||
+                                       bnx2x_nic_load(bp, LOAD_NORMAL)) {
+                                               printk(KERN_ERR"%s: Recovery "
+                                               "has failed. Power cycle is "
+                                               "needed.\n", bp->dev->name);
+                                               /* Disconnect this device */
+                                               netif_device_detach(bp->dev);
+                                               /* Block ifup for all function
+                                                * of this ASIC until
+                                                * "process kill" or power
+                                                * cycle.
+                                                */
+                                               bnx2x_set_reset_in_progress(bp);
+                                               /* Shut down the power */
+                                               bnx2x_set_power_state(bp,
+                                                               PCI_D3hot);
+                                               return;
+                                       }
+
+                                       return;
+                               }
+                       } else { /* non-leader */
+                               if (!bnx2x_reset_is_done(bp)) {
+                                       /* Try to get a LEADER_LOCK HW lock as
+                                        * long as a former leader may have
+                                        * been unloaded by the user or
+                                        * released a leadership by another
+                                        * reason.
+                                        */
+                                       if (bnx2x_trylock_hw_lock(bp,
+                                           HW_LOCK_RESOURCE_RESERVED_08)) {
+                                               /* I'm a leader now! Restart a
+                                                * switch case.
+                                                */
+                                               bp->is_leader = 1;
+                                               break;
+                                       }
 
-       return 0;
+                                       schedule_delayed_work(&bp->reset_task,
+                                                               HZ/10);
+                                       return;
+
+                               } else { /* A leader has completed
+                                         * the "process kill". It's an exit
+                                         * point for a non-leader.
+                                         */
+                                       bnx2x_nic_load(bp, LOAD_NORMAL);
+                                       bp->recovery_state =
+                                               BNX2X_RECOVERY_DONE;
+                                       smp_wmb();
+                                       return;
+                               }
+                       }
+               default:
+                       return;
+               }
+       }
 }
 
+/* bnx2x_nic_unload() flushes the bnx2x_wq, thus reset task is
+ * scheduled on a general queue in order to prevent a dead lock.
+ */
 static void bnx2x_reset_task(struct work_struct *work)
 {
-       struct bnx2x *bp = container_of(work, struct bnx2x, reset_task);
+       struct bnx2x *bp = container_of(work, struct bnx2x, reset_task.work);
 
 #ifdef BNX2X_STOP_ON_ERROR
        BNX2X_ERR("reset task called but STOP_ON_ERROR defined"
                  " so reset not done to allow debug dump,\n"
-                 " you will need to reboot when done\n");
+        KERN_ERR " you will need to reboot when done\n");
        return;
 #endif
 
@@ -7463,8 +8975,12 @@ static void bnx2x_reset_task(struct work_struct *work)
        if (!netif_running(bp->dev))
                goto reset_task_exit;
 
-       bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-       bnx2x_nic_load(bp, LOAD_NORMAL);
+       if (unlikely(bp->recovery_state != BNX2X_RECOVERY_DONE))
+               bnx2x_parity_recover(bp);
+       else {
+               bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+               bnx2x_nic_load(bp, LOAD_NORMAL);
+       }
 
 reset_task_exit:
        rtnl_unlock();
@@ -7668,8 +9184,10 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
                       bp->common.flash_size, bp->common.flash_size);
 
        bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+       bp->common.shmem2_base = REG_RD(bp, MISC_REG_GENERIC_CR_0);
        bp->link_params.shmem_base = bp->common.shmem_base;
-       BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base);
+       BNX2X_DEV_INFO("shmem offset 0x%x  shmem2 offset 0x%x\n",
+                      bp->common.shmem_base, bp->common.shmem2_base);
 
        if (!bp->common.shmem_base ||
            (bp->common.shmem_base < 0xA0000) ||
@@ -7682,7 +9200,7 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
        if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
                != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-               BNX2X_ERR("BAD MCP validity signature\n");
+               BNX2X_ERROR("BAD MCP validity signature\n");
 
        bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
        BNX2X_DEV_INFO("hw_config 0x%08x\n", bp->common.hw_config);
@@ -7706,8 +9224,8 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        if (val < BNX2X_BC_VER) {
                /* for now only warn
                 * later we might need to enforce this */
-               BNX2X_ERR("This driver needs bc_ver %X but found %X,"
-                         please upgrade BC\n", BNX2X_BC_VER, val);
+               BNX2X_ERROR("This driver needs bc_ver %X but found %X, "
+                           "please upgrade BC\n", BNX2X_BC_VER, val);
        }
        bp->link_params.feature_config_flags |=
                (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
@@ -7728,8 +9246,8 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]);
        val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]);
 
-       printk(KERN_INFO PFX "part number %X-%X-%X-%X\n",
-              val, val2, val3, val4);
+       dev_info(&bp->pdev->dev, "part number %X-%X-%X-%X\n",
+                val, val2, val3, val4);
 }
 
 static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
@@ -8007,11 +9525,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_10baseT_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8023,11 +9541,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_10baseT_Half |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8038,11 +9556,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_100baseT_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8054,11 +9572,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_100baseT_Half |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8069,11 +9587,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_1000baseT_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8084,11 +9602,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_2500baseX_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8101,19 +9619,19 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_10000baseT_Full |
                                                ADVERTISED_FIBRE);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
 
        default:
-               BNX2X_ERR("NVRAM config error. "
-                         "BAD link speed link_config 0x%x\n",
-                         bp->port.link_config);
+               BNX2X_ERROR("NVRAM config error. "
+                           "BAD link speed link_config 0x%x\n",
+                           bp->port.link_config);
                bp->link_params.req_line_speed = SPEED_AUTO_NEG;
                bp->port.advertising = bp->port.supported;
                break;
@@ -8132,12 +9650,21 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                       bp->link_params.req_flow_ctrl, bp->port.advertising);
 }
 
+static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
+{
+       mac_hi = cpu_to_be16(mac_hi);
+       mac_lo = cpu_to_be32(mac_lo);
+       memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
+       memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
+}
+
 static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
        u32 val, val2;
        u32 config;
        u16 i;
+       u32 ext_phy_type;
 
        bp->link_params.bp = bp;
        bp->link_params.port = port;
@@ -8197,16 +9724,30 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 
        bnx2x_link_settings_requested(bp);
 
+       /*
+        * If connected directly, work with the internal PHY, otherwise, work
+        * with the external PHY
+        */
+       ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+       if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+               bp->mdio.prtad = bp->link_params.phy_addr;
+
+       else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) &&
+                (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN))
+               bp->mdio.prtad =
+                       XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
+
        val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
        val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
-       bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
-       bp->dev->dev_addr[1] = (u8)(val2 & 0xff);
-       bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff);
-       bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff);
-       bp->dev->dev_addr[4] = (u8)(val >> 8  & 0xff);
-       bp->dev->dev_addr[5] = (u8)(val & 0xff);
+       bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
        memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
        memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
+
+#ifdef BCM_CNIC
+       val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_upper);
+       val = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_lower);
+       bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
+#endif
 }
 
 static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
@@ -8219,24 +9760,35 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
 
        bp->e1hov = 0;
        bp->e1hmf = 0;
-       if (CHIP_IS_E1H(bp)) {
+       if (CHIP_IS_E1H(bp) && !BP_NOMCP(bp)) {
                bp->mf_config =
                        SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
 
-               val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func].e1hov_tag) &
+               val = (SHMEM_RD(bp, mf_cfg.func_mf_config[FUNC_0].e1hov_tag) &
                       FUNC_MF_CFG_E1HOV_TAG_MASK);
-               if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
-
-                       bp->e1hov = val;
+               if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT)
                        bp->e1hmf = 1;
-                       BNX2X_DEV_INFO("MF mode  E1HOV for func %d is %d "
-                                      "(0x%04x)\n",
-                                      func, bp->e1hov, bp->e1hov);
+               BNX2X_DEV_INFO("%s function mode\n",
+                              IS_E1HMF(bp) ? "multi" : "single");
+
+               if (IS_E1HMF(bp)) {
+                       val = (SHMEM_RD(bp, mf_cfg.func_mf_config[func].
+                                                               e1hov_tag) &
+                              FUNC_MF_CFG_E1HOV_TAG_MASK);
+                       if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
+                               bp->e1hov = val;
+                               BNX2X_DEV_INFO("E1HOV for func %d is %d "
+                                              "(0x%04x)\n",
+                                              func, bp->e1hov, bp->e1hov);
+                       } else {
+                               BNX2X_ERROR("No valid E1HOV for func %d,"
+                                           "  aborting\n", func);
+                               rc = -EPERM;
+                       }
                } else {
-                       BNX2X_DEV_INFO("single function mode\n");
                        if (BP_E1HVN(bp)) {
-                               BNX2X_ERR("!!!  No valid E1HOV for func %d,"
-                                         "  aborting\n", func);
+                               BNX2X_ERROR("VN %d in single function mode,"
+                                           "  aborting\n", BP_E1HVN(bp));
                                rc = -EPERM;
                        }
                }
@@ -8272,7 +9824,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
 
        if (BP_NOMCP(bp)) {
                /* only supposed to happen on emulation/FPGA */
-               BNX2X_ERR("warning random MAC workaround active\n");
+               BNX2X_ERROR("warning: random MAC workaround active\n");
                random_ether_addr(bp->dev->dev_addr);
                memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
        }
@@ -8280,6 +9832,70 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
        return rc;
 }
 
+static void __devinit bnx2x_read_fwinfo(struct bnx2x *bp)
+{
+       int cnt, i, block_end, rodi;
+       char vpd_data[BNX2X_VPD_LEN+1];
+       char str_id_reg[VENDOR_ID_LEN+1];
+       char str_id_cap[VENDOR_ID_LEN+1];
+       u8 len;
+
+       cnt = pci_read_vpd(bp->pdev, 0, BNX2X_VPD_LEN, vpd_data);
+       memset(bp->fw_ver, 0, sizeof(bp->fw_ver));
+
+       if (cnt < BNX2X_VPD_LEN)
+               goto out_not_found;
+
+       i = pci_vpd_find_tag(vpd_data, 0, BNX2X_VPD_LEN,
+                            PCI_VPD_LRDT_RO_DATA);
+       if (i < 0)
+               goto out_not_found;
+
+
+       block_end = i + PCI_VPD_LRDT_TAG_SIZE +
+                   pci_vpd_lrdt_size(&vpd_data[i]);
+
+       i += PCI_VPD_LRDT_TAG_SIZE;
+
+       if (block_end > BNX2X_VPD_LEN)
+               goto out_not_found;
+
+       rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
+                                  PCI_VPD_RO_KEYWORD_MFR_ID);
+       if (rodi < 0)
+               goto out_not_found;
+
+       len = pci_vpd_info_field_size(&vpd_data[rodi]);
+
+       if (len != VENDOR_ID_LEN)
+               goto out_not_found;
+
+       rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
+
+       /* vendor specific info */
+       snprintf(str_id_reg, VENDOR_ID_LEN + 1, "%04x", PCI_VENDOR_ID_DELL);
+       snprintf(str_id_cap, VENDOR_ID_LEN + 1, "%04X", PCI_VENDOR_ID_DELL);
+       if (!strncmp(str_id_reg, &vpd_data[rodi], VENDOR_ID_LEN) ||
+           !strncmp(str_id_cap, &vpd_data[rodi], VENDOR_ID_LEN)) {
+
+               rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
+                                               PCI_VPD_RO_KEYWORD_VENDOR0);
+               if (rodi >= 0) {
+                       len = pci_vpd_info_field_size(&vpd_data[rodi]);
+
+                       rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
+
+                       if (len < 32 && (len + rodi) <= BNX2X_VPD_LEN) {
+                               memcpy(bp->fw_ver, &vpd_data[rodi], len);
+                               bp->fw_ver[len] = ' ';
+                       }
+               }
+               return;
+       }
+out_not_found:
+       return;
+}
+
 static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 {
        int func = BP_FUNC(bp);
@@ -8291,33 +9907,40 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
        smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
 
        mutex_init(&bp->port.phy_mutex);
+       mutex_init(&bp->fw_mb_mutex);
+#ifdef BCM_CNIC
+       mutex_init(&bp->cnic_mutex);
+#endif
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
-       INIT_WORK(&bp->reset_task, bnx2x_reset_task);
+       INIT_DELAYED_WORK(&bp->reset_task, bnx2x_reset_task);
 
        rc = bnx2x_get_hwinfo(bp);
 
+       bnx2x_read_fwinfo(bp);
        /* need to reset chip if undi was active */
        if (!BP_NOMCP(bp))
                bnx2x_undi_unload(bp);
 
        if (CHIP_REV_IS_FPGA(bp))
-               printk(KERN_ERR PFX "FPGA detected\n");
+               dev_err(&bp->pdev->dev, "FPGA detected\n");
 
        if (BP_NOMCP(bp) && (func == 0))
-               printk(KERN_ERR PFX
-                      "MCP disabled, must load devices in order!\n");
+               dev_err(&bp->pdev->dev, "MCP disabled, "
+                                       "must load devices in order!\n");
 
        /* Set multi queue mode */
        if ((multi_mode != ETH_RSS_MODE_DISABLED) &&
            ((int_mode == INT_MODE_INTx) || (int_mode == INT_MODE_MSI))) {
-               printk(KERN_ERR PFX
-                     "Multi disabled since int_mode requested is not MSI-X\n");
+               dev_err(&bp->pdev->dev, "Multi disabled since int_mode "
+                                       "requested is not MSI-X\n");
                multi_mode = ETH_RSS_MODE_DISABLED;
        }
        bp->multi_mode = multi_mode;
 
 
+       bp->dev->features |= NETIF_F_GRO;
+
        /* Set TPA flags */
        if (disable_tpa) {
                bp->flags &= ~TPA_ENABLE_FLAG;
@@ -8327,6 +9950,11 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
                bp->dev->features |= NETIF_F_LRO;
        }
 
+       if (CHIP_IS_E1(bp))
+               bp->dropless_fc = 0;
+       else
+               bp->dropless_fc = dropless_fc;
+
        bp->mrrs = mrrs;
 
        bp->tx_ring_size = MAX_TX_AVAIL;
@@ -8334,8 +9962,9 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 
        bp->rx_csum = 1;
 
-       bp->tx_ticks = 50;
-       bp->rx_ticks = 25;
+       /* make sure that the numbers are in the right granularity */
+       bp->tx_ticks = (50 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
+       bp->rx_ticks = (25 / (4 * BNX2X_BTR)) * (4 * BNX2X_BTR);
 
        timer_interval = (CHIP_REV_IS_SLOW(bp) ? 5*HZ : HZ);
        bp->current_interval = (poll ? poll : timer_interval);
@@ -8361,20 +9990,23 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        cmd->supported = bp->port.supported;
        cmd->advertising = bp->port.advertising;
 
-       if (netif_carrier_ok(dev)) {
+       if ((bp->state == BNX2X_STATE_OPEN) &&
+           !(bp->flags & MF_FUNC_DIS) &&
+           (bp->link_vars.link_up)) {
                cmd->speed = bp->link_vars.line_speed;
                cmd->duplex = bp->link_vars.duplex;
-       } else {
-               cmd->speed = bp->link_params.req_line_speed;
-               cmd->duplex = bp->link_params.req_duplex;
-       }
-       if (IS_E1HMF(bp)) {
-               u16 vn_max_rate;
+               if (IS_E1HMF(bp)) {
+                       u16 vn_max_rate;
 
-               vn_max_rate = ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
+                       vn_max_rate =
+                               ((bp->mf_config & FUNC_MF_CFG_MAX_BW_MASK) >>
                                FUNC_MF_CFG_MAX_BW_SHIFT) * 100;
-               if (vn_max_rate < cmd->speed)
-                       cmd->speed = vn_max_rate;
+                       if (vn_max_rate < cmd->speed)
+                               cmd->speed = vn_max_rate;
+               }
+       } else {
+               cmd->speed = -1;
+               cmd->duplex = -1;
        }
 
        if (bp->link_params.switch_cfg == SWITCH_CFG_10G) {
@@ -8410,7 +10042,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        } else
                cmd->port = PORT_TP;
 
-       cmd->phy_address = bp->port.phy_addr;
+       cmd->phy_address = bp->mdio.prtad;
        cmd->transceiver = XCVR_INTERNAL;
 
        if (bp->link_params.req_line_speed == SPEED_AUTO_NEG)
@@ -8583,50 +10215,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        return 0;
 }
 
-#define PHY_FW_VER_LEN                 10
-
-static void bnx2x_get_drvinfo(struct net_device *dev,
-                             struct ethtool_drvinfo *info)
-{
-       struct bnx2x *bp = netdev_priv(dev);
-       u8 phy_fw_ver[PHY_FW_VER_LEN];
-
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
-
-       phy_fw_ver[0] = '\0';
-       if (bp->port.pmf) {
-               bnx2x_acquire_phy_lock(bp);
-               bnx2x_get_ext_phy_fw_version(&bp->link_params,
-                                            (bp->state != BNX2X_STATE_CLOSED),
-                                            phy_fw_ver, PHY_FW_VER_LEN);
-               bnx2x_release_phy_lock(bp);
-       }
-
-       snprintf(info->fw_version, 32, "BC:%d.%d.%d%s%s",
-                (bp->common.bc_ver & 0xff0000) >> 16,
-                (bp->common.bc_ver & 0xff00) >> 8,
-                (bp->common.bc_ver & 0xff),
-                ((phy_fw_ver[0] != '\0') ? " PHY:" : ""), phy_fw_ver);
-       strcpy(info->bus_info, pci_name(bp->pdev));
-       info->n_stats = BNX2X_NUM_STATS;
-       info->testinfo_len = BNX2X_NUM_TESTS;
-       info->eedump_len = bp->common.flash_size;
-       info->regdump_len = 0;
-}
-
 #define IS_E1_ONLINE(info)     (((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
 #define IS_E1H_ONLINE(info)    (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
 
 static int bnx2x_get_regs_len(struct net_device *dev)
 {
-       static u32 regdump_len;
        struct bnx2x *bp = netdev_priv(dev);
+       int regdump_len = 0;
        int i;
 
-       if (regdump_len)
-               return regdump_len;
-
        if (CHIP_IS_E1(bp)) {
                for (i = 0; i < REGS_COUNT; i++)
                        if (IS_E1_ONLINE(reg_addrs[i].info))
@@ -8693,6 +10290,40 @@ static void bnx2x_get_regs(struct net_device *dev,
        }
 }
 
+#define PHY_FW_VER_LEN                 10
+
+static void bnx2x_get_drvinfo(struct net_device *dev,
+                             struct ethtool_drvinfo *info)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       u8 phy_fw_ver[PHY_FW_VER_LEN];
+
+       strcpy(info->driver, DRV_MODULE_NAME);
+       strcpy(info->version, DRV_MODULE_VERSION);
+
+       phy_fw_ver[0] = '\0';
+       if (bp->port.pmf) {
+               bnx2x_acquire_phy_lock(bp);
+               bnx2x_get_ext_phy_fw_version(&bp->link_params,
+                                            (bp->state != BNX2X_STATE_CLOSED),
+                                            phy_fw_ver, PHY_FW_VER_LEN);
+               bnx2x_release_phy_lock(bp);
+       }
+
+       strncpy(info->fw_version, bp->fw_ver, 32);
+       snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+                "bc %d.%d.%d%s%s",
+                (bp->common.bc_ver & 0xff0000) >> 16,
+                (bp->common.bc_ver & 0xff00) >> 8,
+                (bp->common.bc_ver & 0xff),
+                ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
+       strcpy(info->bus_info, pci_name(bp->pdev));
+       info->n_stats = BNX2X_NUM_STATS;
+       info->testinfo_len = BNX2X_NUM_TESTS;
+       info->eedump_len = bp->common.flash_size;
+       info->regdump_len = bnx2x_get_regs_len(dev);
+}
+
 static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct bnx2x *bp = netdev_priv(dev);
@@ -8732,7 +10363,7 @@ static u32 bnx2x_get_msglevel(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
-       return bp->msglevel;
+       return bp->msg_enable;
 }
 
 static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
@@ -8740,7 +10371,7 @@ static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
        struct bnx2x *bp = netdev_priv(dev);
 
        if (capable(CAP_NET_ADMIN))
-               bp->msglevel = level;
+               bp->msg_enable = level;
 }
 
 static int bnx2x_nway_reset(struct net_device *dev)
@@ -8758,11 +10389,13 @@ static int bnx2x_nway_reset(struct net_device *dev)
        return 0;
 }
 
-static u32
-bnx2x_get_link(struct net_device *dev)
+static u32 bnx2x_get_link(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
+       if (bp->flags & MF_FUNC_DIS)
+               return 0;
+
        return bp->link_vars.link_up;
 }
 
@@ -9133,7 +10766,8 @@ static int bnx2x_set_eeprom(struct net_device *dev,
                            struct ethtool_eeprom *eeprom, u8 *eebuf)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       int rc;
+       int port = BP_PORT(bp);
+       int rc = 0;
 
        if (!netif_running(dev))
                return -EAGAIN;
@@ -9145,27 +10779,59 @@ static int bnx2x_set_eeprom(struct net_device *dev,
 
        /* parameters already validated in ethtool_set_eeprom */
 
-       /* If the magic number is PHY (0x00504859) upgrade the PHY FW */
-       if (eeprom->magic == 0x00504859)
-               if (bp->port.pmf) {
+       /* PHY eeprom can be accessed only by the PMF */
+       if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) &&
+           !bp->port.pmf)
+               return -EINVAL;
+
+       if (eeprom->magic == 0x50485950) {
+               /* 'PHYP' (0x50485950): prepare phy for FW upgrade */
+               bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+               bnx2x_acquire_phy_lock(bp);
+               rc |= bnx2x_link_reset(&bp->link_params,
+                                      &bp->link_vars, 0);
+               if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+                                       PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101)
+                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+                                      MISC_REGISTERS_GPIO_HIGH, port);
+               bnx2x_release_phy_lock(bp);
+               bnx2x_link_report(bp);
 
+       } else if (eeprom->magic == 0x50485952) {
+               /* 'PHYR' (0x50485952): re-init link after FW upgrade */
+               if (bp->state == BNX2X_STATE_OPEN) {
                        bnx2x_acquire_phy_lock(bp);
-                       rc = bnx2x_flash_download(bp, BP_PORT(bp),
-                                            bp->link_params.ext_phy_config,
-                                            (bp->state != BNX2X_STATE_CLOSED),
-                                            eebuf, eeprom->len);
-                       if ((bp->state == BNX2X_STATE_OPEN) ||
-                           (bp->state == BNX2X_STATE_DISABLED)) {
-                               rc |= bnx2x_link_reset(&bp->link_params,
-                                                      &bp->link_vars, 1);
-                               rc |= bnx2x_phy_init(&bp->link_params,
-                                                    &bp->link_vars);
-                       }
+                       rc |= bnx2x_link_reset(&bp->link_params,
+                                              &bp->link_vars, 1);
+
+                       rc |= bnx2x_phy_init(&bp->link_params,
+                                            &bp->link_vars);
                        bnx2x_release_phy_lock(bp);
+                       bnx2x_calc_fc_adv(bp);
+               }
+       } else if (eeprom->magic == 0x53985943) {
+               /* 'PHYC' (0x53985943): PHY FW upgrade completed */
+               if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+                                      PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) {
+                       u8 ext_phy_addr =
+                            XGXS_EXT_PHY_ADDR(bp->link_params.ext_phy_config);
 
-               } else /* Only the PMF can access the PHY */
-                       return -EINVAL;
-       else
+                       /* DSP Remove Download Mode */
+                       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+                                      MISC_REGISTERS_GPIO_LOW, port);
+
+                       bnx2x_acquire_phy_lock(bp);
+
+                       bnx2x_sfx7101_sp_sw_reset(bp, port, ext_phy_addr);
+
+                       /* wait 0.5 sec to allow it to run */
+                       msleep(500);
+                       bnx2x_ext_phy_hw_reset(bp, port);
+                       msleep(500);
+                       bnx2x_release_phy_lock(bp);
+               }
+       } else
                rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
 
        return rc;
@@ -9189,11 +10855,11 @@ static int bnx2x_set_coalesce(struct net_device *dev,
 {
        struct bnx2x *bp = netdev_priv(dev);
 
-       bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
+       bp->rx_ticks = (u16)coal->rx_coalesce_usecs;
        if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT)
                bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT;
 
-       bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
+       bp->tx_ticks = (u16)coal->tx_coalesce_usecs;
        if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT)
                bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT;
 
@@ -9226,6 +10892,11 @@ static int bnx2x_set_ringparam(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        if ((ering->rx_pending > MAX_RX_AVAIL) ||
            (ering->tx_pending > MAX_TX_AVAIL) ||
            (ering->tx_pending <= MAX_SKB_FRAGS + 4))
@@ -9311,20 +10982,32 @@ static int bnx2x_set_flags(struct net_device *dev, u32 data)
        int changed = 0;
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        /* TPA requires Rx CSUM offloading */
        if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
-               if (!(dev->features & NETIF_F_LRO)) {
-                       dev->features |= NETIF_F_LRO;
-                       bp->flags |= TPA_ENABLE_FLAG;
-                       changed = 1;
-               }
-
+               if (!disable_tpa) {
+                       if (!(dev->features & NETIF_F_LRO)) {
+                               dev->features |= NETIF_F_LRO;
+                               bp->flags |= TPA_ENABLE_FLAG;
+                               changed = 1;
+                       }
+               } else
+                       rc = -EINVAL;
        } else if (dev->features & NETIF_F_LRO) {
                dev->features &= ~NETIF_F_LRO;
                bp->flags &= ~TPA_ENABLE_FLAG;
                changed = 1;
        }
 
+       if (data & ETH_FLAG_RXHASH)
+               dev->features |= NETIF_F_RXHASH;
+       else
+               dev->features &= ~NETIF_F_RXHASH;
+
        if (changed && netif_running(dev)) {
                bnx2x_nic_unload(bp, UNLOAD_NORMAL);
                rc = bnx2x_nic_load(bp, LOAD_NORMAL);
@@ -9345,6 +11028,11 @@ static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
        struct bnx2x *bp = netdev_priv(dev);
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        bp->rx_csum = data;
 
        /* Disable TPA, when Rx CSUM is disabled. Otherwise all
@@ -9383,20 +11071,15 @@ static const struct {
        { "idle check (online)" }
 };
 
-static int bnx2x_self_test_count(struct net_device *dev)
-{
-       return BNX2X_NUM_TESTS;
-}
-
 static int bnx2x_test_registers(struct bnx2x *bp)
 {
        int idx, i, rc = -ENODEV;
        u32 wr_val = 0;
        int port = BP_PORT(bp);
        static const struct {
-               u32  offset0;
-               u32  offset1;
-               u32  mask;
+               u32 offset0;
+               u32 offset1;
+               u32 mask;
        } reg_tbl[] = {
 /* 0 */                { BRB1_REG_PAUSE_LOW_THRESHOLD_0,      4, 0x000003ff },
                { DORQ_REG_DB_ADDR0,                   4, 0xffffffff },
@@ -9463,15 +11146,19 @@ static int bnx2x_test_registers(struct bnx2x *bp)
 
                        save_val = REG_RD(bp, offset);
 
-                       REG_WR(bp, offset, wr_val);
+                       REG_WR(bp, offset, (wr_val & mask));
                        val = REG_RD(bp, offset);
 
                        /* Restore the original register's value */
                        REG_WR(bp, offset, save_val);
 
-                       /* verify that value is as expected value */
-                       if ((val & mask) != (wr_val & mask))
+                       /* verify value is as expected */
+                       if ((val & mask) != (wr_val & mask)) {
+                               DP(NETIF_MSG_PROBE,
+                                  "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n",
+                                  offset, val, wr_val, mask);
                                goto test_reg_exit;
+                       }
                }
        }
 
@@ -9554,12 +11241,14 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
        unsigned int pkt_size, num_pkts, i;
        struct sk_buff *skb;
        unsigned char *packet;
-       struct bnx2x_fastpath *fp = &bp->fp[0];
+       struct bnx2x_fastpath *fp_rx = &bp->fp[0];
+       struct bnx2x_fastpath *fp_tx = &bp->fp[0];
        u16 tx_start_idx, tx_idx;
        u16 rx_start_idx, rx_idx;
-       u16 pkt_prod;
+       u16 pkt_prod, bd_prod;
        struct sw_tx_bd *tx_buf;
-       struct eth_tx_bd *tx_bd;
+       struct eth_tx_start_bd *tx_start_bd;
+       struct eth_tx_parse_bd *pbd = NULL;
        dma_addr_t mapping;
        union eth_rx_cqe *cqe;
        u8 cqe_fp_flags;
@@ -9591,57 +11280,63 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
        }
        packet = skb_put(skb, pkt_size);
        memcpy(packet, bp->dev->dev_addr, ETH_ALEN);
-       memset(packet + ETH_ALEN, 0, (ETH_HLEN - ETH_ALEN));
+       memset(packet + ETH_ALEN, 0, ETH_ALEN);
+       memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN));
        for (i = ETH_HLEN; i < pkt_size; i++)
                packet[i] = (unsigned char) (i & 0xff);
 
        /* send the loopback packet */
        num_pkts = 0;
-       tx_start_idx = le16_to_cpu(*fp->tx_cons_sb);
-       rx_start_idx = le16_to_cpu(*fp->rx_cons_sb);
+       tx_start_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
+       rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
 
-       pkt_prod = fp->tx_pkt_prod++;
-       tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)];
-       tx_buf->first_bd = fp->tx_bd_prod;
+       pkt_prod = fp_tx->tx_pkt_prod++;
+       tx_buf = &fp_tx->tx_buf_ring[TX_BD(pkt_prod)];
+       tx_buf->first_bd = fp_tx->tx_bd_prod;
        tx_buf->skb = skb;
+       tx_buf->flags = 0;
+
+       bd_prod = TX_BD(fp_tx->tx_bd_prod);
+       tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd;
+       mapping = dma_map_single(&bp->pdev->dev, skb->data,
+                                skb_headlen(skb), DMA_TO_DEVICE);
+       tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+       tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+       tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */
+       tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+       tx_start_bd->vlan = cpu_to_le16(pkt_prod);
+       tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+       tx_start_bd->general_data = ((UNICAST_ADDRESS <<
+                               ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT) | 1);
+
+       /* turn on parsing and get a BD */
+       bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+       pbd = &fp_tx->tx_desc_ring[bd_prod].parse_bd;
 
-       tx_bd = &fp->tx_desc_ring[TX_BD(fp->tx_bd_prod)];
-       mapping = pci_map_single(bp->pdev, skb->data,
-                                skb_headlen(skb), PCI_DMA_TODEVICE);
-       tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-       tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-       tx_bd->nbd = cpu_to_le16(1);
-       tx_bd->nbytes = cpu_to_le16(skb_headlen(skb));
-       tx_bd->vlan = cpu_to_le16(pkt_prod);
-       tx_bd->bd_flags.as_bitfield = (ETH_TX_BD_FLAGS_START_BD |
-                                      ETH_TX_BD_FLAGS_END_BD);
-       tx_bd->general_data = ((UNICAST_ADDRESS <<
-                               ETH_TX_BD_ETH_ADDR_TYPE_SHIFT) | 1);
+       memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
 
        wmb();
 
-       le16_add_cpu(&fp->hw_tx_prods->bds_prod, 1);
-       mb(); /* FW restriction: must not reorder writing nbd and packets */
-       le32_add_cpu(&fp->hw_tx_prods->packets_prod, 1);
-       DOORBELL(bp, fp->index, 0);
+       fp_tx->tx_db.data.prod += 2;
+       barrier();
+       DOORBELL(bp, fp_tx->index, fp_tx->tx_db.raw);
 
        mmiowb();
 
        num_pkts++;
-       fp->tx_bd_prod++;
-       bp->dev->trans_start = jiffies;
+       fp_tx->tx_bd_prod += 2; /* start + pbd */
 
        udelay(100);
 
-       tx_idx = le16_to_cpu(*fp->tx_cons_sb);
+       tx_idx = le16_to_cpu(*fp_tx->tx_cons_sb);
        if (tx_idx != tx_start_idx + num_pkts)
                goto test_loopback_exit;
 
-       rx_idx = le16_to_cpu(*fp->rx_cons_sb);
+       rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb);
        if (rx_idx != rx_start_idx + num_pkts)
                goto test_loopback_exit;
 
-       cqe = &fp->rx_comp_ring[RCQ_BD(fp->rx_comp_cons)];
+       cqe = &fp_rx->rx_comp_ring[RCQ_BD(fp_rx->rx_comp_cons)];
        cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
        if (CQE_TYPE(cqe_fp_flags) || (cqe_fp_flags & ETH_RX_ERROR_FALGS))
                goto test_loopback_rx_exit;
@@ -9650,7 +11345,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
        if (len != pkt_size)
                goto test_loopback_rx_exit;
 
-       rx_buf = &fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)];
+       rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)];
        skb = rx_buf->skb;
        skb_reserve(skb, cqe->fast_path_cqe.placement_offset);
        for (i = ETH_HLEN; i < pkt_size; i++)
@@ -9661,14 +11356,14 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
 
 test_loopback_rx_exit:
 
-       fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons);
-       fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod);
-       fp->rx_comp_cons = NEXT_RCQ_IDX(fp->rx_comp_cons);
-       fp->rx_comp_prod = NEXT_RCQ_IDX(fp->rx_comp_prod);
+       fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons);
+       fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod);
+       fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons);
+       fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod);
 
        /* Update producers */
-       bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod,
-                            fp->rx_sge_prod);
+       bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod,
+                            fp_rx->rx_sge_prod);
 
 test_loopback_exit:
        bp->link_params.loopback_mode = LOOPBACK_NONE;
@@ -9680,6 +11375,9 @@ static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up)
 {
        int rc = 0, res;
 
+       if (BP_NOMCP(bp))
+               return rc;
+
        if (!netif_running(bp->dev))
                return BNX2X_LOOPBACK_FAILED;
 
@@ -9725,7 +11423,10 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
        __be32 buf[0x350 / 4];
        u8 *data = (u8 *)buf;
        int i, rc;
-       u32 magic, csum;
+       u32 magic, crc;
+
+       if (BP_NOMCP(bp))
+               return 0;
 
        rc = bnx2x_nvram_read(bp, 0, data, 4);
        if (rc) {
@@ -9750,10 +11451,10 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
                        goto test_nvram_exit;
                }
 
-               csum = ether_crc_le(nvram_tbl[i].size, data);
-               if (csum != CRC32_RESIDUAL) {
+               crc = ether_crc_le(nvram_tbl[i].size, data);
+               if (crc != CRC32_RESIDUAL) {
                        DP(NETIF_MSG_PROBE,
-                          "nvram_tbl[%d] csum value (0x%08x)\n", i, csum);
+                          "nvram_tbl[%d] crc value (0x%08x)\n", i, crc);
                        rc = -ENODEV;
                        goto test_nvram_exit;
                }
@@ -9773,20 +11474,23 @@ static int bnx2x_test_intr(struct bnx2x *bp)
 
        config->hdr.length = 0;
        if (CHIP_IS_E1(bp))
-               config->hdr.offset = (BP_PORT(bp) ? 32 : 0);
+               /* use last unicast entries */
+               config->hdr.offset = (BP_PORT(bp) ? 63 : 31);
        else
                config->hdr.offset = BP_FUNC(bp);
        config->hdr.client_id = bp->fp->cl_id;
        config->hdr.reserved1 = 0;
 
+       bp->set_mac_pending++;
+       smp_wmb();
        rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
                           U64_HI(bnx2x_sp_mapping(bp, mac_config)),
                           U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
        if (rc == 0) {
-               bp->set_mac_pending++;
                for (i = 0; i < 10; i++) {
                        if (!bp->set_mac_pending)
                                break;
+                       smp_rmb();
                        msleep_interruptible(10);
                }
                if (i == 10)
@@ -9801,6 +11505,12 @@ static void bnx2x_self_test(struct net_device *dev,
 {
        struct bnx2x *bp = netdev_priv(dev);
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               etest->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
+
        memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
 
        if (!netif_running(dev))
@@ -9820,7 +11530,7 @@ static void bnx2x_self_test(struct net_device *dev,
                /* disable input for TX port IF */
                REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
 
-               link_up = bp->link_vars.link_up;
+               link_up = (bnx2x_link_test(bp) == 0);
                bnx2x_nic_unload(bp, UNLOAD_NORMAL);
                bnx2x_nic_load(bp, LOAD_DIAG);
                /* wait until link state is restored */
@@ -9889,7 +11599,11 @@ static const struct {
 
 /* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi),        8, "[%d]: tx_bytes" },
        { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
-                                                       8, "[%d]: tx_packets" }
+                                               8, "[%d]: tx_ucast_packets" },
+       { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+                                               8, "[%d]: tx_mcast_packets" },
+       { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+                                               8, "[%d]: tx_bcast_packets" }
 };
 
 static const struct {
@@ -9951,16 +11665,20 @@ static const struct {
        { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
                                8, STATS_FLAGS_PORT, "tx_error_bytes" },
        { STATS_OFFSET32(total_unicast_packets_transmitted_hi),
-                               8, STATS_FLAGS_BOTH, "tx_packets" },
+                               8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
+       { STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+                               8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
+       { STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+                               8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
        { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
                                8, STATS_FLAGS_PORT, "tx_mac_errors" },
        { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
                                8, STATS_FLAGS_PORT, "tx_carrier_errors" },
-       { STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
+/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
                                8, STATS_FLAGS_PORT, "tx_single_collisions" },
        { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
                                8, STATS_FLAGS_PORT, "tx_multi_collisions" },
-/* 30 */{ STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
+       { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
                                8, STATS_FLAGS_PORT, "tx_deferred" },
        { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
                                8, STATS_FLAGS_PORT, "tx_excess_collisions" },
@@ -9976,11 +11694,11 @@ static const struct {
                        8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
        { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
                        8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
-       { STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
+/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
                        8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
        { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
                        8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
-/* 40 */{ STATS_OFFSET32(etherstatspktsover1522octets_hi),
+       { STATS_OFFSET32(etherstatspktsover1522octets_hi),
                        8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
        { STATS_OFFSET32(pause_frames_sent_hi),
                                8, STATS_FLAGS_PORT, "tx_pause_frames" }
@@ -9990,7 +11708,37 @@ static const struct {
        ((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
 #define IS_FUNC_STAT(i)                (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
 #define IS_E1HMF_MODE_STAT(bp) \
-                       (IS_E1HMF(bp) && !(bp->msglevel & BNX2X_MSG_STATS))
+                       (IS_E1HMF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
+
+static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       int i, num_stats;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               if (is_multi(bp)) {
+                       num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
+                       if (!IS_E1HMF_MODE_STAT(bp))
+                               num_stats += BNX2X_NUM_STATS;
+               } else {
+                       if (IS_E1HMF_MODE_STAT(bp)) {
+                               num_stats = 0;
+                               for (i = 0; i < BNX2X_NUM_STATS; i++)
+                                       if (IS_FUNC_STAT(i))
+                                               num_stats++;
+                       } else
+                               num_stats = BNX2X_NUM_STATS;
+               }
+               return num_stats;
+
+       case ETH_SS_TEST:
+               return BNX2X_NUM_TESTS;
+
+       default:
+               return -EINVAL;
+       }
+}
 
 static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
 {
@@ -10029,28 +11777,6 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
        }
 }
 
-static int bnx2x_get_stats_count(struct net_device *dev)
-{
-       struct bnx2x *bp = netdev_priv(dev);
-       int i, num_stats;
-
-       if (is_multi(bp)) {
-               num_stats = BNX2X_NUM_Q_STATS * BNX2X_NUM_QUEUES(bp);
-               if (!IS_E1HMF_MODE_STAT(bp))
-                       num_stats += BNX2X_NUM_STATS;
-       } else {
-               if (IS_E1HMF_MODE_STAT(bp)) {
-                       num_stats = 0;
-                       for (i = 0; i < BNX2X_NUM_STATS; i++)
-                               if (IS_FUNC_STAT(i))
-                                       num_stats++;
-               } else
-                       num_stats = BNX2X_NUM_STATS;
-       }
-
-       return num_stats;
-}
-
 static void bnx2x_get_ethtool_stats(struct net_device *dev,
                                    struct ethtool_stats *stats, u64 *buf)
 {
@@ -10126,7 +11852,6 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
 static int bnx2x_phys_id(struct net_device *dev, u32 data)
 {
        struct bnx2x *bp = netdev_priv(dev);
-       int port = BP_PORT(bp);
        int i;
 
        if (!netif_running(dev))
@@ -10140,13 +11865,10 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
 
        for (i = 0; i < (data * 2); i++) {
                if ((i % 2) == 0)
-                       bnx2x_set_led(bp, port, LED_MODE_OPER, SPEED_1000,
-                                     bp->link_params.hw_led_mode,
-                                     bp->link_params.chip_id);
+                       bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+                                     SPEED_1000);
                else
-                       bnx2x_set_led(bp, port, LED_MODE_OFF, 0,
-                                     bp->link_params.hw_led_mode,
-                                     bp->link_params.chip_id);
+                       bnx2x_set_led(&bp->link_params, LED_MODE_OFF, 0);
 
                msleep_interruptible(500);
                if (signal_pending(current))
@@ -10154,15 +11876,13 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data)
        }
 
        if (bp->link_vars.link_up)
-               bnx2x_set_led(bp, port, LED_MODE_OPER,
-                             bp->link_vars.line_speed,
-                             bp->link_params.hw_led_mode,
-                             bp->link_params.chip_id);
+               bnx2x_set_led(&bp->link_params, LED_MODE_OPER,
+                             bp->link_vars.line_speed);
 
        return 0;
 }
 
-static struct ethtool_ops bnx2x_ethtool_ops = {
+static const struct ethtool_ops bnx2x_ethtool_ops = {
        .get_settings           = bnx2x_get_settings,
        .set_settings           = bnx2x_set_settings,
        .get_drvinfo            = bnx2x_get_drvinfo,
@@ -10193,11 +11913,10 @@ static struct ethtool_ops bnx2x_ethtool_ops = {
        .set_sg                 = ethtool_op_set_sg,
        .get_tso                = ethtool_op_get_tso,
        .set_tso                = bnx2x_set_tso,
-       .self_test_count        = bnx2x_self_test_count,
        .self_test              = bnx2x_self_test,
+       .get_sset_count         = bnx2x_get_sset_count,
        .get_strings            = bnx2x_get_strings,
        .phys_id                = bnx2x_phys_id,
-       .get_stats_count        = bnx2x_get_stats_count,
        .get_ethtool_stats      = bnx2x_get_ethtool_stats,
 };
 
@@ -10225,6 +11944,14 @@ static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
                break;
 
        case PCI_D3hot:
+               /* If there are other clients above don't
+                  shut down the power */
+               if (atomic_read(&bp->pdev->enable_cnt) != 1)
+                       return 0;
+               /* Don't shut down the power for emulation and FPGA */
+               if (CHIP_REV_IS_SLOW(bp))
+                       return 0;
+
                pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
                pmcsr |= 3;
 
@@ -10263,58 +11990,60 @@ static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
 
 static int bnx2x_poll(struct napi_struct *napi, int budget)
 {
+       int work_done = 0;
        struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
                                                 napi);
        struct bnx2x *bp = fp->bp;
-       int work_done = 0;
 
+       while (1) {
 #ifdef BNX2X_STOP_ON_ERROR
-       if (unlikely(bp->panic))
-               goto poll_panic;
+               if (unlikely(bp->panic)) {
+                       napi_complete(napi);
+                       return 0;
+               }
 #endif
 
-       prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb);
-       prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb);
-       prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256);
-
-       bnx2x_update_fpsb_idx(fp);
-
-       if (bnx2x_has_tx_work(fp))
-               bnx2x_tx_int(fp);
-
-       if (bnx2x_has_rx_work(fp)) {
-               work_done = bnx2x_rx_int(fp, budget);
+               if (bnx2x_has_tx_work(fp))
+                       bnx2x_tx_int(fp);
 
-               /* must not complete if we consumed full budget */
-               if (work_done >= budget)
-                       goto poll_again;
-       }
+               if (bnx2x_has_rx_work(fp)) {
+                       work_done += bnx2x_rx_int(fp, budget - work_done);
 
-       /* BNX2X_HAS_WORK() reads the status block, thus we need to
-        * ensure that status block indices have been actually read
-        * (bnx2x_update_fpsb_idx) prior to this check (BNX2X_HAS_WORK)
-        * so that we won't write the "newer" value of the status block to IGU
-        * (if there was a DMA right after BNX2X_HAS_WORK and
-        * if there is no rmb, the memory reading (bnx2x_update_fpsb_idx)
-        * may be postponed to right before bnx2x_ack_sb). In this case
-        * there will never be another interrupt until there is another update
-        * of the status block, while there is still unhandled work.
-        */
-       rmb();
+                       /* must not complete if we consumed full budget */
+                       if (work_done >= budget)
+                               break;
+               }
 
-       if (!BNX2X_HAS_WORK(fp)) {
-#ifdef BNX2X_STOP_ON_ERROR
-poll_panic:
-#endif
-               napi_complete(napi);
+               /* Fall out from the NAPI loop if needed */
+               if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+                       bnx2x_update_fpsb_idx(fp);
+               /* bnx2x_has_rx_work() reads the status block, thus we need
+                * to ensure that status block indices have been actually read
+                * (bnx2x_update_fpsb_idx) prior to this check
+                * (bnx2x_has_rx_work) so that we won't write the "newer"
+                * value of the status block to IGU (if there was a DMA right
+                * after bnx2x_has_rx_work and if there is no rmb, the memory
+                * reading (bnx2x_update_fpsb_idx) may be postponed to right
+                * before bnx2x_ack_sb). In this case there will never be
+                * another interrupt until there is another update of the
+                * status block, while there is still unhandled work.
+                */
+                       rmb();
 
-               bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
-                            le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1);
-               bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
-                            le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1);
+                       if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+                               napi_complete(napi);
+                               /* Re-enable interrupts */
+                               bnx2x_ack_sb(bp, fp->sb_id, CSTORM_ID,
+                                            le16_to_cpu(fp->fp_c_idx),
+                                            IGU_INT_NOP, 1);
+                               bnx2x_ack_sb(bp, fp->sb_id, USTORM_ID,
+                                            le16_to_cpu(fp->fp_u_idx),
+                                            IGU_INT_ENABLE, 1);
+                               break;
+                       }
+               }
        }
 
-poll_again:
        return work_done;
 }
 
@@ -10327,10 +12056,11 @@ poll_again:
  */
 static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
                                   struct bnx2x_fastpath *fp,
-                                  struct eth_tx_bd **tx_bd, u16 hlen,
+                                  struct sw_tx_bd *tx_buf,
+                                  struct eth_tx_start_bd **tx_bd, u16 hlen,
                                   u16 bd_prod, int nbd)
 {
-       struct eth_tx_bd *h_tx_bd = *tx_bd;
+       struct eth_tx_start_bd *h_tx_bd = *tx_bd;
        struct eth_tx_bd *d_tx_bd;
        dma_addr_t mapping;
        int old_len = le16_to_cpu(h_tx_bd->nbytes);
@@ -10346,7 +12076,7 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
        /* now get a new data BD
         * (after the pbd) and fill it */
        bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-       d_tx_bd = &fp->tx_desc_ring[bd_prod];
+       d_tx_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
 
        mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi),
                           le32_to_cpu(h_tx_bd->addr_lo)) + hlen;
@@ -10354,17 +12084,16 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
        d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
        d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
        d_tx_bd->nbytes = cpu_to_le16(old_len - hlen);
-       d_tx_bd->vlan = 0;
-       /* this marks the BD as one that has no individual mapping
-        * the FW ignores this flag in a BD not marked start
-        */
-       d_tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO;
+
+       /* this marks the BD as one that has no individual mapping */
+       tx_buf->flags |= BNX2X_TSO_SPLIT_BD;
+
        DP(NETIF_MSG_TX_QUEUED,
           "TSO split data size is %d (%x:%x)\n",
           d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo);
 
-       /* update tx_bd for marking the last BD flag */
-       *tx_bd = d_tx_bd;
+       /* update tx_bd */
+       *tx_bd = (struct eth_tx_start_bd *)d_tx_bd;
 
        return bd_prod;
 }
@@ -10403,10 +12132,10 @@ static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
        }
 
        if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
-               rc |= XMIT_GSO_V4;
+               rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
 
        else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
-               rc |= XMIT_GSO_V6;
+               rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
 
        return rc;
 }
@@ -10496,21 +12225,24 @@ exit_lbl:
  * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
  * netif_wake_queue()
  */
-static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
        struct bnx2x_fastpath *fp;
        struct netdev_queue *txq;
        struct sw_tx_bd *tx_buf;
-       struct eth_tx_bd *tx_bd;
+       struct eth_tx_start_bd *tx_start_bd;
+       struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
        struct eth_tx_parse_bd *pbd = NULL;
        u16 pkt_prod, bd_prod;
        int nbd, fp_index;
        dma_addr_t mapping;
        u32 xmit_type = bnx2x_xmit_type(bp, skb);
-       int vlan_off = (bp->e1hov ? 4 : 0);
        int i;
        u8 hlen = 0;
+       __le16 pkt_size = 0;
+       struct ethhdr *eth;
+       u8 mac_type = UNICAST_ADDRESS;
 
 #ifdef BNX2X_STOP_ON_ERROR
        if (unlikely(bp->panic))
@@ -10523,7 +12255,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        fp = &bp->fp[fp_index];
 
        if (unlikely(bnx2x_tx_avail(fp) < (skb_shinfo(skb)->nr_frags + 3))) {
-               fp->eth_q_stats.driver_xoff++,
+               fp->eth_q_stats.driver_xoff++;
                netif_tx_stop_queue(txq);
                BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
                return NETDEV_TX_BUSY;
@@ -10534,6 +12266,16 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
           skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
           ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
 
+       eth = (struct ethhdr *)skb->data;
+
+       /* set flag according to packet type (UNICAST_ADDRESS is default)*/
+       if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
+               if (is_broadcast_ether_addr(eth->h_dest))
+                       mac_type = BROADCAST_ADDRESS;
+               else
+                       mac_type = MULTICAST_ADDRESS;
+       }
+
 #if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
        /* First, check if we need to linearize the skb (due to FW
           restrictions). No need to check fragmentation if page size > 8K
@@ -10552,7 +12294,7 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /*
        Please read carefully. First we use one BD which we mark as start,
-       then for TSO or xsum we have a parsing info BD,
+       then we have a parsing info BD (used for TSO or xsum),
        and only then we have the rest of the TSO BDs.
        (don't forget to mark the last one as last,
        and to unmap only AFTER you write to the BD ...)
@@ -10564,42 +12306,40 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* get a tx_buf and first BD */
        tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)];
-       tx_bd = &fp->tx_desc_ring[bd_prod];
+       tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd;
 
-       tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
-       tx_bd->general_data = (UNICAST_ADDRESS <<
-                              ETH_TX_BD_ETH_ADDR_TYPE_SHIFT);
+       tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+       tx_start_bd->general_data =  (mac_type <<
+                                       ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
        /* header nbd */
-       tx_bd->general_data |= (1 << ETH_TX_BD_HDR_NBDS_SHIFT);
+       tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
 
        /* remember the first BD of the packet */
        tx_buf->first_bd = fp->tx_bd_prod;
        tx_buf->skb = skb;
+       tx_buf->flags = 0;
 
        DP(NETIF_MSG_TX_QUEUED,
           "sending pkt %u @%p  next_idx %u  bd %u @%p\n",
-          pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd);
+          pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_start_bd);
 
 #ifdef BCM_VLAN
        if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) &&
            (bp->flags & HW_VLAN_TX_FLAG)) {
-               tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
-               tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
-               vlan_off += 4;
+               tx_start_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+               tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
        } else
 #endif
-               tx_bd->vlan = cpu_to_le16(pkt_prod);
+               tx_start_bd->vlan = cpu_to_le16(pkt_prod);
 
-       if (xmit_type) {
-               /* turn on parsing and get a BD */
-               bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-               pbd = (void *)&fp->tx_desc_ring[bd_prod];
+       /* turn on parsing and get a BD */
+       bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+       pbd = &fp->tx_desc_ring[bd_prod].parse_bd;
 
-               memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
-       }
+       memset(pbd, 0, sizeof(struct eth_tx_parse_bd));
 
        if (xmit_type & XMIT_CSUM) {
-               hlen = (skb_network_header(skb) - skb->data + vlan_off) / 2;
+               hlen = (skb_network_header(skb) - skb->data) / 2;
 
                /* for now NS flag is not used in Linux */
                pbd->global_data =
@@ -10612,15 +12352,16 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                hlen += pbd->ip_hlen + tcp_hdrlen(skb) / 2;
 
                pbd->total_hlen = cpu_to_le16(hlen);
-               hlen = hlen*2 - vlan_off;
+               hlen = hlen*2;
 
-               tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_TCP_CSUM;
+               tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
 
                if (xmit_type & XMIT_CSUM_V4)
-                       tx_bd->bd_flags.as_bitfield |=
+                       tx_start_bd->bd_flags.as_bitfield |=
                                                ETH_TX_BD_FLAGS_IP_CSUM;
                else
-                       tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IPV6;
+                       tx_start_bd->bd_flags.as_bitfield |=
+                                               ETH_TX_BD_FLAGS_IPV6;
 
                if (xmit_type & XMIT_CSUM_TCP) {
                        pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check);
@@ -10628,13 +12369,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                } else {
                        s8 fix = SKB_CS_OFF(skb); /* signed! */
 
-                       pbd->global_data |= ETH_TX_PARSE_BD_CS_ANY_FLG;
-                       pbd->cs_offset = fix / 2;
+                       pbd->global_data |= ETH_TX_PARSE_BD_UDP_CS_FLG;
 
                        DP(NETIF_MSG_TX_QUEUED,
-                          "hlen %d  offset %d  fix %d  csum before fix %x\n",
-                          le16_to_cpu(pbd->total_hlen), pbd->cs_offset, fix,
-                          SKB_CS(skb));
+                          "hlen %d  fix %d  csum before fix %x\n",
+                          le16_to_cpu(pbd->total_hlen), fix, SKB_CS(skb));
 
                        /* HW bug: fixup the CSUM */
                        pbd->tcp_pseudo_csum =
@@ -10646,20 +12385,21 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
-       mapping = pci_map_single(bp->pdev, skb->data,
-                                skb_headlen(skb), PCI_DMA_TODEVICE);
+       mapping = dma_map_single(&bp->pdev->dev, skb->data,
+                                skb_headlen(skb), DMA_TO_DEVICE);
 
-       tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-       tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-       nbd = skb_shinfo(skb)->nr_frags + ((pbd == NULL) ? 1 : 2);
-       tx_bd->nbd = cpu_to_le16(nbd);
-       tx_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+       tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+       tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+       nbd = skb_shinfo(skb)->nr_frags + 2; /* start_bd + pbd + frags */
+       tx_start_bd->nbd = cpu_to_le16(nbd);
+       tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+       pkt_size = tx_start_bd->nbytes;
 
        DP(NETIF_MSG_TX_QUEUED, "first bd @%p  addr (%x:%x)  nbd %d"
           "  nbytes %d  flags %x  vlan %x\n",
-          tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, le16_to_cpu(tx_bd->nbd),
-          le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield,
-          le16_to_cpu(tx_bd->vlan));
+          tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
+          le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes),
+          tx_start_bd->bd_flags.as_bitfield, le16_to_cpu(tx_start_bd->vlan));
 
        if (xmit_type & XMIT_GSO) {
 
@@ -10668,11 +12408,11 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                   skb->len, hlen, skb_headlen(skb),
                   skb_shinfo(skb)->gso_size);
 
-               tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
+               tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
 
                if (unlikely(skb_headlen(skb) > hlen))
-                       bd_prod = bnx2x_tx_split(bp, fp, &tx_bd, hlen,
-                                                bd_prod, ++nbd);
+                       bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
+                                                hlen, bd_prod, ++nbd);
 
                pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
                pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
@@ -10693,33 +12433,32 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN;
        }
+       tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
-               tx_bd = &fp->tx_desc_ring[bd_prod];
+               tx_data_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
+               if (total_pkt_bd == NULL)
+                       total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
 
-               mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
-                                      frag->size, PCI_DMA_TODEVICE);
+               mapping = dma_map_page(&bp->pdev->dev, frag->page,
+                                      frag->page_offset,
+                                      frag->size, DMA_TO_DEVICE);
 
-               tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
-               tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
-               tx_bd->nbytes = cpu_to_le16(frag->size);
-               tx_bd->vlan = cpu_to_le16(pkt_prod);
-               tx_bd->bd_flags.as_bitfield = 0;
+               tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+               tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+               tx_data_bd->nbytes = cpu_to_le16(frag->size);
+               le16_add_cpu(&pkt_size, frag->size);
 
                DP(NETIF_MSG_TX_QUEUED,
-                  "frag %d  bd @%p  addr (%x:%x)  nbytes %d  flags %x\n",
-                  i, tx_bd, tx_bd->addr_hi, tx_bd->addr_lo,
-                  le16_to_cpu(tx_bd->nbytes), tx_bd->bd_flags.as_bitfield);
+                  "frag %d  bd @%p  addr (%x:%x)  nbytes %d\n",
+                  i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo,
+                  le16_to_cpu(tx_data_bd->nbytes));
        }
 
-       /* now at last mark the BD as the last BD */
-       tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_END_BD;
-
-       DP(NETIF_MSG_TX_QUEUED, "last bd @%p  flags %x\n",
-          tx_bd, tx_bd->bd_flags.as_bitfield);
+       DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd);
 
        bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
 
@@ -10729,6 +12468,9 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (TX_BD_POFF(bd_prod) < nbd)
                nbd++;
 
+       if (total_pkt_bd != NULL)
+               total_pkt_bd->total_pkt_bytes = pkt_size;
+
        if (pbd)
                DP(NETIF_MSG_TX_QUEUED,
                   "PBD @%p  ip_data %x  ip_hlen %u  ip_id %u  lso_mss %u"
@@ -10748,20 +12490,22 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        wmb();
 
-       le16_add_cpu(&fp->hw_tx_prods->bds_prod, nbd);
-       mb(); /* FW restriction: must not reorder writing nbd and packets */
-       le32_add_cpu(&fp->hw_tx_prods->packets_prod, 1);
-       DOORBELL(bp, fp->index, 0);
+       fp->tx_db.data.prod += nbd;
+       barrier();
+       DOORBELL(bp, fp->index, fp->tx_db.raw);
 
        mmiowb();
 
        fp->tx_bd_prod += nbd;
 
        if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
-               /* We want bnx2x_tx_int to "see" the updated tx_bd_prod
-                  if we put Tx into XOFF state. */
-               smp_mb();
                netif_tx_stop_queue(txq);
+
+               /* paired memory barrier is in bnx2x_tx_int(), we have to keep
+                * ordering of set_bit() in netif_tx_stop_queue() and read of
+                * fp->bd_tx_cons */
+               smp_mb();
+
                fp->eth_q_stats.driver_xoff++;
                if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
                        netif_tx_wake_queue(txq);
@@ -10780,6 +12524,40 @@ static int bnx2x_open(struct net_device *dev)
 
        bnx2x_set_power_state(bp, PCI_D0);
 
+       if (!bnx2x_reset_is_done(bp)) {
+               do {
+                       /* Reset MCP mail box sequence if there is on going
+                        * recovery
+                        */
+                       bp->fw_seq = 0;
+
+                       /* If it's the first function to load and reset done
+                        * is still not cleared it may mean that. We don't
+                        * check the attention state here because it may have
+                        * already been cleared by a "common" reset but we
+                        * shell proceed with "process kill" anyway.
+                        */
+                       if ((bnx2x_get_load_cnt(bp) == 0) &&
+                               bnx2x_trylock_hw_lock(bp,
+                               HW_LOCK_RESOURCE_RESERVED_08) &&
+                               (!bnx2x_leader_reset(bp))) {
+                               DP(NETIF_MSG_HW, "Recovered in open\n");
+                               break;
+                       }
+
+                       bnx2x_set_power_state(bp, PCI_D3hot);
+
+                       printk(KERN_ERR"%s: Recovery flow hasn't been properly"
+                       " completed yet. Try again later. If u still see this"
+                       " message after a few retries then power cycle is"
+                       " required.\n", bp->dev->name);
+
+                       return -EAGAIN;
+               } while (0);
+       }
+
+       bp->recovery_state = BNX2X_RECOVERY_DONE;
+
        return bnx2x_nic_load(bp, LOAD_OPEN);
 }
 
@@ -10790,9 +12568,7 @@ static int bnx2x_close(struct net_device *dev)
 
        /* Unload the driver, release IRQs */
        bnx2x_nic_unload(bp, UNLOAD_CLOSE);
-       if (atomic_read(&bp->pdev->enable_cnt) == 1)
-               if (!CHIP_REV_IS_SLOW(bp))
-                       bnx2x_set_power_state(bp, PCI_D3hot);
+       bnx2x_set_power_state(bp, PCI_D3hot);
 
        return 0;
 }
@@ -10815,35 +12591,35 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
                rx_mode = BNX2X_RX_MODE_PROMISC;
 
        else if ((dev->flags & IFF_ALLMULTI) ||
-                ((dev->mc_count > BNX2X_MAX_MULTICAST) && CHIP_IS_E1(bp)))
+                ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) &&
+                 CHIP_IS_E1(bp)))
                rx_mode = BNX2X_RX_MODE_ALLMULTI;
 
        else { /* some multicasts */
                if (CHIP_IS_E1(bp)) {
                        int i, old, offset;
-                       struct dev_mc_list *mclist;
+                       struct netdev_hw_addr *ha;
                        struct mac_configuration_cmd *config =
                                                bnx2x_sp(bp, mcast_config);
 
-                       for (i = 0, mclist = dev->mc_list;
-                            mclist && (i < dev->mc_count);
-                            i++, mclist = mclist->next) {
-
+                       i = 0;
+                       netdev_for_each_mc_addr(ha, dev) {
                                config->config_table[i].
                                        cam_entry.msb_mac_addr =
-                                       swab16(*(u16 *)&mclist->dmi_addr[0]);
+                                       swab16(*(u16 *)&ha->addr[0]);
                                config->config_table[i].
                                        cam_entry.middle_mac_addr =
-                                       swab16(*(u16 *)&mclist->dmi_addr[2]);
+                                       swab16(*(u16 *)&ha->addr[2]);
                                config->config_table[i].
                                        cam_entry.lsb_mac_addr =
-                                       swab16(*(u16 *)&mclist->dmi_addr[4]);
+                                       swab16(*(u16 *)&ha->addr[4]);
                                config->config_table[i].cam_entry.flags =
                                                        cpu_to_le16(port);
                                config->config_table[i].
                                        target_table_entry.flags = 0;
-                               config->config_table[i].
-                                       target_table_entry.client_id = 0;
+                               config->config_table[i].target_table_entry.
+                                       clients_bit_vector =
+                                               cpu_to_le32(1 << BP_L_ID(bp));
                                config->config_table[i].
                                        target_table_entry.vlan_id = 0;
 
@@ -10855,6 +12631,7 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
                                                cam_entry.middle_mac_addr,
                                   config->config_table[i].
                                                cam_entry.lsb_mac_addr);
+                               i++;
                        }
                        old = config->hdr.length;
                        if (old > i) {
@@ -10880,27 +12657,27 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
                        config->hdr.client_id = bp->fp->cl_id;
                        config->hdr.reserved1 = 0;
 
+                       bp->set_mac_pending++;
+                       smp_wmb();
+
                        bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
                                   U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
                                   U64_LO(bnx2x_sp_mapping(bp, mcast_config)),
                                      0);
                } else { /* E1H */
                        /* Accept one or more multicasts */
-                       struct dev_mc_list *mclist;
+                       struct netdev_hw_addr *ha;
                        u32 mc_filter[MC_HASH_SIZE];
                        u32 crc, bit, regidx;
                        int i;
 
                        memset(mc_filter, 0, 4 * MC_HASH_SIZE);
 
-                       for (i = 0, mclist = dev->mc_list;
-                            mclist && (i < dev->mc_count);
-                            i++, mclist = mclist->next) {
-
+                       netdev_for_each_mc_addr(ha, dev) {
                                DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
-                                  mclist->dmi_addr);
+                                  ha->addr);
 
-                               crc = crc32c_le(0, mclist->dmi_addr, ETH_ALEN);
+                               crc = crc32c_le(0, ha->addr, ETH_ALEN);
                                bit = (crc >> 24) & 0xff;
                                regidx = bit >> 5;
                                bit &= 0x1f;
@@ -10929,63 +12706,86 @@ static int bnx2x_change_mac_addr(struct net_device *dev, void *p)
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
        if (netif_running(dev)) {
                if (CHIP_IS_E1(bp))
-                       bnx2x_set_mac_addr_e1(bp, 1);
+                       bnx2x_set_eth_mac_addr_e1(bp, 1);
                else
-                       bnx2x_set_mac_addr_e1h(bp, 1);
+                       bnx2x_set_eth_mac_addr_e1h(bp, 1);
        }
 
        return 0;
 }
 
 /* called with rtnl_lock */
-static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int bnx2x_mdio_read(struct net_device *netdev, int prtad,
+                          int devad, u16 addr)
 {
-       struct mii_ioctl_data *data = if_mii(ifr);
-       struct bnx2x *bp = netdev_priv(dev);
-       int port = BP_PORT(bp);
-       int err;
+       struct bnx2x *bp = netdev_priv(netdev);
+       u16 value;
+       int rc;
+       u32 phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
 
-       switch (cmd) {
-       case SIOCGMIIPHY:
-               data->phy_id = bp->port.phy_addr;
+       DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n",
+          prtad, devad, addr);
 
-               /* fallthrough */
+       if (prtad != bp->mdio.prtad) {
+               DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
+                  prtad, bp->mdio.prtad);
+               return -EINVAL;
+       }
 
-       case SIOCGMIIREG: {
-               u16 mii_regval;
+       /* The HW expects different devad if CL22 is used */
+       devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
 
-               if (!netif_running(dev))
-                       return -EAGAIN;
+       bnx2x_acquire_phy_lock(bp);
+       rc = bnx2x_cl45_read(bp, BP_PORT(bp), phy_type, prtad,
+                            devad, addr, &value);
+       bnx2x_release_phy_lock(bp);
+       DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc);
 
-               mutex_lock(&bp->port.phy_mutex);
-               err = bnx2x_cl45_read(bp, port, 0, bp->port.phy_addr,
-                                     DEFAULT_PHY_DEV_ADDR,
-                                     (data->reg_num & 0x1f), &mii_regval);
-               data->val_out = mii_regval;
-               mutex_unlock(&bp->port.phy_mutex);
-               return err;
+       if (!rc)
+               rc = value;
+       return rc;
+}
+
+/* called with rtnl_lock */
+static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad,
+                           u16 addr, u16 value)
+{
+       struct bnx2x *bp = netdev_priv(netdev);
+       u32 ext_phy_type = XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config);
+       int rc;
+
+       DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x,"
+                          " value 0x%x\n", prtad, devad, addr, value);
+
+       if (prtad != bp->mdio.prtad) {
+               DP(NETIF_MSG_LINK, "prtad missmatch (cmd:0x%x != bp:0x%x)\n",
+                  prtad, bp->mdio.prtad);
+               return -EINVAL;
        }
 
-       case SIOCSMIIREG:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
+       /* The HW expects different devad if CL22 is used */
+       devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad;
 
-               if (!netif_running(dev))
-                       return -EAGAIN;
+       bnx2x_acquire_phy_lock(bp);
+       rc = bnx2x_cl45_write(bp, BP_PORT(bp), ext_phy_type, prtad,
+                             devad, addr, value);
+       bnx2x_release_phy_lock(bp);
+       return rc;
+}
+
+/* called with rtnl_lock */
+static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       struct mii_ioctl_data *mdio = if_mii(ifr);
 
-               mutex_lock(&bp->port.phy_mutex);
-               err = bnx2x_cl45_write(bp, port, 0, bp->port.phy_addr,
-                                      DEFAULT_PHY_DEV_ADDR,
-                                      (data->reg_num & 0x1f), data->val_in);
-               mutex_unlock(&bp->port.phy_mutex);
-               return err;
+       DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
+          mdio->phy_id, mdio->reg_num, mdio->val_in);
 
-       default:
-               /* do nothing */
-               break;
-       }
+       if (!netif_running(dev))
+               return -EAGAIN;
 
-       return -EOPNOTSUPP;
+       return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
 }
 
 /* called with rtnl_lock */
@@ -10994,6 +12794,11 @@ static int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
        struct bnx2x *bp = netdev_priv(dev);
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) ||
            ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE))
                return -EINVAL;
@@ -11021,7 +12826,7 @@ static void bnx2x_tx_timeout(struct net_device *dev)
                bnx2x_panic();
 #endif
        /* This allows the netif to be shutdown gracefully before resetting */
-       schedule_work(&bp->reset_task);
+       schedule_delayed_work(&bp->reset_task, 0);
 }
 
 #ifdef BCM_VLAN
@@ -11048,7 +12853,7 @@ static void bnx2x_vlan_rx_register(struct net_device *dev,
 
 #endif
 
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
 static void poll_bnx2x(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
@@ -11072,7 +12877,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
 #ifdef BCM_VLAN
        .ndo_vlan_rx_register   = bnx2x_vlan_rx_register,
 #endif
-#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+#ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = poll_bnx2x,
 #endif
 };
@@ -11093,19 +12898,20 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 
        rc = pci_enable_device(pdev);
        if (rc) {
-               printk(KERN_ERR PFX "Cannot enable PCI device, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot enable PCI device, aborting\n");
                goto err_out;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX "Cannot find PCI device base address,"
-                      " aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot find PCI device base address, aborting\n");
                rc = -ENODEV;
                goto err_out_disable;
        }
 
        if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX "Cannot find second PCI device"
+               dev_err(&bp->pdev->dev, "Cannot find second PCI device"
                       " base address, aborting\n");
                rc = -ENODEV;
                goto err_out_disable;
@@ -11114,8 +12920,8 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        if (atomic_read(&pdev->enable_cnt) == 1) {
                rc = pci_request_regions(pdev, DRV_MODULE_NAME);
                if (rc) {
-                       printk(KERN_ERR PFX "Cannot obtain PCI resources,"
-                              " aborting\n");
+                       dev_err(&bp->pdev->dev,
+                               "Cannot obtain PCI resources, aborting\n");
                        goto err_out_disable;
                }
 
@@ -11125,32 +12931,32 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 
        bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
        if (bp->pm_cap == 0) {
-               printk(KERN_ERR PFX "Cannot find power management"
-                      " capability, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot find power management capability, aborting\n");
                rc = -EIO;
                goto err_out_release;
        }
 
        bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
        if (bp->pcie_cap == 0) {
-               printk(KERN_ERR PFX "Cannot find PCI Express capability,"
-                      " aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot find PCI Express capability, aborting\n");
                rc = -EIO;
                goto err_out_release;
        }
 
-       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
+       if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) == 0) {
                bp->flags |= USING_DAC_FLAG;
-               if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
-                       printk(KERN_ERR PFX "pci_set_consistent_dma_mask"
+               if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)) != 0) {
+                       dev_err(&bp->pdev->dev, "dma_set_coherent_mask"
                               " failed, aborting\n");
                        rc = -EIO;
                        goto err_out_release;
                }
 
-       } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
-               printk(KERN_ERR PFX "System does not support DMA,"
-                      " aborting\n");
+       } else if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
+               dev_err(&bp->pdev->dev,
+                       "System does not support DMA, aborting\n");
                rc = -EIO;
                goto err_out_release;
        }
@@ -11163,7 +12969,8 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 
        bp->regview = pci_ioremap_bar(pdev, 0);
        if (!bp->regview) {
-               printk(KERN_ERR PFX "Cannot map register space, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot map register space, aborting\n");
                rc = -ENOMEM;
                goto err_out_release;
        }
@@ -11172,7 +12979,8 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
                                        min_t(u64, BNX2X_DB_SIZE,
                                              pci_resource_len(pdev, 2)));
        if (!bp->doorbells) {
-               printk(KERN_ERR PFX "Cannot map doorbell space, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot map doorbell space, aborting\n");
                rc = -ENOMEM;
                goto err_out_unmap;
        }
@@ -11187,6 +12995,9 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0);
        REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0);
 
+       /* Reset the load counter */
+       bnx2x_clear_load_cnt(bp);
+
        dev->watchdog_timeo = TX_TIMEOUT;
 
        dev->netdev_ops = &bnx2x_netdev_ops;
@@ -11209,6 +13020,14 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        dev->vlan_features |= NETIF_F_TSO6;
 #endif
 
+       /* get_port_hwinfo() will set prtad and mmds properly */
+       bp->mdio.prtad = MDIO_PRTAD_NONE;
+       bp->mdio.mmds = 0;
+       bp->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
+       bp->mdio.dev = dev;
+       bp->mdio.mdio_read = bnx2x_mdio_read;
+       bp->mdio.mdio_write = bnx2x_mdio_write;
+
        return 0;
 
 err_out_unmap:
@@ -11233,31 +13052,26 @@ err_out:
        return rc;
 }
 
-static int __devinit bnx2x_get_pcie_width(struct bnx2x *bp)
+static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp,
+                                                int *width, int *speed)
 {
        u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
 
-       val = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
-       return val;
-}
-
-/* return value of 1=2.5GHz 2=5GHz */
-static int __devinit bnx2x_get_pcie_speed(struct bnx2x *bp)
-{
-       u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL);
+       *width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
 
-       val = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
-       return val;
+       /* return value of 1=2.5GHz 2=5GHz */
+       *speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
 }
+
 static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
 {
+       const struct firmware *firmware = bp->firmware;
        struct bnx2x_fw_file_hdr *fw_hdr;
        struct bnx2x_fw_file_section *sections;
-       u16 *ops_offsets;
        u32 offset, len, num_ops;
+       u16 *ops_offsets;
        int i;
-       const struct firmware *firmware = bp->firmware;
-       const u8 * fw_ver;
+       const u8 *fw_ver;
 
        if (firmware->size < sizeof(struct bnx2x_fw_file_hdr))
                return -EINVAL;
@@ -11271,7 +13085,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
                offset = be32_to_cpu(sections[i].offset);
                len = be32_to_cpu(sections[i].len);
                if (offset + len > firmware->size) {
-                       printk(KERN_ERR PFX "Section %d length is out of bounds\n", i);
+                       dev_err(&bp->pdev->dev,
+                               "Section %d length is out of bounds\n", i);
                        return -EINVAL;
                }
        }
@@ -11283,7 +13098,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
 
        for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
                if (be16_to_cpu(ops_offsets[i]) > num_ops) {
-                       printk(KERN_ERR PFX "Section offset %d is out of bounds\n", i);
+                       dev_err(&bp->pdev->dev,
+                               "Section offset %d is out of bounds\n", i);
                        return -EINVAL;
                }
        }
@@ -11295,24 +13111,24 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
            (fw_ver[1] != BCM_5710_FW_MINOR_VERSION) ||
            (fw_ver[2] != BCM_5710_FW_REVISION_VERSION) ||
            (fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) {
-               printk(KERN_ERR PFX "Bad FW version:%d.%d.%d.%d."
-                                   " Should be %d.%d.%d.%d\n",
+               dev_err(&bp->pdev->dev,
+                       "Bad FW version:%d.%d.%d.%d. Should be %d.%d.%d.%d\n",
                       fw_ver[0], fw_ver[1], fw_ver[2],
                       fw_ver[3], BCM_5710_FW_MAJOR_VERSION,
                       BCM_5710_FW_MINOR_VERSION,
                       BCM_5710_FW_REVISION_VERSION,
                       BCM_5710_FW_ENGINEERING_VERSION);
-                return -EINVAL;
+               return -EINVAL;
        }
 
        return 0;
 }
 
-static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
+static inline void be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
 {
+       const __be32 *source = (const __be32 *)_source;
+       u32 *target = (u32 *)_target;
        u32 i;
-       const __be32 *source = (const __be32*)_source;
-       u32 *target = (u32*)_target;
 
        for (i = 0; i < n/4; i++)
                target[i] = be32_to_cpu(source[i]);
@@ -11322,72 +13138,68 @@ static void inline be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
    Ops array is stored in the following format:
    {op(8bit), offset(24bit, big endian), data(32bit, big endian)}
  */
-static void inline bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n)
+static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n)
 {
+       const __be32 *source = (const __be32 *)_source;
+       struct raw_op *target = (struct raw_op *)_target;
        u32 i, j, tmp;
-       const __be32 *source = (const __be32*)_source;
-       struct raw_op *target = (struct raw_op*)_target;
 
-       for (i = 0, j = 0; i < n/8; i++, j+=2) {
+       for (i = 0, j = 0; i < n/8; i++, j += 2) {
                tmp = be32_to_cpu(source[j]);
                target[i].op = (tmp >> 24) & 0xff;
-               target[i].offset =  tmp & 0xffffff;
-               target[i].raw_data = be32_to_cpu(source[j+1]);
+               target[i].offset = tmp & 0xffffff;
+               target[i].raw_data = be32_to_cpu(source[j + 1]);
        }
 }
-static void inline be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
+
+static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n)
 {
+       const __be16 *source = (const __be16 *)_source;
+       u16 *target = (u16 *)_target;
        u32 i;
-       u16 *target = (u16*)_target;
-       const __be16 *source = (const __be16*)_source;
 
        for (i = 0; i < n/2; i++)
                target[i] = be16_to_cpu(source[i]);
 }
 
-#define BNX2X_ALLOC_AND_SET(arr, lbl, func) \
-       do {   \
-               u32 len = be32_to_cpu(fw_hdr->arr.len);   \
-               bp->arr = kmalloc(len, GFP_KERNEL);  \
-               if (!bp->arr) { \
-                       printk(KERN_ERR PFX "Failed to allocate %d bytes for "#arr"\n", len); \
-                       goto lbl; \
-               } \
-               func(bp->firmware->data + \
-                       be32_to_cpu(fw_hdr->arr.offset), \
-                       (u8*)bp->arr, len); \
-       } while (0)
-
+#define BNX2X_ALLOC_AND_SET(arr, lbl, func)                            \
+do {                                                                   \
+       u32 len = be32_to_cpu(fw_hdr->arr.len);                         \
+       bp->arr = kmalloc(len, GFP_KERNEL);                             \
+       if (!bp->arr) {                                                 \
+               pr_err("Failed to allocate %d bytes for "#arr"\n", len); \
+               goto lbl;                                               \
+       }                                                               \
+       func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset),      \
+            (u8 *)bp->arr, len);                                       \
+} while (0)
 
 static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
 {
-       char fw_file_name[40] = {0};
-        int rc, offset;
+       const char *fw_file_name;
        struct bnx2x_fw_file_hdr *fw_hdr;
+       int rc;
 
-       /* Create a FW file name */
        if (CHIP_IS_E1(bp))
-                offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1);
-       else
-               offset = sprintf(fw_file_name, FW_FILE_PREFIX_E1H);
-
-       sprintf(fw_file_name + offset, "%d.%d.%d.%d.fw",
-               BCM_5710_FW_MAJOR_VERSION,
-                BCM_5710_FW_MINOR_VERSION,
-                BCM_5710_FW_REVISION_VERSION,
-                BCM_5710_FW_ENGINEERING_VERSION);
+               fw_file_name = FW_FILE_NAME_E1;
+       else if (CHIP_IS_E1H(bp))
+               fw_file_name = FW_FILE_NAME_E1H;
+       else {
+               dev_err(dev, "Unsupported chip revision\n");
+               return -EINVAL;
+       }
 
-       printk(KERN_INFO PFX "Loading %s\n", fw_file_name);
+       dev_info(dev, "Loading %s\n", fw_file_name);
 
        rc = request_firmware(&bp->firmware, fw_file_name, dev);
        if (rc) {
-               printk(KERN_ERR PFX "Can't load firmware file %s\n", fw_file_name);
+               dev_err(dev, "Can't load firmware file %s\n", fw_file_name);
                goto request_firmware_exit;
        }
 
        rc = bnx2x_check_firmware(bp);
        if (rc) {
-               printk(KERN_ERR PFX "Corrupt firmware file %s\n", fw_file_name);
+               dev_err(dev, "Corrupt firmware file %s\n", fw_file_name);
                goto request_firmware_exit;
        }
 
@@ -11401,27 +13213,29 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
        BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops);
 
        /* Offsets */
-       BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, be16_to_cpu_n);
+       BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err,
+                           be16_to_cpu_n);
 
        /* STORMs firmware */
-       bp->tsem_int_table_data = bp->firmware->data +
-               be32_to_cpu(fw_hdr->tsem_int_table_data.offset);
-       bp->tsem_pram_data      = bp->firmware->data +
-               be32_to_cpu(fw_hdr->tsem_pram_data.offset);
-       bp->usem_int_table_data = bp->firmware->data +
-               be32_to_cpu(fw_hdr->usem_int_table_data.offset);
-       bp->usem_pram_data      = bp->firmware->data +
-               be32_to_cpu(fw_hdr->usem_pram_data.offset);
-       bp->xsem_int_table_data = bp->firmware->data +
-               be32_to_cpu(fw_hdr->xsem_int_table_data.offset);
-       bp->xsem_pram_data      = bp->firmware->data +
-               be32_to_cpu(fw_hdr->xsem_pram_data.offset);
-       bp->csem_int_table_data = bp->firmware->data +
-               be32_to_cpu(fw_hdr->csem_int_table_data.offset);
-       bp->csem_pram_data      = bp->firmware->data +
-               be32_to_cpu(fw_hdr->csem_pram_data.offset);
+       INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->tsem_int_table_data.offset);
+       INIT_TSEM_PRAM_DATA(bp)      = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->tsem_pram_data.offset);
+       INIT_USEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->usem_int_table_data.offset);
+       INIT_USEM_PRAM_DATA(bp)      = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->usem_pram_data.offset);
+       INIT_XSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->xsem_int_table_data.offset);
+       INIT_XSEM_PRAM_DATA(bp)      = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->xsem_pram_data.offset);
+       INIT_CSEM_INT_TABLE_DATA(bp) = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->csem_int_table_data.offset);
+       INIT_CSEM_PRAM_DATA(bp)      = bp->firmware->data +
+                       be32_to_cpu(fw_hdr->csem_pram_data.offset);
 
        return 0;
+
 init_offsets_alloc_err:
        kfree(bp->init_ops);
 init_ops_alloc_err:
@@ -11433,27 +13247,25 @@ request_firmware_exit:
 }
 
 
-
 static int __devinit bnx2x_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
-       static int version_printed;
        struct net_device *dev = NULL;
        struct bnx2x *bp;
+       int pcie_width, pcie_speed;
        int rc;
 
-       if (version_printed++ == 0)
-               printk(KERN_INFO "%s", version);
-
        /* dev zeroed in init_etherdev */
        dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT);
        if (!dev) {
-               printk(KERN_ERR PFX "Cannot allocate net device\n");
+               dev_err(&pdev->dev, "Cannot allocate net device\n");
                return -ENOMEM;
        }
 
        bp = netdev_priv(dev);
-       bp->msglevel = debug;
+       bp->msg_enable = debug;
+
+       pci_set_drvdata(pdev, dev);
 
        rc = bnx2x_init_dev(pdev, dev);
        if (rc < 0) {
@@ -11461,8 +13273,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
                return rc;
        }
 
-       pci_set_drvdata(pdev, dev);
-
        rc = bnx2x_init_bp(bp);
        if (rc)
                goto init_one_exit;
@@ -11470,7 +13280,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        /* Set init arrays */
        rc = bnx2x_init_firmware(bp, &pdev->dev);
        if (rc) {
-               printk(KERN_ERR PFX "Error loading firmware\n");
+               dev_err(&pdev->dev, "Error loading firmware\n");
                goto init_one_exit;
        }
 
@@ -11480,13 +13290,13 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
                goto init_one_exit;
        }
 
-       printk(KERN_INFO "%s: %s (%c%d) PCI-E x%d %s found at mem %lx,"
-              " IRQ %d, ", dev->name, board_info[ent->driver_data].name,
+       bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
+       netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx,"
+              " IRQ %d, ", board_info[ent->driver_data].name,
               (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
-              bnx2x_get_pcie_width(bp),
-              (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz",
+              pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
               dev->base_addr, bp->pdev->irq);
-       printk(KERN_CONT "node addr %pM\n", dev->dev_addr);
+       pr_cont("node addr %pM\n", dev->dev_addr);
 
        return 0;
 
@@ -11514,13 +13324,16 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
        struct bnx2x *bp;
 
        if (!dev) {
-               printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+               dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
                return;
        }
        bp = netdev_priv(dev);
 
        unregister_netdev(dev);
 
+       /* Make sure RESET task is not scheduled before continuing */
+       cancel_delayed_work_sync(&bp->reset_task);
+
        kfree(bp->init_ops_offsets);
        kfree(bp->init_ops);
        kfree(bp->init_data);
@@ -11547,7 +13360,7 @@ static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
        struct bnx2x *bp;
 
        if (!dev) {
-               printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+               dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
                return -ENODEV;
        }
        bp = netdev_priv(dev);
@@ -11579,11 +13392,16 @@ static int bnx2x_resume(struct pci_dev *pdev)
        int rc;
 
        if (!dev) {
-               printk(KERN_ERR PFX "BAD net device from bnx2x_init_one\n");
+               dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
                return -ENODEV;
        }
        bp = netdev_priv(dev);
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        rtnl_lock();
 
        pci_restore_state(pdev);
@@ -11612,13 +13430,14 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
        bp->rx_mode = BNX2X_RX_MODE_NONE;
 
        bnx2x_netif_stop(bp, 0);
+       netif_carrier_off(bp->dev);
 
        del_timer_sync(&bp->timer);
        bp->stats_state = STATS_STATE_DISABLED;
        DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
 
        /* Release IRQs */
-       bnx2x_free_irq(bp);
+       bnx2x_free_irq(bp, false);
 
        if (CHIP_IS_E1(bp)) {
                struct mac_configuration_cmd *config =
@@ -11630,16 +13449,14 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
 
        /* Free SKBs, SGEs, TPA pool and driver internals */
        bnx2x_free_skbs(bp);
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-       for_each_rx_queue(bp, i)
+       for_each_queue(bp, i)
                netif_napi_del(&bnx2x_fp(bp, i, napi));
        bnx2x_free_mem(bp);
 
        bp->state = BNX2X_STATE_CLOSED;
 
-       netif_carrier_off(bp->dev);
-
        return 0;
 }
 
@@ -11750,6 +13567,11 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct bnx2x *bp = netdev_priv(dev);
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return;
+       }
+
        rtnl_lock();
 
        bnx2x_eeh_recover(bp);
@@ -11782,15 +13604,17 @@ static int __init bnx2x_init(void)
 {
        int ret;
 
+       pr_info("%s", version);
+
        bnx2x_wq = create_singlethread_workqueue("bnx2x");
        if (bnx2x_wq == NULL) {
-               printk(KERN_ERR PFX "Cannot create workqueue\n");
+               pr_err("Cannot create workqueue\n");
                return -ENOMEM;
        }
 
        ret = pci_register_driver(&bnx2x_pci_driver);
        if (ret) {
-               printk(KERN_ERR PFX "Cannot register driver\n");
+               pr_err("Cannot register driver\n");
                destroy_workqueue(bnx2x_wq);
        }
        return ret;
@@ -11806,4 +13630,287 @@ static void __exit bnx2x_cleanup(void)
 module_init(bnx2x_init);
 module_exit(bnx2x_cleanup);
 
+#ifdef BCM_CNIC
+
+/* count denotes the number of new completions we have seen */
+static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
+{
+       struct eth_spe *spe;
+
+#ifdef BNX2X_STOP_ON_ERROR
+       if (unlikely(bp->panic))
+               return;
+#endif
+
+       spin_lock_bh(&bp->spq_lock);
+       bp->cnic_spq_pending -= count;
+
+       for (; bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending;
+            bp->cnic_spq_pending++) {
+
+               if (!bp->cnic_kwq_pending)
+                       break;
+
+               spe = bnx2x_sp_get_next(bp);
+               *spe = *bp->cnic_kwq_cons;
+
+               bp->cnic_kwq_pending--;
+
+               DP(NETIF_MSG_TIMER, "pending on SPQ %d, on KWQ %d count %d\n",
+                  bp->cnic_spq_pending, bp->cnic_kwq_pending, count);
+
+               if (bp->cnic_kwq_cons == bp->cnic_kwq_last)
+                       bp->cnic_kwq_cons = bp->cnic_kwq;
+               else
+                       bp->cnic_kwq_cons++;
+       }
+       bnx2x_sp_prod_update(bp);
+       spin_unlock_bh(&bp->spq_lock);
+}
+
+static int bnx2x_cnic_sp_queue(struct net_device *dev,
+                              struct kwqe_16 *kwqes[], u32 count)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       int i;
+
+#ifdef BNX2X_STOP_ON_ERROR
+       if (unlikely(bp->panic))
+               return -EIO;
+#endif
+
+       spin_lock_bh(&bp->spq_lock);
+
+       for (i = 0; i < count; i++) {
+               struct eth_spe *spe = (struct eth_spe *)kwqes[i];
+
+               if (bp->cnic_kwq_pending == MAX_SP_DESC_CNT)
+                       break;
+
+               *bp->cnic_kwq_prod = *spe;
+
+               bp->cnic_kwq_pending++;
+
+               DP(NETIF_MSG_TIMER, "L5 SPQE %x %x %x:%x pos %d\n",
+                  spe->hdr.conn_and_cmd_data, spe->hdr.type,
+                  spe->data.mac_config_addr.hi,
+                  spe->data.mac_config_addr.lo,
+                  bp->cnic_kwq_pending);
+
+               if (bp->cnic_kwq_prod == bp->cnic_kwq_last)
+                       bp->cnic_kwq_prod = bp->cnic_kwq;
+               else
+                       bp->cnic_kwq_prod++;
+       }
+
+       spin_unlock_bh(&bp->spq_lock);
+
+       if (bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending)
+               bnx2x_cnic_sp_post(bp, 0);
+
+       return i;
+}
+
+static int bnx2x_cnic_ctl_send(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+       struct cnic_ops *c_ops;
+       int rc = 0;
+
+       mutex_lock(&bp->cnic_mutex);
+       c_ops = bp->cnic_ops;
+       if (c_ops)
+               rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+       mutex_unlock(&bp->cnic_mutex);
+
+       return rc;
+}
+
+static int bnx2x_cnic_ctl_send_bh(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+       struct cnic_ops *c_ops;
+       int rc = 0;
+
+       rcu_read_lock();
+       c_ops = rcu_dereference(bp->cnic_ops);
+       if (c_ops)
+               rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+       rcu_read_unlock();
+
+       return rc;
+}
+
+/*
+ * for commands that have no data
+ */
+static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd)
+{
+       struct cnic_ctl_info ctl = {0};
+
+       ctl.cmd = cmd;
+
+       return bnx2x_cnic_ctl_send(bp, &ctl);
+}
+
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid)
+{
+       struct cnic_ctl_info ctl;
+
+       /* first we tell CNIC and only then we count this as a completion */
+       ctl.cmd = CNIC_CTL_COMPLETION_CMD;
+       ctl.data.comp.cid = cid;
+
+       bnx2x_cnic_ctl_send_bh(bp, &ctl);
+       bnx2x_cnic_sp_post(bp, 1);
+}
+
+static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       int rc = 0;
+
+       switch (ctl->cmd) {
+       case DRV_CTL_CTXTBL_WR_CMD: {
+               u32 index = ctl->data.io.offset;
+               dma_addr_t addr = ctl->data.io.dma_addr;
+
+               bnx2x_ilt_wr(bp, index, addr);
+               break;
+       }
+
+       case DRV_CTL_COMPLETION_CMD: {
+               int count = ctl->data.comp.comp_count;
+
+               bnx2x_cnic_sp_post(bp, count);
+               break;
+       }
+
+       /* rtnl_lock is held.  */
+       case DRV_CTL_START_L2_CMD: {
+               u32 cli = ctl->data.ring.client_id;
+
+               bp->rx_mode_cl_mask |= (1 << cli);
+               bnx2x_set_storm_rx_mode(bp);
+               break;
+       }
+
+       /* rtnl_lock is held.  */
+       case DRV_CTL_STOP_L2_CMD: {
+               u32 cli = ctl->data.ring.client_id;
+
+               bp->rx_mode_cl_mask &= ~(1 << cli);
+               bnx2x_set_storm_rx_mode(bp);
+               break;
+       }
+
+       default:
+               BNX2X_ERR("unknown command %x\n", ctl->cmd);
+               rc = -EINVAL;
+       }
+
+       return rc;
+}
+
+static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
+{
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+       if (bp->flags & USING_MSIX_FLAG) {
+               cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
+               cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
+               cp->irq_arr[0].vector = bp->msix_table[1].vector;
+       } else {
+               cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
+               cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
+       }
+       cp->irq_arr[0].status_blk = bp->cnic_sb;
+       cp->irq_arr[0].status_blk_num = CNIC_SB_ID(bp);
+       cp->irq_arr[1].status_blk = bp->def_status_blk;
+       cp->irq_arr[1].status_blk_num = DEF_SB_ID;
+
+       cp->num_irq = 2;
+}
+
+static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
+                              void *data)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+       if (ops == NULL)
+               return -EINVAL;
+
+       if (atomic_read(&bp->intr_sem) != 0)
+               return -EBUSY;
+
+       bp->cnic_kwq = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!bp->cnic_kwq)
+               return -ENOMEM;
+
+       bp->cnic_kwq_cons = bp->cnic_kwq;
+       bp->cnic_kwq_prod = bp->cnic_kwq;
+       bp->cnic_kwq_last = bp->cnic_kwq + MAX_SP_DESC_CNT;
+
+       bp->cnic_spq_pending = 0;
+       bp->cnic_kwq_pending = 0;
+
+       bp->cnic_data = data;
+
+       cp->num_irq = 0;
+       cp->drv_state = CNIC_DRV_STATE_REGD;
+
+       bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping, CNIC_SB_ID(bp));
+
+       bnx2x_setup_cnic_irq_info(bp);
+       bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+       bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+       rcu_assign_pointer(bp->cnic_ops, ops);
+
+       return 0;
+}
+
+static int bnx2x_unregister_cnic(struct net_device *dev)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+       mutex_lock(&bp->cnic_mutex);
+       if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+               bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+               bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+       }
+       cp->drv_state = 0;
+       rcu_assign_pointer(bp->cnic_ops, NULL);
+       mutex_unlock(&bp->cnic_mutex);
+       synchronize_rcu();
+       kfree(bp->cnic_kwq);
+       bp->cnic_kwq = NULL;
+
+       return 0;
+}
+
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+       struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+       cp->drv_owner = THIS_MODULE;
+       cp->chip_id = CHIP_ID(bp);
+       cp->pdev = bp->pdev;
+       cp->io_base = bp->regview;
+       cp->io_base2 = bp->doorbells;
+       cp->max_kwqe_pending = 8;
+       cp->ctx_blk_size = CNIC_CTX_PER_ILT * sizeof(union cdu_context);
+       cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) + 1;
+       cp->ctx_tbl_len = CNIC_ILT_LINES;
+       cp->starting_cid = BCM_CNIC_CID_START;
+       cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue;
+       cp->drv_ctl = bnx2x_drv_ctl;
+       cp->drv_register_cnic = bnx2x_register_cnic;
+       cp->drv_unregister_cnic = bnx2x_unregister_cnic;
+
+       return cp;
+}
+EXPORT_SYMBOL(bnx2x_cnic_probe);
+
+#endif /* BCM_CNIC */