]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/qlcnic/qlcnic_main.c
qlcnic: change driver description
[net-next-2.6.git] / drivers / net / qlcnic / qlcnic_main.c
index 234dab1f99823c588e2532ba6ea0a6e35ed6a8e0..28ed28c1cbccbe695da2310aebe98612263e4fdb 100644 (file)
 #include <linux/inetdevice.h>
 #include <linux/sysfs.h>
 
-MODULE_DESCRIPTION("QLogic 10 GbE Converged Ethernet Driver");
+MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(QLCNIC_LINUX_VERSIONID);
 MODULE_FIRMWARE(QLCNIC_UNIFIED_ROMIMAGE_NAME);
 
 char qlcnic_driver_name[] = "qlcnic";
-static const char qlcnic_driver_string[] = "QLogic Converged Ethernet Driver v"
-    QLCNIC_LINUX_VERSIONID;
+static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
+       "Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
 
 static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
 
@@ -61,6 +61,14 @@ static int auto_fw_reset = AUTO_FW_RESET_ENABLED;
 module_param(auto_fw_reset, int, 0644);
 MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
 
+static int load_fw_file;
+module_param(load_fw_file, int, 0644);
+MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
+
+static int qlcnic_config_npars;
+module_param(qlcnic_config_npars, int, 0644);
+MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
+
 static int __devinit qlcnic_probe(struct pci_dev *pdev,
                const struct pci_device_id *ent);
 static void __devexit qlcnic_remove(struct pci_dev *pdev);
@@ -84,6 +92,7 @@ static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
 static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
 static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
 
+static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
 static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
 static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
 
@@ -94,7 +103,14 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data);
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
 static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
-
+static int qlcnic_start_firmware(struct qlcnic_adapter *);
+
+static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
+static void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -208,6 +224,9 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter)
        struct qlcnic_host_sds_ring *sds_ring;
        struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
 
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
                napi_enable(&sds_ring->napi);
@@ -222,6 +241,9 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter)
        struct qlcnic_host_sds_ring *sds_ring;
        struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
 
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
                qlcnic_disable_int(sds_ring);
@@ -233,67 +255,6 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter)
 static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
 {
        memset(&adapter->stats, 0, sizeof(adapter->stats));
-       return;
-}
-
-static int qlcnic_set_dma_mask(struct qlcnic_adapter *adapter)
-{
-       struct pci_dev *pdev = adapter->pdev;
-       u64 mask, cmask;
-
-       adapter->pci_using_dac = 0;
-
-       mask = DMA_BIT_MASK(39);
-       cmask = mask;
-
-       if (pci_set_dma_mask(pdev, mask) == 0 &&
-                       pci_set_consistent_dma_mask(pdev, cmask) == 0) {
-               adapter->pci_using_dac = 1;
-               return 0;
-       }
-
-       return -EIO;
-}
-
-/* Update addressable range if firmware supports it */
-static int
-qlcnic_update_dma_mask(struct qlcnic_adapter *adapter)
-{
-       int change, shift, err;
-       u64 mask, old_mask, old_cmask;
-       struct pci_dev *pdev = adapter->pdev;
-
-       change = 0;
-
-       shift = QLCRD32(adapter, CRB_DMA_SHIFT);
-       if (shift > 32)
-               return 0;
-
-       if (shift > 9)
-               change = 1;
-
-       if (change) {
-               old_mask = pdev->dma_mask;
-               old_cmask = pdev->dev.coherent_dma_mask;
-
-               mask = DMA_BIT_MASK(32+shift);
-
-               err = pci_set_dma_mask(pdev, mask);
-               if (err)
-                       goto err_out;
-
-               err = pci_set_consistent_dma_mask(pdev, mask);
-               if (err)
-                       goto err_out;
-               dev_info(&pdev->dev, "using %d-bit dma mask\n", 32+shift);
-       }
-
-       return 0;
-
-err_out:
-       pci_set_dma_mask(pdev, old_mask);
-       pci_set_consistent_dma_mask(pdev, old_cmask);
-       return err;
 }
 
 static void qlcnic_set_port_mode(struct qlcnic_adapter *adapter)
@@ -357,19 +318,14 @@ static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
 static int
 qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
 {
-       int i;
-       unsigned char *p;
-       u64 mac_addr;
+       u8 mac_addr[ETH_ALEN];
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
 
-       if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0)
+       if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
                return -EIO;
 
-       p = (unsigned char *)&mac_addr;
-       for (i = 0; i < 6; i++)
-               netdev->dev_addr[i] = *(p + 5 - i);
-
+       memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
        memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
        memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
 
@@ -421,6 +377,33 @@ static const struct net_device_ops qlcnic_netdev_ops = {
 #endif
 };
 
+static struct qlcnic_nic_template qlcnic_ops = {
+       .get_mac_addr = qlcnic_get_mac_addr,
+       .config_bridged_mode = qlcnic_config_bridged_mode,
+       .config_led = qlcnic_config_led,
+       .set_ilb_mode = qlcnic_set_ilb_mode,
+       .clear_ilb_mode = qlcnic_clear_ilb_mode,
+       .start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_pf_ops = {
+       .get_mac_addr = qlcnic_get_mac_address,
+       .config_bridged_mode = qlcnic_config_bridged_mode,
+       .config_led = qlcnic_config_led,
+       .set_ilb_mode = qlcnic_set_ilb_mode,
+       .clear_ilb_mode = qlcnic_clear_ilb_mode,
+       .start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_vf_ops = {
+       .get_mac_addr = qlcnic_get_mac_address,
+       .config_bridged_mode = qlcnicvf_config_bridged_mode,
+       .config_led = qlcnicvf_config_led,
+       .set_ilb_mode = qlcnicvf_set_ilb_mode,
+       .clear_ilb_mode = qlcnicvf_clear_ilb_mode,
+       .start_firmware = qlcnicvf_start_firmware
+};
+
 static void
 qlcnic_setup_intr(struct qlcnic_adapter *adapter)
 {
@@ -502,6 +485,121 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
                iounmap(adapter->ahw.pci_base0);
 }
 
+static int
+qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
+{
+       u8 id;
+       u32 ref_count;
+       int i, ret = 1;
+       u32 data = QLCNIC_MGMT_FUNC;
+       void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+
+       /* If other drivers are not in use set their privilege level */
+       ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+       ret = qlcnic_api_lock(adapter);
+       if (ret)
+               goto err_lock;
+       if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
+               goto err_npar;
+
+       if (qlcnic_config_npars) {
+               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+                       id = adapter->npars[i].id;
+                       if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
+                               id == adapter->ahw.pci_func)
+                               continue;
+                       data |= (qlcnic_config_npars &
+                                       QLC_DEV_SET_DRV(0xf, id));
+               }
+       } else {
+               data = readl(priv_op);
+               data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw.pci_func)) |
+                       (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
+                       adapter->ahw.pci_func));
+       }
+       writel(data, priv_op);
+err_npar:
+       qlcnic_api_unlock(adapter);
+err_lock:
+       return ret;
+}
+
+static u32
+qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+{
+       void __iomem *msix_base_addr;
+       void __iomem *priv_op;
+       u32 func;
+       u32 msix_base;
+       u32 op_mode, priv_level;
+
+       /* Determine FW API version */
+       adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
+       if (adapter->fw_hal_version == ~0) {
+               adapter->nic_ops = &qlcnic_ops;
+               adapter->fw_hal_version = QLCNIC_FW_BASE;
+               adapter->ahw.pci_func = PCI_FUNC(adapter->pdev->devfn);
+               adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+               dev_info(&adapter->pdev->dev,
+                       "FW does not support nic partion\n");
+               return adapter->fw_hal_version;
+       }
+
+       /* Find PCI function number */
+       pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+       msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
+       msix_base = readl(msix_base_addr);
+       func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
+       adapter->ahw.pci_func = func;
+
+       qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+               adapter->nic_ops = &qlcnic_ops;
+               return adapter->fw_hal_version;
+       }
+
+       /* Determine function privilege level */
+       priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+       op_mode = readl(priv_op);
+       if (op_mode == QLC_DEV_DRV_DEFAULT)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+       switch (priv_level) {
+       case QLCNIC_MGMT_FUNC:
+               adapter->op_mode = QLCNIC_MGMT_FUNC;
+               adapter->nic_ops = &qlcnic_pf_ops;
+               qlcnic_get_pci_info(adapter);
+               /* Set privilege level for other functions */
+               qlcnic_set_function_modes(adapter);
+               dev_info(&adapter->pdev->dev,
+                       "HAL Version: %d, Management function\n",
+                       adapter->fw_hal_version);
+               break;
+       case QLCNIC_PRIV_FUNC:
+               adapter->op_mode = QLCNIC_PRIV_FUNC;
+               dev_info(&adapter->pdev->dev,
+                       "HAL Version: %d, Privileged function\n",
+                       adapter->fw_hal_version);
+               adapter->nic_ops = &qlcnic_pf_ops;
+               break;
+       case QLCNIC_NON_PRIV_FUNC:
+               adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
+               dev_info(&adapter->pdev->dev,
+                       "HAL Version: %d Non Privileged function\n",
+                       adapter->fw_hal_version);
+               adapter->nic_ops = &qlcnic_vf_ops;
+               break;
+       default:
+               dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
+                       priv_level);
+               return 0;
+       }
+       return adapter->fw_hal_version;
+}
+
 static int
 qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
 {
@@ -510,14 +608,6 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        unsigned long mem_len, pci_len0 = 0;
 
        struct pci_dev *pdev = adapter->pdev;
-       int pci_func = adapter->ahw.pci_func;
-
-       /*
-        * Set the CRB window to invalid. If any register in window 0 is
-        * accessed it should set the window to 0 and then reset it to 1.
-        */
-       adapter->ahw.crb_win = -1;
-       adapter->ahw.ocm_win = -1;
 
        /* remap phys address */
        mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
@@ -540,8 +630,13 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        adapter->ahw.pci_base0 = mem_ptr0;
        adapter->ahw.pci_len0 = pci_len0;
 
+       if (!qlcnic_get_driver_mode(adapter)) {
+               iounmap(adapter->ahw.pci_base0);
+               return -EIO;
+       }
+
        adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
-               QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+               QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
 
        return 0;
 }
@@ -556,7 +651,9 @@ static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
                        qlcnic_boards[i].device == pdev->device &&
                        qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
                        qlcnic_boards[i].sub_device == pdev->subsystem_device) {
-                               strcpy(name, qlcnic_boards[i].short_name);
+                               sprintf(name, "%pM: %s" ,
+                                       adapter->mac_addr,
+                                       qlcnic_boards[i].short_name);
                                found = 1;
                                break;
                }
@@ -564,7 +661,7 @@ static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
        }
 
        if (!found)
-               name = "Unknown";
+               sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
 }
 
 static void
@@ -605,22 +702,8 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
                                brd_name, adapter->ahw.revision_id);
        }
 
-       if (adapter->fw_version < QLCNIC_VERSION_CODE(3, 4, 216)) {
-               adapter->driver_mismatch = 1;
-               dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n",
-                               fw_major, fw_minor, fw_build);
-               return;
-       }
-
-       i = QLCRD32(adapter, QLCNIC_SRE_MISC);
-       adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0;
-
-       dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n",
-                       fw_major, fw_minor, fw_build,
-                       adapter->ahw.cut_through ? "cut-through" : "legacy");
-
-       if (adapter->fw_version >= QLCNIC_VERSION_CODE(4, 0, 222))
-               adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+       dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
+                       fw_major, fw_minor, fw_build);
 
        adapter->flags &= ~QLCNIC_LRO_ENABLED;
 
@@ -632,12 +715,13 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
                adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
        }
 
+       qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+
        adapter->msix_supported = !!use_msi_x;
        adapter->rss_supported = !!use_msi_x;
 
        adapter->num_txd = MAX_CMD_DESCRIPTORS;
 
-       adapter->num_lro_rxd = 0;
        adapter->max_rds_rings = 2;
 }
 
@@ -646,11 +730,10 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
 {
        int val, err, first_boot;
 
-       err = qlcnic_set_dma_mask(adapter);
-       if (err)
+       err = qlcnic_can_start_firmware(adapter);
+       if (err < 0)
                return err;
-
-       if (!qlcnic_can_start_firmware(adapter))
+       else if (!err)
                goto wait_init;
 
        first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc));
@@ -658,7 +741,10 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
                /* This is the first boot after power up */
                QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
 
-       qlcnic_request_firmware(adapter);
+       if (load_fw_file)
+               qlcnic_request_firmware(adapter);
+       else
+               adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
 
        err = qlcnic_need_fw_reset(adapter);
        if (err < 0)
@@ -672,7 +758,6 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
                msleep(1);
        }
 
-       QLCWR32(adapter, CRB_DMA_SHIFT, 0x55555555);
        QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
        QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
 
@@ -696,16 +781,22 @@ wait_init:
                goto err_out;
 
        QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
-
-       qlcnic_update_dma_mask(adapter);
+       qlcnic_idc_debug_info(adapter, 1);
 
        qlcnic_check_options(adapter);
 
+       if (adapter->flags & QLCNIC_ESWITCH_ENABLED &&
+               adapter->op_mode != QLCNIC_NON_PRIV_FUNC)
+               qlcnic_dev_set_npar_ready(adapter);
+
        adapter->need_fw_reset = 0;
 
-       /* fall through and release firmware */
+       qlcnic_release_firmware(adapter);
+       return 0;
 
 err_out:
+       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+       dev_err(&adapter->pdev->dev, "Device state set to failed\n");
        qlcnic_release_firmware(adapter);
        return err;
 }
@@ -937,6 +1028,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
        struct qlcnic_host_sds_ring *sds_ring;
        int ring;
 
+       clear_bit(__QLCNIC_DEV_UP, &adapter->state);
        if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx.sds_rings[ring];
@@ -950,11 +1042,11 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
        adapter->max_sds_rings = max_sds_rings;
 
        if (qlcnic_attach(adapter))
-               return;
+               goto out;
 
        if (netif_running(netdev))
                __qlcnic_up(adapter, netdev);
-
+out:
        netif_device_attach(netdev);
 }
 
@@ -976,8 +1068,10 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
        adapter->diag_test = test;
 
        ret = qlcnic_attach(adapter);
-       if (ret)
+       if (ret) {
+               netif_device_attach(netdev);
                return ret;
+       }
 
        if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
@@ -985,6 +1079,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
                        qlcnic_enable_int(sds_ring);
                }
        }
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
 
        return 0;
 }
@@ -1010,23 +1105,19 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter)
                if (netif_running(netdev)) {
                        err = qlcnic_attach(adapter);
                        if (!err)
-                               err = __qlcnic_up(adapter, netdev);
-
-                       if (err)
-                               goto done;
+                               __qlcnic_up(adapter, netdev);
                }
 
                netif_device_attach(netdev);
        }
 
-done:
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
        return err;
 }
 
 static int
 qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
-               struct net_device *netdev)
+               struct net_device *netdev, u8 pci_using_dac)
 {
        int err;
        struct pci_dev *pdev = adapter->pdev;
@@ -1042,14 +1133,13 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
 
        SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
 
-       netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
-       netdev->features |= (NETIF_F_GRO);
-       netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+       netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+               NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6);
 
-       netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
-       netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+       netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+               NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6);
 
-       if (adapter->pci_using_dac) {
+       if (pci_using_dac) {
                netdev->features |= NETIF_F_HIGHDMA;
                netdev->vlan_features |= NETIF_F_HIGHDMA;
        }
@@ -1079,14 +1169,30 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        return 0;
 }
 
+static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
+{
+       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+                       !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))
+               *pci_using_dac = 1;
+       else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) &&
+                       !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+               *pci_using_dac = 0;
+       else {
+               dev_err(&pdev->dev, "Unable to set DMA mask, aborting\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static int __devinit
 qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct net_device *netdev = NULL;
        struct qlcnic_adapter *adapter = NULL;
        int err;
-       int pci_func_id = PCI_FUNC(pdev->devfn);
        uint8_t revision_id;
+       uint8_t pci_using_dac;
 
        err = pci_enable_device(pdev);
        if (err)
@@ -1097,6 +1203,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_disable_pdev;
        }
 
+       err = qlcnic_set_dma_mask(pdev, &pci_using_dac);
+       if (err)
+               goto err_out_disable_pdev;
+
        err = pci_request_regions(pdev, qlcnic_driver_name);
        if (err)
                goto err_out_disable_pdev;
@@ -1115,7 +1225,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter = netdev_priv(netdev);
        adapter->netdev  = netdev;
        adapter->pdev    = pdev;
-       adapter->ahw.pci_func  = pci_func_id;
+       adapter->dev_rst_time = jiffies;
 
        revision_id = pdev->revision;
        adapter->ahw.revision_id = revision_id;
@@ -1131,7 +1241,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_free_netdev;
 
        /* This will be reset for mezz cards  */
-       adapter->portnum = pci_func_id;
+       adapter->portnum = adapter->ahw.pci_func;
 
        err = qlcnic_get_board_info(adapter);
        if (err) {
@@ -1139,21 +1249,23 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_iounmap;
        }
 
+       if (qlcnic_read_mac_addr(adapter))
+               dev_warn(&pdev->dev, "failed to read mac addr\n");
 
-       err = qlcnic_start_firmware(adapter);
-       if (err)
-               goto err_out_decr_ref;
+       if (qlcnic_setup_idc_param(adapter))
+               goto err_out_iounmap;
 
-       /*
-        * See if the firmware gave us a virtual-physical port mapping.
-        */
-       adapter->physical_port = adapter->portnum;
+       err = adapter->nic_ops->start_firmware(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
+               goto err_out_decr_ref;
+       }
 
        qlcnic_clear_stats(adapter);
 
        qlcnic_setup_intr(adapter);
 
-       err = qlcnic_setup_netdev(adapter, netdev);
+       err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
        if (err)
                goto err_out_disable_msi;
 
@@ -1216,6 +1328,11 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
 
        qlcnic_detach(adapter);
 
+       if (adapter->npars != NULL)
+               kfree(adapter->npars);
+       if (adapter->eswitch != NULL)
+               kfree(adapter->eswitch);
+
        qlcnic_clr_all_drv_state(adapter);
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1304,10 +1421,7 @@ qlcnic_resume(struct pci_dev *pdev)
        pci_set_master(pdev);
        pci_restore_state(pdev);
 
-       adapter->ahw.crb_win = -1;
-       adapter->ahw.ocm_win = -1;
-
-       err = qlcnic_start_firmware(adapter);
+       err = adapter->nic_ops->start_firmware(adapter);
        if (err) {
                dev_err(&pdev->dev, "failed to start firmware\n");
                return err;
@@ -1334,6 +1448,7 @@ err_out_detach:
        qlcnic_detach(adapter);
 err_out:
        qlcnic_clr_all_drv_state(adapter);
+       netif_device_attach(netdev);
        return err;
 }
 #endif
@@ -1383,11 +1498,11 @@ qlcnic_tso_check(struct net_device *netdev,
        u8 opcode = TX_ETHER_PKT;
        __be16 protocol = skb->protocol;
        u16 flags = 0, vid = 0;
-       u32 producer;
        int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
        struct cmd_desc_type0 *hwdesc;
        struct vlan_ethhdr *vh;
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       u32 producer = tx_ring->producer;
 
        if (protocol == cpu_to_be16(ETH_P_8021Q)) {
 
@@ -1403,6 +1518,11 @@ qlcnic_tso_check(struct net_device *netdev,
                vlan_oob = 1;
        }
 
+       if (*(skb->data) & BIT_0) {
+               flags |= BIT_0;
+               memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
+       }
+
        if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
                        skb_shinfo(skb)->gso_size > 0) {
 
@@ -1452,7 +1572,6 @@ qlcnic_tso_check(struct net_device *netdev,
        /* For LSO, we need to copy the MAC/IP/TCP headers into
         * the descriptor ring
         */
-       producer = tx_ring->producer;
        copied = 0;
        offset = 2;
 
@@ -1570,6 +1689,11 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        int frag_count, no_of_desc;
        u32 num_txd = tx_ring->num_desc;
 
+       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+               netif_stop_queue(netdev);
+               return NETDEV_TX_BUSY;
+       }
+
        frag_count = skb_shinfo(skb)->nr_frags + 1;
 
        /* 4 fragments per cmd des */
@@ -1586,8 +1710,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        pdev = adapter->pdev;
 
-       if (qlcnic_map_tx_skb(pdev, skb, pbuf))
+       if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
+               adapter->stats.tx_dma_map_error++;
                goto drop_packet;
+       }
 
        pbuf->skb = skb;
        pbuf->frag_count = frag_count;
@@ -1739,6 +1865,7 @@ static void qlcnic_tx_timeout_task(struct work_struct *work)
 request_reset:
        adapter->need_fw_reset = 1;
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       QLCDB(adapter, DRV, "Resetting adapter\n");
 }
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
@@ -1750,7 +1877,7 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
 
        stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
        stats->tx_packets = adapter->stats.xmitfinished;
-       stats->rx_bytes = adapter->stats.rxbytes;
+       stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
        stats->tx_bytes = adapter->stats.txbytes;
        stats->rx_dropped = adapter->stats.rxdropped;
        stats->tx_dropped = adapter->stats.txdropped;
@@ -1944,7 +2071,20 @@ static void qlcnic_poll_controller(struct net_device *netdev)
 #endif
 
 static void
-qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state)
+qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
+{
+       u32 val;
+
+       val = adapter->portnum & 0xf;
+       val |= encoding << 7;
+       val |= (jiffies - adapter->dev_rst_time) << 8;
+
+       QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
+       adapter->dev_rst_time = jiffies;
+}
+
+static int
+qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
 {
        u32  val;
 
@@ -1952,18 +2092,20 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state)
                        state != QLCNIC_DEV_NEED_QUISCENT);
 
        if (qlcnic_api_lock(adapter))
-               return ;
+               return -EIO;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
 
        if (state == QLCNIC_DEV_NEED_RESET)
-               val |= ((u32)0x1 << (adapter->portnum * 4));
+               QLC_DEV_SET_RST_RDY(val, adapter->portnum);
        else if (state == QLCNIC_DEV_NEED_QUISCENT)
-               val |= ((u32)0x1 << ((adapter->portnum * 4) + 1));
+               QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
 
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
+
+       return 0;
 }
 
 static int
@@ -1975,7 +2117,7 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
                return -EBUSY;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       val &= ~((u32)0x3 << (adapter->portnum * 4));
+       QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
@@ -1992,14 +2134,14 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
                goto err;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
-       val &= ~((u32)0x1 << (adapter->portnum * 4));
+       QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
        QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
 
        if (!(val & 0x11111111))
                QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       val &= ~((u32)0x3 << (adapter->portnum * 4));
+       QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
@@ -2009,6 +2151,7 @@ err:
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 }
 
+/* Grab api lock, before checking state */
 static int
 qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 {
@@ -2024,73 +2167,103 @@ qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
                return 1;
 }
 
+static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
+{
+       u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
+
+       if (val != QLCNIC_DRV_IDC_VER) {
+               dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
+                       " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
+       }
+
+       return 0;
+}
+
 static int
 qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
 {
        u32 val, prev_state;
-       int cnt = 0;
-       int portnum = adapter->portnum;
+       u8 dev_init_timeo = adapter->dev_init_timeo;
+       u8 portnum = adapter->portnum;
+       u8 ret;
+
+       if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
+               return 1;
 
        if (qlcnic_api_lock(adapter))
                return -1;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
-       if (!(val & ((int)0x1 << (portnum * 4)))) {
-               val |= ((u32)0x1 << (portnum * 4));
+       if (!(val & (1 << (portnum * 4)))) {
+               QLC_DEV_SET_REF_CNT(val, portnum);
                QLCWR32(adapter, QLCNIC_CRB_DEV_REF_COUNT, val);
-       } else if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state)) {
-               goto start_fw;
        }
 
        prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       QLCDB(adapter, HW, "Device state = %u\n", prev_state);
 
        switch (prev_state) {
        case QLCNIC_DEV_COLD:
-start_fw:
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITALIZING);
+               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+               QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
+               qlcnic_idc_debug_info(adapter, 0);
                qlcnic_api_unlock(adapter);
                return 1;
 
        case QLCNIC_DEV_READY:
+               ret = qlcnic_check_idc_ver(adapter);
                qlcnic_api_unlock(adapter);
-               return 0;
+               return ret;
 
        case QLCNIC_DEV_NEED_RESET:
                val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-               val |= ((u32)0x1 << (portnum * 4));
+               QLC_DEV_SET_RST_RDY(val, portnum);
                QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
                break;
 
        case QLCNIC_DEV_NEED_QUISCENT:
                val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-               val |= ((u32)0x1 << ((portnum * 4) + 1));
+               QLC_DEV_SET_QSCNT_RDY(val, portnum);
                QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
                break;
 
        case QLCNIC_DEV_FAILED:
+               dev_err(&adapter->pdev->dev, "Device in failed state.\n");
                qlcnic_api_unlock(adapter);
                return -1;
+
+       case QLCNIC_DEV_INITIALIZING:
+       case QLCNIC_DEV_QUISCENT:
+               break;
        }
 
        qlcnic_api_unlock(adapter);
-       msleep(1000);
-       while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) &&
-                       ++cnt < 20)
+
+       do {
                msleep(1000);
+               prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
-       if (cnt >= 20)
+               if (prev_state == QLCNIC_DEV_QUISCENT)
+                       continue;
+       } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
+
+       if (!dev_init_timeo) {
+               dev_err(&adapter->pdev->dev,
+                       "Waiting for device to initialize timeout\n");
                return -1;
+       }
 
        if (qlcnic_api_lock(adapter))
                return -1;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       val &= ~((u32)0x3 << (portnum * 4));
+       QLC_DEV_CLR_RST_QSCNT(val, portnum);
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
+       ret = qlcnic_check_idc_ver(adapter);
        qlcnic_api_unlock(adapter);
 
-       return 0;
+       return ret;
 }
 
 static void
@@ -2098,44 +2271,98 @@ qlcnic_fwinit_work(struct work_struct *work)
 {
        struct qlcnic_adapter *adapter = container_of(work,
                        struct qlcnic_adapter, fw_work.work);
-       int dev_state;
+       u32 dev_state = 0xf, npar_state;
 
-       if (++adapter->fw_wait_cnt > FW_POLL_THRESH)
+       if (qlcnic_api_lock(adapter))
                goto err_ret;
 
-       if (test_bit(__QLCNIC_START_FW, &adapter->state)) {
+       dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (dev_state ==  QLCNIC_DEV_QUISCENT) {
+               qlcnic_api_unlock(adapter);
+               qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+                                               FW_POLL_DELAY * 2);
+               return;
+       }
+
+       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+               if (npar_state == QLCNIC_DEV_NPAR_RDY) {
+                       qlcnic_api_unlock(adapter);
+                       goto wait_npar;
+               } else {
+                       qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+                               FW_POLL_DELAY);
+                       qlcnic_api_unlock(adapter);
+                       return;
+               }
+       }
 
-               if (qlcnic_check_drv_state(adapter)) {
-                       qlcnic_schedule_work(adapter,
-                                       qlcnic_fwinit_work, FW_POLL_DELAY);
+       if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
+               dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
+                                       adapter->reset_ack_timeo);
+               goto skip_ack_check;
+       }
+
+       if (!qlcnic_check_drv_state(adapter)) {
+skip_ack_check:
+               dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+               if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
+                       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                               QLCNIC_DEV_QUISCENT);
+                       qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+                                               FW_POLL_DELAY * 2);
+                       QLCDB(adapter, DRV, "Quiscing the driver\n");
+                       qlcnic_idc_debug_info(adapter, 0);
+
+                       qlcnic_api_unlock(adapter);
                        return;
                }
 
-               if (!qlcnic_start_firmware(adapter)) {
+               if (dev_state == QLCNIC_DEV_NEED_RESET) {
+                       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                               QLCNIC_DEV_INITIALIZING);
+                       set_bit(__QLCNIC_START_FW, &adapter->state);
+                       QLCDB(adapter, DRV, "Restarting fw\n");
+                       qlcnic_idc_debug_info(adapter, 0);
+               }
+
+               qlcnic_api_unlock(adapter);
+
+               if (!adapter->nic_ops->start_firmware(adapter)) {
                        qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
                        return;
                }
-
                goto err_ret;
        }
 
+       qlcnic_api_unlock(adapter);
+
+wait_npar:
        dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
+
        switch (dev_state) {
-       case QLCNIC_DEV_READY:
-               if (!qlcnic_start_firmware(adapter)) {
-                       qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
-                       return;
-               }
+       case QLCNIC_DEV_QUISCENT:
+       case QLCNIC_DEV_NEED_QUISCENT:
+       case QLCNIC_DEV_NEED_RESET:
+               qlcnic_schedule_work(adapter,
+                       qlcnic_fwinit_work, FW_POLL_DELAY);
+               return;
        case QLCNIC_DEV_FAILED:
                break;
 
        default:
-               qlcnic_schedule_work(adapter,
-                       qlcnic_fwinit_work, 2 * FW_POLL_DELAY);
-               return;
+               if (!adapter->nic_ops->start_firmware(adapter)) {
+                       qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+                       return;
+               }
        }
 
 err_ret:
+       dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
+               "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
+       netif_device_attach(adapter->netdev);
        qlcnic_clr_all_drv_state(adapter);
 }
 
@@ -2163,7 +2390,8 @@ qlcnic_detach_work(struct work_struct *work)
        if (adapter->temp == QLCNIC_TEMP_PANIC)
                goto err_ret;
 
-       qlcnic_set_drv_state(adapter, adapter->dev_state);
+       if (qlcnic_set_drv_state(adapter, adapter->dev_state))
+               goto err_ret;
 
        adapter->fw_wait_cnt = 0;
 
@@ -2172,10 +2400,14 @@ qlcnic_detach_work(struct work_struct *work)
        return;
 
 err_ret:
+       dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
+                       status, adapter->temp);
+       netif_device_attach(netdev);
        qlcnic_clr_all_drv_state(adapter);
 
 }
 
+/*Transit to RESET state from READY state only */
 static void
 qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
 {
@@ -2186,9 +2418,30 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
 
        state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
-       if (state != QLCNIC_DEV_INITALIZING && state != QLCNIC_DEV_NEED_RESET) {
+       if (state == QLCNIC_DEV_READY) {
                QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
-               set_bit(__QLCNIC_START_FW, &adapter->state);
+               QLCDB(adapter, DRV, "NEED_RESET state set\n");
+               qlcnic_idc_debug_info(adapter, 0);
+       }
+
+       qlcnic_api_unlock(adapter);
+}
+
+/* Transit to NPAR READY state from NPAR NOT READY state */
+static void
+qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
+{
+       u32 state;
+
+       if (qlcnic_api_lock(adapter))
+               return;
+
+       state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+
+       if (state != QLCNIC_DEV_NPAR_RDY) {
+               QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+                       QLCNIC_DEV_NPAR_RDY);
+               QLCDB(adapter, DRV, "NPAR READY state set\n");
        }
 
        qlcnic_api_unlock(adapter);
@@ -2233,9 +2486,8 @@ qlcnic_attach_work(struct work_struct *work)
                qlcnic_config_indev_addr(netdev, NETDEV_UP);
        }
 
-       netif_device_attach(netdev);
-
 done:
+       netif_device_attach(netdev);
        adapter->fw_fail_cnt = 0;
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 
@@ -2253,10 +2505,8 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
        if (qlcnic_check_temp(adapter))
                goto detach;
 
-       if (adapter->need_fw_reset) {
+       if (adapter->need_fw_reset)
                qlcnic_dev_request_reset(adapter);
-               goto detach;
-       }
 
        state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
        if (state == QLCNIC_DEV_NEED_RESET || state == QLCNIC_DEV_NEED_QUISCENT)
@@ -2285,8 +2535,11 @@ detach:
                QLCNIC_DEV_NEED_RESET;
 
        if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
-                       !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) {
+
                qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
+               QLCDB(adapter, DRV, "fw recovery scheduled.\n");
+       }
 
        return 1;
 }
@@ -2308,6 +2561,46 @@ reschedule:
        qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
 }
 
+static int
+qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
+{
+       int err;
+
+       err = qlcnic_can_start_firmware(adapter);
+       if (err)
+               return err;
+
+       qlcnic_check_options(adapter);
+
+       adapter->need_fw_reset = 0;
+
+       return err;
+}
+
+static int
+qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
+{
+       return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+       return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       return -EOPNOTSUPP;
+}
+
+static void
+qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+       return;
+}
+
 static ssize_t
 qlcnic_store_bridged_mode(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t len)
@@ -2325,7 +2618,7 @@ qlcnic_store_bridged_mode(struct device *dev,
        if (strict_strtoul(buf, 2, &new))
                goto err_out;
 
-       if (!qlcnic_config_bridged_mode(adapter, !!new))
+       if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
                ret = len;
 
 err_out:
@@ -2387,51 +2680,72 @@ static int
 qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
                loff_t offset, size_t size)
 {
+       size_t crb_size = 4;
+
        if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
                return -EIO;
 
-       if ((size != 4) || (offset & 0x3))
-               return  -EINVAL;
+       if (offset < QLCNIC_PCI_CRBSPACE) {
+               if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
+                                       QLCNIC_PCI_CAMQM_END))
+                       crb_size = 8;
+               else
+                       return -EINVAL;
+       }
 
-       if (offset < QLCNIC_PCI_CRBSPACE)
-               return -EINVAL;
+       if ((size != crb_size) || (offset & (crb_size-1)))
+               return  -EINVAL;
 
        return 0;
 }
 
 static ssize_t
-qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
+qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       data = QLCRD32(adapter, offset);
-       memcpy(buf, &data, size);
+       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+               qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
+               memcpy(buf, &qmdata, size);
+       } else {
+               data = QLCRD32(adapter, offset);
+               memcpy(buf, &data, size);
+       }
        return size;
 }
 
 static ssize_t
-qlcnic_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr,
+qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       memcpy(&data, buf, size);
-       QLCWR32(adapter, offset, data);
+       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+               memcpy(&qmdata, buf, size);
+               qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
+       } else {
+               memcpy(&data, buf, size);
+               QLCWR32(adapter, offset, data);
+       }
        return size;
 }
 
@@ -2449,7 +2763,8 @@ qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
 }
 
 static ssize_t
-qlcnic_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
+qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
@@ -2470,7 +2785,8 @@ qlcnic_sysfs_read_mem(struct kobject *kobj, struct bin_attribute *attr,
 }
 
 static ssize_t
-qlcnic_sysfs_write_mem(struct kobject *kobj, struct bin_attribute *attr,
+qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
        struct device *dev = container_of(kobj, struct device, kobj);
@@ -2553,24 +2869,12 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 
 #define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
 
-static int
-qlcnic_destip_supported(struct qlcnic_adapter *adapter)
-{
-       if (adapter->ahw.cut_through)
-               return 0;
-
-       return 1;
-}
-
 static void
 qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
 {
        struct in_device *indev;
        struct qlcnic_adapter *adapter = netdev_priv(dev);
 
-       if (!qlcnic_destip_supported(adapter))
-               return;
-
        indev = in_dev_get(dev);
        if (!indev)
                return;
@@ -2591,7 +2895,6 @@ qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
        } endfor_ifa(indev);
 
        in_dev_put(indev);
-       return;
 }
 
 static int qlcnic_netdev_event(struct notifier_block *this,
@@ -2650,7 +2953,7 @@ recheck:
 
        adapter = netdev_priv(dev);
 
-       if (!adapter || !qlcnic_destip_supported(adapter))
+       if (!adapter)
                goto done;
 
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)