]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
qlcnic: Update to 5.1.27.35
authorSritej Velaga <sritej.velaga@qlogic.com>
Tue, 8 Jan 2013 21:07:56 +0000 (14:07 -0700)
committerJerry Snitselaar <jerry.snitselaar@oracle.com>
Tue, 8 Jan 2013 21:09:01 +0000 (14:09 -0700)
Signed-off-by: Jerry Snitselaar <jerry.snitselaar@oracle.com>
16 files changed:
drivers/net/qlcnic/Makefile
drivers/net/qlcnic/qlcnic.h
drivers/net/qlcnic/qlcnic_83xx.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_83xx.h [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_83xx_init.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_83xx_vnic.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_ctx.c
drivers/net/qlcnic/qlcnic_ethtool.c
drivers/net/qlcnic/qlcnic_hdr.h
drivers/net/qlcnic/qlcnic_hw.c
drivers/net/qlcnic/qlcnic_hw.h [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_init.c
drivers/net/qlcnic/qlcnic_io.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_main.c
drivers/net/qlcnic/qlcnic_minidump.c [new file with mode: 0644]
drivers/net/qlcnic/qlcnic_sysfs.c [new file with mode: 0644]

index ddba83ef3f4468ddc5471b3b04ddeb314c0d4c7f..086c44b3fbb926ee177af1f5f595a28a744387bb 100644 (file)
@@ -5,4 +5,6 @@
 obj-$(CONFIG_QLCNIC) := qlcnic.o
 
 qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
-       qlcnic_ethtool.o qlcnic_ctx.o
+       qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
+       qlcnic_sysfs.o qlcnic_83xx.o qlcnic_83xx_init.o \
+       qlcnic_minidump.o qlcnic_83xx_vnic.o
index eaa1db9fec32ccbd8fad0b2e501b78f38a741138..9701663521fecdaff8e44d91fa62172d7da56960 100644 (file)
 #include <linux/if_vlan.h>
 
 #include "qlcnic_hdr.h"
+#include "qlcnic_hw.h"
+#include "qlcnic_83xx.h"
 
 #define _QLCNIC_LINUX_MAJOR 5
-#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 29
-#define QLCNIC_LINUX_VERSIONID  "5.0.29"
+#define _QLCNIC_LINUX_MINOR 1
+#define _QLCNIC_LINUX_SUBVERSION 27
+#define QLCNIC_LINUX_VERSIONID  "5.1.27.35"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -89,6 +91,8 @@
 #define QLCNIC_CT_DEFAULT_RX_BUF_LEN   2048
 #define QLCNIC_LRO_BUFFER_EXTRA                2048
 
+#define RSS_HASHTYPE_IP_TCP     0x3
+
 /* Opcodes to be used with the commands */
 #define TX_ETHER_PKT   0x01
 #define TX_TCP_PKT     0x02
 #define TX_STOP_THRESH         ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \
                                                        + MGMT_CMD_DESC_RESV)
 #define QLCNIC_MAX_TX_TIMEOUTS 2
-
+#define QLCNIC_MAX_TX_QUEUES   1
 /*
  * Following are the states of the Phantom. Phantom will set them and
  * Host will read to check if the fields are correct.
        ((cmd_desc)->port_ctxid |= ((var) & 0x0F))
 #define qlcnic_set_cmd_desc_ctxid(cmd_desc, var)       \
        ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))
-
 #define qlcnic_set_tx_port(_desc, _port) \
        ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))
 
@@ -210,6 +213,8 @@ struct rcv_desc {
 #define QLCNIC_RESPONSE_DESC   0x05
 #define QLCNIC_LRO_DESC        0x12
 
+#define QLCNIC_TX_POLL_BUDGET  128
+
 /* for status field in status_desc */
 #define STATUS_CKSUM_LOOP      0
 #define STATUS_CKSUM_OK                2
@@ -219,12 +224,10 @@ struct rcv_desc {
 #define STATUS_OWNER_PHANTOM   (0x2ULL << 56)
 
 /* Status descriptor:
-   0-3 port, 4-7 status, 8-11 type, 12-27 total_length
-   28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
+   0-3 rsvd, 4-7 status, 8-11 type, 12-27 total_length
+   28-43 reference_handle, 44-47 rsvd, 48-52 pkt_offset
    53-55 desc_cnt, 56-57 owner, 58-63 opcode
  */
-#define qlcnic_get_sts_port(sts_data)  \
-       ((sts_data) & 0x0F)
 #define qlcnic_get_sts_status(sts_data)        \
        (((sts_data) >> 4) & 0x0F)
 #define qlcnic_get_sts_type(sts_data)  \
@@ -232,9 +235,7 @@ struct rcv_desc {
 #define qlcnic_get_sts_totallength(sts_data)   \
        (((sts_data) >> 12) & 0xFFFF)
 #define qlcnic_get_sts_refhandle(sts_data)     \
-       (((sts_data) >> 28) & 0xFFFF)
-#define qlcnic_get_sts_prot(sts_data)  \
-       (((sts_data) >> 44) & 0x0F)
+       (((sts_data) >> 28) & 0x7FFF)
 #define qlcnic_get_sts_pkt_offset(sts_data)    \
        (((sts_data) >> 48) & 0x1F)
 #define qlcnic_get_sts_desc_cnt(sts_data)      \
@@ -243,7 +244,7 @@ struct rcv_desc {
        (((sts_data) >> 58) & 0x03F)
 
 #define qlcnic_get_lro_sts_refhandle(sts_data)         \
-       ((sts_data) & 0x0FFFF)
+       ((sts_data) & 0x07FFF)
 #define qlcnic_get_lro_sts_length(sts_data)    \
        (((sts_data) >> 16) & 0x0FFFF)
 #define qlcnic_get_lro_sts_l2_hdr_offset(sts_data)     \
@@ -258,14 +259,14 @@ struct rcv_desc {
        (((sts_data) >> 52) & 0x1)
 #define qlcnic_get_lro_sts_seq_number(sts_data)                \
        ((sts_data) & 0x0FFFFFFFF)
-#define qlcnic_get_lro_sts_mss(sts_data1)              \
+#define qlcnic_get_lro_sts_mss(sts_data1)              \
        ((sts_data1 >> 32) & 0x0FFFF)
 
-
 struct status_desc {
        __le64 status_desc_data[2];
 } __attribute__ ((aligned(16)));
 
+#define QLCNIC_DEV_INFO_SIZE   1
 /* UNIFIED ROMIMAGE */
 #define QLCNIC_UNI_FW_MIN_SIZE         0xc8000
 #define QLCNIC_UNI_DIR_SECT_PRODUCT_TBL        0x0
@@ -294,6 +295,7 @@ struct uni_data_desc{
 
 /* Flash Defines and Structures */
 #define QLCNIC_FLT_LOCATION    0x3F1000
+#define QLCNIC_FDT_LOCATION    0x3F0000
 #define QLCNIC_B0_FW_IMAGE_REGION 0x74
 #define QLCNIC_C0_FW_IMAGE_REGION 0x97
 #define QLCNIC_BOOTLD_REGION    0X72
@@ -314,6 +316,37 @@ struct qlcnic_flt_entry {
        u32 end_addr;
 };
 
+struct qlcnic_flash_desc_table {
+       u32     flash_valid;
+       u16     flash_ver;
+       u16     flash_len;
+       u16     flash_cksum;
+       u16     flash_unused;
+       u8      flash_model[16];
+       u16     flash_manuf;
+       u16     flash_id;
+       u8      flash_flag;
+       u8      erase_cmd;
+       u8      alt_erase_cmd;
+       u8      write_enable_cmd;
+       u8      write_enable_bits;
+       u8      write_statusreg_cmd;
+       u8      unprotected_sec_cmd;
+       u8      read_manuf_cmd;
+       u32     block_size;
+       u32     alt_block_size;
+       u32     flash_size;
+       u32     write_enable_data;
+       u8      readid_addr_len;
+       u8      write_disable_bits;
+       u8      read_dev_id_len;
+       u8      chip_erase_cmd;
+       u16     read_timeo;
+       u8      protected_sec_cmd;
+       u8      resvd[65];
+};
+
+
 /* Magic number to let user know flash is programmed */
 #define        QLCNIC_BDINFO_MAGIC 0x12345678
 
@@ -331,6 +364,7 @@ struct qlcnic_flt_entry {
 #define QLCNIC_BRDTYPE_P3P_10G_CX4     0x0031
 #define QLCNIC_BRDTYPE_P3P_10G_XFP     0x0032
 #define QLCNIC_BRDTYPE_P3P_10G_TP      0x0080
+#define QLCNIC_BRDTYPE_83XX_10G        0x0083
 
 #define QLCNIC_MSIX_TABLE_OFFSET       0x44
 
@@ -357,6 +391,11 @@ struct qlcnic_flt_entry {
 #define QLCNIC_FLASH_ROMIMAGE_NAME     "flash"
 
 extern char qlcnic_driver_name[];
+extern int use_msi;
+extern int use_msi_x;
+extern int auto_fw_reset;
+extern int load_fw_file;
+extern int qlcnic_config_npars;
 
 /* Number of status descriptors to handle per interrupt */
 #define MAX_STATUS_HANDLE      (64)
@@ -428,17 +467,21 @@ struct qlcnic_dump_template_hdr {
        __le32  sys_info[3];
        __le32  saved_state[16];
        __le32  cap_sizes[8];
+       __le32  ocm_wnd_reg[16];
        __le32  rsvd[0];
 };
 
 struct qlcnic_fw_dump {
        u8      clr;    /* flag to indicate if dump is cleared */
+       u32     pos;    /* position in the dump buffer */
        u8      enable; /* enable/disable dump */
        u32     size;   /* total size of the dump */
        void    *data;  /* dump data area */
        struct  qlcnic_dump_template_hdr *tmpl_hdr;
 };
 
+struct qlcnic_hardware_ops;
+
 /*
  * One hardware_context{} per adapter
  * contains interrupt info as well shared hardware info.
@@ -456,13 +499,54 @@ struct qlcnic_hardware_context {
        u8 pci_func;
        u8 linkup;
        u8 loopback_state;
+       u8 beacon_state;
+       u8 has_link_events;
+       u8 fw_type;
+       u8 physical_port;
+       u8 reset_context;
+       u8 msix_supported;
+       u8 max_mac_filters;
+       u8 mc_enabled;
+       u8 max_mc_count;
+       u8 diag_test;
+       u8 num_msix;
+       u8 nic_mode;
+       char diag_cnt;
+
        u16 port_type;
        u16 board_type;
 
-       u8 beacon_state;
+       u16 link_speed;
+       u16 link_duplex;
+       u16 link_autoneg;
+       u16 module_type;
 
+       u16 op_mode;
+       u16 switch_mode;
+       u16 max_tx_ques;
+       u16 max_rx_ques;
+       u16 max_mtu;
+       u16 msg_enable;
+       u16 act_pci_func;
+
+       u32 capabilities;
+       u32 temp;
+       u32 int_vec_bit;
+       u32 fw_hal_version;
+       u32 port_config;
+       struct qlcnic_hardware_ops *hw_ops;
        struct qlcnic_nic_intr_coalesce coal;
        struct qlcnic_fw_dump fw_dump;
+       struct qlcnic_flash_desc_table flash_fdt;
+       struct qlcnic_83xx_reset reset;
+       struct qlcnic_83xx_idc idc;
+       struct qlcnic_83xx_fw_info fw_info;
+       struct qlcnic_intrpt_config *intr_tbl;
+       u32 *reg_tbl;
+       u32 *ext_reg_tbl;
+       u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
+       u32 mbox_reg[4];
+       spinlock_t mbx_lock;
 };
 
 struct qlcnic_adapter_stats {
@@ -483,6 +567,8 @@ struct qlcnic_adapter_stats {
        u64  null_rxbuf;
        u64  rx_dma_map_error;
        u64  tx_dma_map_error;
+       u64  mac_filter_limit_overrun;
+       u64  spurious_intr;
 };
 
 /*
@@ -521,11 +607,17 @@ struct qlcnic_host_sds_ring {
 } ____cacheline_internodealigned_in_smp;
 
 struct qlcnic_host_tx_ring {
+       int irq;
+       void __iomem *crb_intr_mask;
+       char name[IFNAMSIZ+4];
+       u16 ctx_id;
        u32 producer;
        u32 sw_consumer;
        u32 num_desc;
        void __iomem *crb_cmd_producer;
        struct cmd_desc_type0 *desc_head;
+       struct qlcnic_adapter *adapter;
+       struct napi_struct napi;
        struct qlcnic_cmd_buffer *cmd_buf_arr;
        __le32 *hw_consumer;
 
@@ -552,8 +644,9 @@ struct qlcnic_recv_context {
 /* HW context creation */
 
 #define QLCNIC_OS_CRB_RETRY_COUNT      4000
-#define QLCNIC_CDRP_SIGNATURE_MAKE(pcifn, version) \
-       (((pcifn) & 0xff) | (((version) & 0xff) << 8) | (0xcafe << 16))
+#define QLCNIC_CDRP_SIGNATURE_MAKE(ahw)                                        \
+       (((ahw->pci_func) & 0xff) | (((ahw->fw_hal_version) &           \
+       0xff) << 8) | (0xcafe << 16))
 
 #define QLCNIC_CDRP_CMD_BIT            0x80000000
 
@@ -573,52 +666,10 @@ struct qlcnic_recv_context {
  * the crb QLCNIC_CDRP_CRB_OFFSET.
  */
 #define QLCNIC_CDRP_FORM_CMD(cmd)      (QLCNIC_CDRP_CMD_BIT | (cmd))
-#define QLCNIC_CDRP_IS_CMD(cmd)        (((cmd) & QLCNIC_CDRP_CMD_BIT) != 0)
-
-#define QLCNIC_CDRP_CMD_SUBMIT_CAPABILITIES     0x00000001
-#define QLCNIC_CDRP_CMD_READ_MAX_RDS_PER_CTX    0x00000002
-#define QLCNIC_CDRP_CMD_READ_MAX_SDS_PER_CTX    0x00000003
-#define QLCNIC_CDRP_CMD_READ_MAX_RULES_PER_CTX  0x00000004
-#define QLCNIC_CDRP_CMD_READ_MAX_RX_CTX         0x00000005
-#define QLCNIC_CDRP_CMD_READ_MAX_TX_CTX         0x00000006
-#define QLCNIC_CDRP_CMD_CREATE_RX_CTX           0x00000007
-#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX          0x00000008
-#define QLCNIC_CDRP_CMD_CREATE_TX_CTX           0x00000009
-#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX          0x0000000a
-#define QLCNIC_CDRP_CMD_INTRPT_TEST            0x00000011
-#define QLCNIC_CDRP_CMD_SET_MTU                 0x00000012
-#define QLCNIC_CDRP_CMD_READ_PHY               0x00000013
-#define QLCNIC_CDRP_CMD_WRITE_PHY              0x00000014
-#define QLCNIC_CDRP_CMD_READ_HW_REG            0x00000015
-#define QLCNIC_CDRP_CMD_GET_FLOW_CTL           0x00000016
-#define QLCNIC_CDRP_CMD_SET_FLOW_CTL           0x00000017
-#define QLCNIC_CDRP_CMD_READ_MAX_MTU           0x00000018
-#define QLCNIC_CDRP_CMD_READ_MAX_LRO           0x00000019
-#define QLCNIC_CDRP_CMD_MAC_ADDRESS            0x0000001f
-
-#define QLCNIC_CDRP_CMD_GET_PCI_INFO           0x00000020
-#define QLCNIC_CDRP_CMD_GET_NIC_INFO           0x00000021
-#define QLCNIC_CDRP_CMD_SET_NIC_INFO           0x00000022
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024
-#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH         0x00000025
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS     0x00000026
-#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING      0x00000027
-#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH      0x00000028
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG        0x00000029
-#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS      0x0000002a
-#define QLCNIC_CDRP_CMD_CONFIG_PORT            0x0000002E
-#define QLCNIC_CDRP_CMD_TEMP_SIZE              0x0000002f
-#define QLCNIC_CDRP_CMD_GET_TEMP_HDR           0x00000030
-#define QLCNIC_CDRP_CMD_GET_MAC_STATS          0x00000037
 
 #define QLCNIC_RCODE_SUCCESS           0
-#define QLCNIC_RCODE_INVALID_ARGS      6
 #define QLCNIC_RCODE_NOT_SUPPORTED     9
-#define QLCNIC_RCODE_NOT_PERMITTED     10
-#define QLCNIC_RCODE_NOT_IMPL          15
-#define QLCNIC_RCODE_INVALID           16
 #define QLCNIC_RCODE_TIMEOUT           17
-#define QLCNIC_DESTROY_CTX_RESET       0
 
 /*
  * Capabilities Announced
@@ -821,8 +872,8 @@ struct qlcnic_mac_list_s {
  * Firmware --> Driver
  */
 
-#define QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK              0x8f
-#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE       141
+#define QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK              0x8F
+#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE       0x8D
 
 #define VPORT_MISS_MODE_DROP           0 /* drop all unmatched */
 #define VPORT_MISS_MODE_ACCEPT_ALL     1 /* accept all packets */
@@ -839,7 +890,7 @@ struct qlcnic_mac_list_s {
 #define QLCNIC_FW_CAPABILITY_MORE_CAPS         BIT_31
 
 #define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2
-
+#define QLCNIC_FW_CAPABILITY_2_OCBB            BIT_5
 /* module types */
 #define LINKEVENT_MODULE_NOT_PRESENT                   1
 #define LINKEVENT_MODULE_OPTICAL_UNKNOWN               2
@@ -850,19 +901,10 @@ struct qlcnic_mac_list_s {
 #define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN   7
 #define LINKEVENT_MODULE_TWINAX                        8
 
-#define LINKSPEED_10GBPS       10000
-#define LINKSPEED_1GBPS        1000
-#define LINKSPEED_100MBPS      100
-#define LINKSPEED_10MBPS       10
-
 #define LINKSPEED_ENCODED_10MBPS       0
 #define LINKSPEED_ENCODED_100MBPS      1
 #define LINKSPEED_ENCODED_1GBPS        2
 
-#define LINKEVENT_AUTONEG_DISABLED     0
-#define LINKEVENT_AUTONEG_ENABLED      1
-
-#define LINKEVENT_HALF_DUPLEX          0
 #define LINKEVENT_FULL_DUPLEX          1
 
 #define LINKEVENT_LINKSPEED_MBPS       0
@@ -915,7 +957,7 @@ struct qlcnic_ipaddr {
 
 #define QLCNIC_MSI_ENABLED             0x02
 #define QLCNIC_MSIX_ENABLED            0x04
-#define QLCNIC_LRO_ENABLED             0x08
+#define QLCNIC_LRO_ENABLED             0x01
 #define QLCNIC_LRO_DISABLED            0x00
 #define QLCNIC_BRIDGE_ENABLED          0X10
 #define QLCNIC_DIAG_ENABLED            0x20
@@ -946,7 +988,8 @@ struct qlcnic_ipaddr {
 #define __QLCNIC_START_FW              4
 #define __QLCNIC_AER                   5
 #define __QLCNIC_DIAG_RES_ALLOC                6
-#define __QLCNIC_LED_ENABLE            7
+#define        __QLCNIC_LED_ENABLE             7
+#define __QLCNIC_ELB_INPROGRESS                8
 
 #define QLCNIC_INTERRUPT_TEST          1
 #define QLCNIC_LOOPBACK_TEST           2
@@ -955,6 +998,7 @@ struct qlcnic_ipaddr {
 #define QLCNIC_FILTER_AGE      80
 #define QLCNIC_READD_AGE       20
 #define QLCNIC_LB_MAX_FILTERS  64
+#define QLCNIC_LB_BUCKET_SIZE  32
 
 /* QLCNIC Driver Error Code */
 #define QLCNIC_FW_NOT_RESPOND          51
@@ -962,6 +1006,11 @@ struct qlcnic_ipaddr {
 #define QLCNIC_UNDEFINED_ERROR         53
 #define QLCNIC_LB_CABLE_NOT_CONN       54
 
+/* Loopback test */
+#define QLCNIC_ILB_PKT_SIZE    64
+#define QLCNIC_NUM_ILB_PKT     16
+#define QLCNIC_ILB_MAX_RCV_LOOP        10
+
 struct qlcnic_filter {
        struct hlist_node fnode;
        u8 faddr[ETH_ALEN];
@@ -972,7 +1021,8 @@ struct qlcnic_filter {
 struct qlcnic_filter_hash {
        struct hlist_head *fhead;
        u8 fnum;
-       u8 fmax;
+       u16 fmax;
+       u16 fbucket_size;
 };
 
 struct qlcnic_adapter {
@@ -985,6 +1035,7 @@ struct qlcnic_adapter {
        unsigned long state;
        u32 flags;
 
+       int max_drv_tx_rings;
        u16 num_txd;
        u16 num_rxd;
        u16 num_jumbo_rxd;
@@ -993,55 +1044,29 @@ struct qlcnic_adapter {
 
        u8 max_rds_rings;
        u8 max_sds_rings;
-       u8 msix_supported;
        u8 portnum;
-       u8 physical_port;
-       u8 reset_context;
 
-       u8 mc_enabled;
-       u8 max_mc_count;
        u8 fw_wait_cnt;
        u8 fw_fail_cnt;
        u8 tx_timeo_cnt;
        u8 need_fw_reset;
 
-       u8 has_link_events;
-       u8 fw_type;
-       u16 tx_context_id;
        u16 is_up;
-
-       u16 link_speed;
-       u16 link_duplex;
-       u16 link_autoneg;
-       u16 module_type;
-
-       u16 op_mode;
-       u16 switch_mode;
-       u16 max_tx_ques;
-       u16 max_rx_ques;
-       u16 max_mtu;
        u16 pvid;
 
-       u32 fw_hal_version;
-       u32 capabilities;
        u32 irq;
-       u32 temp;
-
-       u32 int_vec_bit;
        u32 heartbeat;
 
-       u8 max_mac_filters;
        u8 dev_state;
-       u8 diag_test;
-       char diag_cnt;
        u8 reset_ack_timeo;
        u8 dev_init_timeo;
-       u16 msg_enable;
 
        u8 mac_addr[ETH_ALEN];
 
-       u64 dev_rst_time;
        u8 mac_learn;
+
+       u64 dev_rst_time;
+       u8 flash_mfg_id;
        unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];
 
        struct qlcnic_npar_info *npars;
@@ -1058,8 +1083,9 @@ struct qlcnic_adapter {
 
        struct msix_entry *msix_entries;
 
+       struct workqueue_struct *qlcnic_wq;
        struct delayed_work fw_work;
-
+       struct delayed_work idc_aen_work;
 
        struct qlcnic_filter_hash fhash;
 
@@ -1085,7 +1111,24 @@ struct qlcnic_info {
        __le16  max_rx_ques;
        __le16  min_tx_bw;
        __le16  max_tx_bw;
-       u8      reserved2[104];
+       __le32  op_type;
+       __le16  max_bw_reg_offset;
+       __le16  max_linkspeed_reg_offset;
+       __le32  capability1;
+       __le32  capability2;
+       __le32  capability3;
+       __le16  max_tx_mac_filters;
+       __le16  max_rx_mcast_mac_filters;
+       __le16  max_rx_ucast_mac_filters;
+       __le16  max_rx_ip_addr;
+       __le16  max_rx_lro_flow;
+       __le16  max_rx_status_rings;
+       __le16  max_rx_buf_rings;
+       __le16  max_tx_vlan_keys;
+       u8      total_pf;
+       u8      total_rss_engines;
+       __le16  max_vports;
+       u8      reserved2[64];
 } __packed;
 
 struct qlcnic_pci_info {
@@ -1099,7 +1142,8 @@ struct qlcnic_pci_info {
        __le16  reserved1[2];
 
        u8      mac[ETH_ALEN];
-       u8      reserved2[106];
+       __le16  func_count;
+       u8      reserved2[104];
 } __packed;
 
 struct qlcnic_npar_info {
@@ -1116,6 +1160,7 @@ struct qlcnic_npar_info {
        u8      mac_anti_spoof;
        u8      promisc_mode;
        u8      offload_flags;
+       u8      pci_func;
 };
 
 struct qlcnic_eswitch {
@@ -1135,7 +1180,8 @@ struct qlcnic_eswitch {
 
 
 /* Return codes for Error handling */
-#define QL_STATUS_INVALID_PARAM        -1
+#define QL_STATUS_INVALID_PARAM                -1
+#define QL_STATUS_UNSUPPORTED_CMD      -2
 
 #define MAX_BW                 100     /* % of link speed */
 #define MAX_VLAN_ID            4095
@@ -1244,7 +1290,7 @@ struct qlcnic_mac_statistics{
        __le64  mac_rx_length_large;
        __le64  mac_rx_jabber;
        __le64  mac_rx_dropped;
-       __le64  mac_rx_crc_error;
+       __le64  mac_FCS_error;
        __le64  mac_align_error;
 } __packed;
 
@@ -1355,16 +1401,55 @@ struct __queue {
        u8      rsvd3[2];
 } __packed;
 
+struct __pollrd {
+       __le32  sel_addr;
+       __le32  read_addr;
+       __le32  sel_val;
+       __le16  sel_val_stride;
+       __le16  no_ops;
+       __le32  poll_wait;
+       __le32  poll_mask;
+       __le32  data_size;
+       u8      rsvd[4];
+} __packed;
+
+struct __mux2 {
+       __le32  sel_addr1;
+       __le32  sel_addr2;
+       __le32  sel_val1;
+       __le32  sel_val2;
+       __le32  no_ops;
+       __le32  sel_val_mask;
+       __le32  read_addr;
+       u8      sel_val_stride;
+       u8      data_size;
+       u8      rsvd[2];
+} __packed;
+
+struct __pollrdmwr {
+       __le32  addr1;
+       __le32  addr2;
+       __le32  val1;
+       __le32  val2;
+       __le32  poll_wait;
+       __le32  poll_mask;
+       __le32  mod_mask;
+       __le32  data_size;
+} __packed;
+
 struct qlcnic_dump_entry {
        struct qlcnic_common_entry_hdr hdr;
        union {
-               struct __crb    crb;
-               struct __cache  cache;
-               struct __ocm    ocm;
-               struct __mem    mem;
-               struct __mux    mux;
-               struct __queue  que;
-               struct __ctrl   ctrl;
+               struct __crb            crb;
+               struct __cache          cache;
+               struct __ocm            ocm;
+               struct __mem            mem;
+               struct __mux            mux;
+               struct __queue          que;
+               struct __ctrl           ctrl;
+               struct __pollrdmwr      pollrdmwr;
+               struct __mux2           mux2;
+               struct __pollrd         pollrd;
        } region;
 } __packed;
 
@@ -1384,6 +1469,9 @@ enum op_codes {
        QLCNIC_DUMP_L2_ITAG     = 22,
        QLCNIC_DUMP_L2_DATA     = 23,
        QLCNIC_DUMP_L2_INST     = 24,
+       QLCNIC_DUMP_POLL_RD     = 35,
+       QLCNIC_READ_MUX2        = 36,
+       QLCNIC_READ_POLLRDMWR   = 37,
        QLCNIC_DUMP_READ_ROM    = 71,
        QLCNIC_DUMP_READ_MEM    = 72,
        QLCNIC_DUMP_READ_CTRL   = 98,
@@ -1408,8 +1496,14 @@ enum op_codes {
 #define QLCNIC_ENABLE_FW_DUMP          0xaddfeed
 #define QLCNIC_DISABLE_FW_DUMP         0xbadfeed
 #define QLCNIC_FORCE_FW_RESET          0xdeaddead
-#define QLCNIC_SET_QUIESCENT           0xadd00010
-#define QLCNIC_RESET_QUIESCENT         0xadd00020
+
+#ifndef SPEED_UNKNOWN
+#define SPEED_UNKNOWN  -1
+#endif
+
+#ifndef DUPLEX_UNKNOWN
+#define DUPLEX_UNKNOWN 0xff
+#endif
 
 struct qlcnic_dump_operations {
        enum op_codes opcode;
@@ -1418,10 +1512,8 @@ struct qlcnic_dump_operations {
 };
 
 struct _cdrp_cmd {
-       u32 cmd;
-       u32 arg1;
-       u32 arg2;
-       u32 arg3;
+       u32 num;
+       u32 *arg;
 };
 
 struct qlcnic_cmd_args {
@@ -1432,7 +1524,7 @@ struct qlcnic_cmd_args {
 int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
 int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
 
-u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
+u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off, int *);
 int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data);
 int qlcnic_pci_mem_write_2M(struct qlcnic_adapter *, u64 off, u64 data);
 int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *, u64 off, u64 *data);
@@ -1442,10 +1534,10 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);
 #define ADDR_IN_RANGE(addr, low, high) \
        (((addr) < (high)) && ((addr) >= (low)))
 
-#define QLCRD32(adapter, off) \
-       (qlcnic_hw_read_wx_2M(adapter, off))
+#define QLCRD32(adapter, off, err) \
+       adapter->ahw->hw_ops->rdreg(adapter, off, err)
 #define QLCWR32(adapter, off, val) \
-       (qlcnic_hw_write_wx_2M(adapter, off, val))
+       adapter->ahw->hw_ops->wrtreg(adapter, off, val)
 
 int qlcnic_pcie_sem_lock(struct qlcnic_adapter *, int, u32);
 void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
@@ -1458,10 +1550,6 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
        qlcnic_pcie_sem_lock((a), 3, QLCNIC_PHY_LOCK_ID)
 #define qlcnic_phy_unlock(a)   \
        qlcnic_pcie_sem_unlock((a), 3)
-#define qlcnic_api_lock(a)     \
-       qlcnic_pcie_sem_lock((a), 5, 0)
-#define qlcnic_api_unlock(a)   \
-       qlcnic_pcie_sem_unlock((a), 5)
 #define qlcnic_sw_lock(a)      \
        qlcnic_pcie_sem_lock((a), 6, 0)
 #define qlcnic_sw_unlock(a)    \
@@ -1474,88 +1562,148 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
 #define __QLCNIC_MAX_LED_RATE  0xf
 #define __QLCNIC_MAX_LED_STATE 0x2
 
-int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
-int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
-int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
-void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
-void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
+int qlcnic_get_board_info(struct qlcnic_adapter *);
+int qlcnic_wol_supported(struct qlcnic_adapter *);
+int qlcnic_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_prune_lb_filters(struct qlcnic_adapter *);
+void qlcnic_delete_lb_filters(struct qlcnic_adapter *);
 int qlcnic_dump_fw(struct qlcnic_adapter *);
+void qlcnic_get_ocm_win(struct qlcnic_hardware_context *);
+void qlcnic_get_func_no(struct qlcnic_adapter *);
+int qlcnic_api_lock(struct qlcnic_adapter *);
+void qlcnic_api_unlock(struct qlcnic_adapter *);
 
 /* Functions from qlcnic_init.c */
-int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
-int qlcnic_need_fw_reset(struct qlcnic_adapter *adapter);
-void qlcnic_request_firmware(struct qlcnic_adapter *adapter);
-void qlcnic_release_firmware(struct qlcnic_adapter *adapter);
-int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter);
-int qlcnic_setup_idc_param(struct qlcnic_adapter *adapter);
-int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter);
-
-int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp);
-int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
-                               u8 *bytes, size_t size);
-int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter);
-void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter);
-
-void __iomem *qlcnic_get_ioaddr(struct qlcnic_adapter *, u32);
-
-int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter);
-void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter);
-
-int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter);
-void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter);
-
-void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter);
-void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter);
-void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
-
-int qlcnic_check_fw_status(struct qlcnic_adapter *adapter);
-void qlcnic_watchdog_task(struct work_struct *work);
-void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_rds_ring *rds_ring);
-int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
-void qlcnic_set_multi(struct net_device *netdev);
-void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
-int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter);
-int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd);
-int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable);
-void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
-
-int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
-int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
-netdev_features_t qlcnic_fix_features(struct net_device *netdev,
-       netdev_features_t features);
-int qlcnic_set_features(struct net_device *netdev, netdev_features_t features);
-int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
-int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
-void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_tx_ring *tx_ring);
-void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
-void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter);
-int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode);
+int qlcnic_attach(struct qlcnic_adapter *);
+void qlcnic_detach(struct qlcnic_adapter *);
+void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter);
+void qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+void __qlcnic_down(struct qlcnic_adapter *, struct net_device *);
+int qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+int __qlcnic_up(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_restore_indev_addr(struct net_device *, unsigned long);
+void qlcnic_83xx_cancel_idc_work(struct qlcnic_adapter *);
+void qlcnic_schedule_work(struct qlcnic_adapter *, work_func_t, int);
+int qlcnic_load_firmware(struct qlcnic_adapter *);
+int qlcnic_need_fw_reset(struct qlcnic_adapter *);
+void qlcnic_request_firmware(struct qlcnic_adapter *);
+void qlcnic_release_firmware(struct qlcnic_adapter *);
+int qlcnic_pinit_from_rom(struct qlcnic_adapter *);
+int qlcnic_setup_idc_param(struct qlcnic_adapter *);
+int qlcnic_check_flash_fw_ver(struct qlcnic_adapter *);
+int qlcnic_rom_fast_read(struct qlcnic_adapter *, u32, u32 *);
+int qlcnic_rom_fast_read_words(struct qlcnic_adapter *, int, u8 *, size_t);
+int qlcnic_alloc_sw_resources(struct qlcnic_adapter *);
+void qlcnic_free_sw_resources(struct qlcnic_adapter *);
+void __iomem *qlcnic_get_ioaddr(struct qlcnic_hardware_context *, u32);
+
+int qlcnic_alloc_hw_resources(struct qlcnic_adapter *);
+void qlcnic_free_hw_resources(struct qlcnic_adapter *);
+int qlcnic_fw_create_ctx(struct qlcnic_adapter *);
+void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *);
+void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *);
+void qlcnic_release_rx_buffers(struct qlcnic_adapter *);
+void qlcnic_release_tx_buffers(struct qlcnic_adapter *);
+struct sk_buff* qlcnic_process_rxbuf(struct qlcnic_adapter *,
+                struct qlcnic_host_rds_ring *, u16, u16);
+int qlcnic_check_fw_status(struct qlcnic_adapter *);
+void qlcnic_watchdog_task(struct work_struct *);
+void qlcnic_post_rx_buffers(struct qlcnic_adapter *,
+               struct qlcnic_host_rds_ring *, u8);
+int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *, int);
+void qlcnic_set_multi(struct net_device *);
+void qlcnic_free_mac_list(struct qlcnic_adapter *);
+int qlcnic_nic_set_promisc(struct qlcnic_adapter *, u32);
+void qlcnic_config_intr_coalesce(struct qlcnic_adapter *);
+int qlcnic_config_rss(struct qlcnic_adapter *, int);
+void qlcnic_config_ipaddr(struct qlcnic_adapter *, __be32, int);
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *, __be32, int);
+int qlcnic_linkevent_request(struct qlcnic_adapter *, int);
+int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *, int);
+int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter);
+int qlcnic_change_mtu(struct net_device *, int);
+u32 qlcnic_fix_features(struct net_device *, u32);
+int qlcnic_set_features(struct net_device *, u32);
+int qlcnic_config_hw_lro(struct qlcnic_adapter *, int);
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *, u32);
+int qlcnic_send_lro_cleanup(struct qlcnic_adapter *);
+void qlcnic_update_cmd_producer(struct qlcnic_adapter *,
+               struct qlcnic_host_tx_ring *);
+void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);
+int qlcnic_clear_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_set_lb_mode(struct qlcnic_adapter *, u8);
+
+void qlcnic_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+int qlcnic_set_fw_loopback(struct qlcnic_adapter *, u8);
+int qlcnic_nic_set_promisc(struct qlcnic_adapter *, u32);
+void qlcnic_change_filter(struct qlcnic_adapter *, u64 *, __le16);
 
 /* Functions from qlcnic_ethtool.c */
-int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);
+int qlcnic_check_loopback_buff(unsigned char *, u8 []);
+int qlcnic_do_lb_test(struct qlcnic_adapter *, u8);
+int qlcnic_loopback_test(struct net_device *, u8);
 
 /* Functions from qlcnic_main.c */
 int qlcnic_reset_context(struct qlcnic_adapter *);
-void qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *);
+int qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *);
 void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
 netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val);
+int qlcnic_validate_max_rss(u8 max_hw, u8 val);
 int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
-void qlcnic_dev_request_reset(struct qlcnic_adapter *);
+void qlcnic_dev_request_reset(struct qlcnic_adapter *, u32);
 void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
 
+int qlcnic_setup_intr(struct qlcnic_adapter *, u8);
+int qlcnic_poll(struct napi_struct *, int);
+int qlcnic_rx_poll(struct napi_struct *, int);
+void qlcnic_set_vlan_config(struct qlcnic_adapter *,
+                struct qlcnic_esw_func_cfg *);
+void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *,
+               struct qlcnic_esw_func_cfg *);
+int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
+void qlcnic_check_options(struct qlcnic_adapter *adapter);
+void qlcnic_handle_fw_message(int, int, struct qlcnic_host_sds_ring *);
+int qlcnic_alloc_rx_skb(struct qlcnic_adapter *, struct qlcnic_host_rds_ring *,
+               struct qlcnic_rx_buffer *);
+void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *,
+               struct qlcnic_host_rds_ring *, u8);
+int qlcnic_process_cmd_ring(struct qlcnic_adapter *,
+       struct qlcnic_host_tx_ring *, int);
+int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *, int);
+int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
+void qlcnic_process_rcv_diag(struct qlcnic_adapter *,
+               struct qlcnic_host_sds_ring *, int, u64);
+int qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *,
+       struct qlcnic_host_tx_ring *tx_ring, int);
+void qlcnic_handle_linkevent(struct qlcnic_adapter *, struct qlcnic_fw_msg *);
+void qlcnic_advert_link_change(struct qlcnic_adapter *, int);
+int qlcnic_check_rx_tagging(struct qlcnic_adapter *, struct sk_buff *, u16 *);
+int qlcnic_check_temp(struct qlcnic_adapter *adapter);
+void qlcnic_get_lro_mss_cap(struct qlcnic_adapter *adapter);
+int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter);
+/* functions from qlcnic_io.c */
+void dump_skb(struct sk_buff *, struct qlcnic_adapter *);
+
+/* functions in qlcnic_sysfs.c */
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
+void qlcnic_create_sysfs_entries(struct qlcnic_adapter *);
+void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *);
+void qlcnic_create_diag_entries(struct qlcnic_adapter *);
+void qlcnic_remove_diag_entries(struct qlcnic_adapter *);
+void qlcnic_add_sysfs(struct qlcnic_adapter *);
+void qlcnic_remove_sysfs(struct qlcnic_adapter *);
+int qlcnic_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+
 /* Management functions */
 int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
 int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
 int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
 int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
+int qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter);
 
 /*  eSwitch management functions */
 int qlcnic_config_switch_port(struct qlcnic_adapter *,
@@ -1565,11 +1713,139 @@ int qlcnic_get_eswitch_port_config(struct qlcnic_adapter *,
 int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
 int qlcnic_get_port_stats(struct qlcnic_adapter *, const u8, const u8,
                                        struct __qlcnic_esw_statistics *);
+int qlcnic_get_mac_stats(struct qlcnic_adapter *,
+                                       struct qlcnic_mac_statistics *);
 int qlcnic_get_eswitch_stats(struct qlcnic_adapter *, const u8, u8,
                                        struct __qlcnic_esw_statistics *);
-int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
-int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
-extern int qlcnic_config_tso;
+int qlcnic_clear_esw_stats(struct qlcnic_adapter *, u8, u8, u8);
+int qlcnic_check_eswitch_mode(struct qlcnic_adapter *);
+int qlcnic_init_pci_info(struct qlcnic_adapter *);
+int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_reset_npar_config(struct qlcnic_adapter *);
+int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *,
+                               struct qlcnic_adapter *, u32);
+/* 83xx funcitons */
+int qlcnic_83xx_get_fw_version(struct qlcnic_adapter *);
+void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *);
+int qlcnic_83xx_mbx_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+int qlcnic_83xx_setup_intr(struct qlcnic_adapter *, u8);
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *);
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *);
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *);
+int qlcnic_83xx_lock_driver(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_driver(struct qlcnic_adapter *);
+int qlcnic_send_ctrl_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *, u32);
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *);
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
+u32 qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *);
+int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *,
+               struct qlcnic_host_sds_ring *, int, u64 []);
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8);
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *);
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, __le16);
+int qlcnic_83xx_napi_add(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_83xx_napi_del(struct qlcnic_adapter *);
+
+int qlcnic_83xx_init(struct qlcnic_adapter *);
+void qlcnic_83xx_cancel_fw_work(struct qlcnic_adapter *);
+void qlcnic_83xx_dev_request_reset(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_83xx_idc_vnic_pf_ready_state_entry_action(struct qlcnic_adapter *);
+int qlcnic_83xx_idc_ready_state_entry_action(struct qlcnic_adapter *);
+int qlcnic_83xx_set_vnic_operational(struct qlcnic_adapter *, int);
+int qlcnic_83xx_set_vnic_non_operational(struct qlcnic_adapter *, int);
+int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *);
+int qlcnic_83xx_set_default_offload_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *,
+               struct qlcnic_info *, u8);
+int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *);
+void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int);
+int qlcnic_83xx_interrupt_test(struct net_device *);
+void qlcnic_83xx_idc_aen_work(struct work_struct *);
+int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *);
+int qlcnic_83xx_loopback_test(struct net_device *, u8);
+
+/* 83xx MS memory access API's */
+int qlcnic_83xx_ms_mem_write_128b(struct qlcnic_adapter *, u64, u32 *, u32);
+void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32);
+u32 qlcnic_ind_rd(struct qlcnic_adapter *, u32);
+
+/* 83xx flash operations */
+int qlcnic_83xx_flash_read_u32(struct qlcnic_adapter *, u32, u8 *, int);
+int qlcnic_83xx_lockless_flash_read_u32(struct qlcnic_adapter *,
+               u32, u8 *, int);
+int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *, u32);
+int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *, u32, u32 *, int);
+int qlcnic_83xx_flash_write_u32(struct qlcnic_adapter *, u32, u32 *);
+int qlcnic_83xx_lock_flash(struct qlcnic_adapter *);
+void qlcnic_83xx_unlock_flash(struct qlcnic_adapter *);
+int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *);
+int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *);
+
+/* IDC user API */
+
+/* 83xx reset template operations */
+int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);
+void qlcnic_83xx_free_reset_template(struct qlcnic_adapter *);
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *,
+        struct qlcnic_host_tx_ring *, int);
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int);
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool);
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *);
+int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *);
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *);
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8,
+       struct qlcnic_cmd_args *);
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *,
+                                       struct qlcnic_adapter *, u32);
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *);
+void qlcnic_set_npar_data(struct qlcnic_adapter *, const struct qlcnic_info *,
+       struct qlcnic_info *);
+void qlcnic_83xx_napi_enable(struct qlcnic_adapter *);
+void qlcnic_83xx_napi_disable(struct qlcnic_adapter *);
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_handle_aen(int, void *);
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *,
+               struct ethtool_pauseparam *);
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *,
+               struct ethtool_pauseparam *);
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
+int qlcnic_83xx_test_link(struct qlcnic_adapter *);
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *);
+int qlcnic_83xx_eeprom_test(struct qlcnic_adapter *);
+int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *);
+int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *);
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
+irqreturn_t qlcnic_83xx_tmp_intr(int, void *);
+void qlcnic_83xx_enable_intr(struct qlcnic_adapter *,
+               struct qlcnic_host_sds_ring *);
+void qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *,
+               struct qlcnic_host_tx_ring *);
+void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *,
+       struct qlcnic_host_tx_ring *);
+void qlcnic_83xx_check_vf(struct qlcnic_adapter *,
+               const struct pci_device_id *);
+void qlcnic_83xx_register_map(struct qlcnic_hardware_context *);
+
+int qlcnic_is_valid_nic_func(struct qlcnic_adapter *, u8);
+
+int qlcnic_enable_eswitch(struct qlcnic_adapter *, u8, u8);
 
 /*
  * QLOGIC Board information
@@ -1584,30 +1860,6 @@ struct qlcnic_brdinfo {
        char short_name[QLCNIC_MAX_BOARD_NAME_LEN];
 };
 
-static const struct qlcnic_brdinfo qlcnic_boards[] = {
-       {0x1077, 0x8020, 0x1077, 0x203,
-               "8200 Series Single Port 10GbE Converged Network Adapter "
-               "(TCP/IP Networking)"},
-       {0x1077, 0x8020, 0x1077, 0x207,
-               "8200 Series Dual Port 10GbE Converged Network Adapter "
-               "(TCP/IP Networking)"},
-       {0x1077, 0x8020, 0x1077, 0x20b,
-               "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"},
-       {0x1077, 0x8020, 0x1077, 0x20c,
-               "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"},
-       {0x1077, 0x8020, 0x1077, 0x20f,
-               "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
-       {0x1077, 0x8020, 0x103c, 0x3733,
-               "NC523SFP 10Gb 2-port Server Adapter"},
-       {0x1077, 0x8020, 0x103c, 0x3346,
-               "CN1000Q Dual Port Converged Network Adapter"},
-       {0x1077, 0x8020, 0x1077, 0x210,
-               "QME8242-k 10GbE Dual Port Mezzanine Card"},
-       {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
-};
-
-#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
-
 static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
 {
        if (likely(tx_ring->producer < tx_ring->sw_consumer))
@@ -1618,16 +1870,60 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
 }
 
 extern const struct ethtool_ops qlcnic_ethtool_ops;
-extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
 
 struct qlcnic_nic_template {
        int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
        int (*config_led) (struct qlcnic_adapter *, u32, u32);
        int (*start_firmware) (struct qlcnic_adapter *);
+       int (*init_driver) (struct qlcnic_adapter *);
+       void (*request_reset) (struct qlcnic_adapter *, u32);
+       void (*cancel_idc_work) (struct qlcnic_adapter *);
+       int (*napi_add)(struct qlcnic_adapter *, struct net_device *);
+       void (*napi_del)(struct qlcnic_adapter *);
+       void (*config_ipaddr)(struct qlcnic_adapter *, __be32, int);
+       irqreturn_t (*clear_legacy_intr)(struct qlcnic_adapter *);
+};
+
+/* function template for hardware ops based on different chip type */
+struct qlcnic_hardware_ops {
+       void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+       void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
+       u32 (*rdreg) (struct qlcnic_adapter *, ulong, int *);
+       int (*wrtreg) (struct qlcnic_adapter *, ulong, u32);
+       void (*get_ocm_win) (struct qlcnic_hardware_context *);
+       int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
+       int (*setup_intr) (struct qlcnic_adapter *, u8);
+       int (*alloc_mbx_args)(struct qlcnic_cmd_args *,
+                               struct qlcnic_adapter *, u32);
+       int (*mbx_cmd) (struct qlcnic_adapter *, struct qlcnic_cmd_args *);
+       void (*get_func_no) (struct qlcnic_adapter *);
+       int (*api_lock) (struct qlcnic_adapter *);
+       void (*api_unlock) (struct qlcnic_adapter *);
+       void (*add_sysfs) (struct qlcnic_adapter *);
+       void (*remove_sysfs) (struct qlcnic_adapter *);
+       void (*process_lb_rcv_ring_diag) (struct qlcnic_host_sds_ring *);
+       int (*create_rx_ctx) (struct qlcnic_adapter *);
+       int (*create_tx_ctx) (struct qlcnic_adapter *,
+                struct qlcnic_host_tx_ring *, int);
+       int (*setup_link_event) (struct qlcnic_adapter *, int);
+       int (*get_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *, u8);
+       int (*get_pci_info) (struct qlcnic_adapter *, struct qlcnic_pci_info *);
+       int (*set_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *);
+       int (*change_macvlan) (struct qlcnic_adapter *, u8*, __le16, u8);
+       void (*napi_enable) (struct qlcnic_adapter *);
+       void (*napi_disable) (struct qlcnic_adapter *);
+       void (*config_intr_coal) (struct qlcnic_adapter *);
+       int (*config_rss) (struct qlcnic_adapter *, int);
+       int (*config_hw_lro) (struct qlcnic_adapter *, int);
+       int (*config_loopback) (struct qlcnic_adapter *, u8);
+       int (*clear_loopback) (struct qlcnic_adapter *, u8);
+       int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
+       void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, __le16);
+       int (*get_board_info) (struct qlcnic_adapter *);
 };
 
 #define QLCDB(adapter, lvl, _fmt, _args...) do {       \
-       if (NETIF_MSG_##lvl & adapter->msg_enable)      \
+       if (NETIF_MSG_##lvl & adapter->ahw->msg_enable) \
                printk(KERN_INFO "%s: %s: " _fmt,       \
                         dev_name(&adapter->pdev->dev), \
                        __func__, ##_args);             \
diff --git a/drivers/net/qlcnic/qlcnic_83xx.c b/drivers/net/qlcnic/qlcnic_83xx.c
new file mode 100644 (file)
index 0000000..372c31e
--- /dev/null
@@ -0,0 +1,3731 @@
+#include "qlcnic.h"
+#include <linux/if_vlan.h>
+#include <linux/ipv6.h>
+
+/* Array of FW control command structs with command type and required
+ * number of input and output arguments respectively.
+*/
+static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
+       { QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1 },
+       { QLCNIC_CMD_CONFIG_INTRPT, 18, 34 },
+       { QLCNIC_CMD_CREATE_RX_CTX, 136, 27 },
+       { QLCNIC_CMD_DESTROY_RX_CTX, 2, 1 },
+       { QLCNIC_CMD_CREATE_TX_CTX, 54, 18 },
+       { QLCNIC_CMD_DESTROY_TX_CTX, 2, 1 },
+       { QLCNIC_CMD_CONFIGURE_MAC_LEARNING, 2, 1 },
+       { QLCNIC_CMD_INTRPT_TEST, 22, 12 },
+       { QLCNIC_CMD_SET_MTU, 3, 1 },
+       { QLCNIC_CMD_READ_PHY, 4, 2 },
+       { QLCNIC_CMD_WRITE_PHY, 5, 1 },
+       { QLCNIC_CMD_READ_HW_REG, 4, 1 },
+       { QLCNIC_CMD_GET_FLOW_CTL, 4, 2 },
+       { QLCNIC_CMD_SET_FLOW_CTL, 4, 1 },
+       { QLCNIC_CMD_READ_MAX_MTU, 4, 2 },
+       { QLCNIC_CMD_READ_MAX_LRO, 4, 2 },
+       { QLCNIC_CMD_MAC_ADDRESS, 4, 3 },
+       { QLCNIC_CMD_GET_PCI_INFO, 1, 66 },
+       { QLCNIC_CMD_GET_NIC_INFO, 2, 19 },
+       { QLCNIC_CMD_SET_NIC_INFO, 32, 1 },
+       { QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3 },
+       { QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1 },
+       { QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3 },
+       { QLCNIC_CMD_SET_PORTMIRRORING, 4, 1 },
+       { QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1 },
+       { QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3 },
+       { QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1 },
+       { QLCNIC_CMD_CONFIG_PORT, 4, 1 },
+       { QLCNIC_CMD_TEMP_SIZE, 1, 4 },
+       { QLCNIC_CMD_GET_TEMP_HDR, 5, 5 },
+       { QLCNIC_CMD_GET_LINK_EVENT, 2, 1 },
+       { QLCNIC_CMD_CONFIG_MAC_VLAN, 4, 3 },
+       { QLCNIC_CMD_CONFIG_INTR_COAL, 6, 1 },
+       { QLCNIC_CMD_CONFIGURE_RSS, 14, 1 },
+       { QLCNIC_CMD_CONFIGURE_LED, 2, 1 },
+       { QLCNIC_CMD_CONFIGURE_MAC_RX_MODE, 2, 1 },
+       { QLCNIC_CMD_CONFIGURE_HW_LRO, 2, 1 },
+       { QLCNIC_CMD_GET_STATISTICS, 2, 80 },
+       { QLCNIC_CMD_SET_PORT_CONFIG, 2, 1 },
+       { QLCNIC_CMD_GET_PORT_CONFIG, 2, 2 },
+       { QLCNIC_CMD_GET_LINK_STATUS, 2, 4},
+       { QLCNIC_CMD_IDC_ACK, 5, 1},
+       { QLCNIC_CMD_INIT_NIC_FUNC, 2, 1},
+       { QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
+       { QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
+       { QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
+       { QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
+};
+
+const u32 qlcnic_83xx_ext_reg_tbl[] = {
+       0x38CC, /* Global Reset */
+       0x38F0, /* Wildcard */
+       0x38FC, /* Informant */
+       0x3038, /* Host MBX ctrl */
+       0x303C, /* FW MBX ctrl */
+       0x355C, /* BOOT LOADER ADDRESS REG */
+       0x3560, /* BOOT LOADER SIZE REG */
+       0x3564, /* FW IMAGE ADDR REG */
+       0x1000, /* MBX intr enable */
+       0x1200, /* Default Intr mask */
+       0x1204, /* Default Interrupt ID */
+       0x3780, /* QLC_83XX_IDC_MAJ_VERSION */
+       0x3784, /* QLC_83XX_IDC_DEV_STATE */
+       0x3788, /* QLC_83XX_IDC_DRV_PRESENCE */
+       0x378C, /* QLC_83XX_IDC_DRV_ACK */
+       0x3790, /* QLC_83XX_IDC_CTRL */
+       0x3794, /* QLC_83XX_IDC_DRV_AUDIT */
+       0x3798, /* QLC_83XX_IDC_MIN_VERSION */
+       0x379C, /* QLC_83XX_RECOVER_DRV_LOCK */
+       0x37A0, /* QLC_83XX_IDC_PF_0 */
+       0x37A4, /* QLC_83XX_IDC_PF_1 */
+       0x37A8, /* QLC_83XX_IDC_PF_2 */
+       0x37AC, /* QLC_83XX_IDC_PF_3 */
+       0x37B0, /* QLC_83XX_IDC_PF_4 */
+       0x37B4, /* QLC_83XX_IDC_PF_5 */
+       0x37B8, /* QLC_83XX_IDC_PF_6 */
+       0x37BC, /* QLC_83XX_IDC_PF_7 */
+       0x37C0, /* QLC_83XX_IDC_PF_8 */
+       0x37C4, /* QLC_83XX_IDC_PF_9 */
+       0x37C8, /* QLC_83XX_IDC_PF_10 */
+       0x37CC, /* QLC_83XX_IDC_PF_11 */
+       0x37D0, /* QLC_83XX_IDC_PF_12 */
+       0x37D4, /* QLC_83XX_IDC_PF_13 */
+       0x37D8, /* QLC_83XX_IDC_PF_14 */
+       0x37DC, /* QLC_83XX_IDC_PF_15 */
+       0x37E0, /* QLC_83XX_IDC_DEV_PARTITION_INFO_1 */
+       0x37E4, /* QLC_83XX_IDC_DEV_PARTITION_INFO_2 */
+       0x37F0, /* QLC_83XX_DRV_OP_MODE */
+       0x37F4, /* QLC_83XX_VNIC_STATE */
+       0x3868, /* QLC_83XX_DRV_LOCK */
+       0x386C, /* QLC_83XX_DRV_UNLOCK */
+       0x3504, /* QLC_83XX_DRV_LOCK_ID */
+       0x34A4, /* QLC_83XX_ASIC_TEMP */
+};
+
+const u32 qlcnic_83xx_reg_tbl[] = {
+       0x34A8, /* PEG_HALT_STAT1 */
+       0x34AC, /* PEG_HALT_STAT2 */
+       0x34B0, /* FW_HEARTBEAT */
+       0x3500, /* FLASH LOCK_ID */
+       0x3528, /* FW_CAPABILITIES */
+       0x3538, /* drv active, DRV_REG0 */
+       0x3540, /* dev state, DRV_REG1 */
+       0x3544, /* drv state, DRV_REG2 */
+       0x3548, /* drv scratch, DRV_REG3 */
+       0x354C, /* dev part info, DRV_REG4 */
+       0x3524, /* drv IDC ver, DRV_REG5 */
+       0x3550, /* FW_VER_MAJOR */
+       0x3554, /* FW_VER_MINOR */
+       0x3558, /* FW_VER_SUB */
+       0x359C, /* NPAR STATE */
+       0x35FC, /* FW_IMG_VALID */
+       0x3650, /* CMD_PEG_STATE */
+       0x373C, /* RCV_PEG_STATE */
+       0x37B4, /* ASIC TEMP */
+       0x356C, /* FW API */
+       0x3570, /* DRV OP MODE */
+       0x3850, /* FLASH LOCK */
+       0x3854, /* FLASH UNLOCK */
+};
+
+static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
+       .read_crb = qlcnic_83xx_read_crb,
+       .write_crb = qlcnic_83xx_write_crb,
+       .rdreg = qlcnic_83xx_rd_reg_indirect,
+       .wrtreg = qlcnic_83xx_wrt_reg_indirect,
+       .get_mac_address = qlcnic_83xx_get_mac_address,
+       .setup_intr = qlcnic_83xx_setup_intr,
+       .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args,
+       .mbx_cmd = qlcnic_83xx_mbx_op,
+       .get_func_no = qlcnic_83xx_get_func_no,
+       .api_lock = qlcnic_83xx_cam_lock,
+       .api_unlock = qlcnic_83xx_cam_unlock,
+       .add_sysfs = qlcnic_83xx_add_sysfs,
+       .remove_sysfs = qlcnic_83xx_remove_sysfs,
+       .process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag,
+       .create_rx_ctx = qlcnic_83xx_create_rx_ctx,
+       .create_tx_ctx = qlcnic_83xx_create_tx_ctx,
+       .setup_link_event = qlcnic_83xx_setup_link_event,
+       .get_nic_info = qlcnic_83xx_get_nic_info,
+       .get_pci_info = qlcnic_83xx_get_pci_info,
+       .set_nic_info = qlcnic_83xx_set_nic_info,
+       .change_macvlan = qlcnic_83xx_sre_macaddr_change,
+       .napi_enable = qlcnic_83xx_napi_enable,
+       .napi_disable = qlcnic_83xx_napi_disable,
+       .config_intr_coal = qlcnic_83xx_config_intr_coal,
+       .config_rss = qlcnic_83xx_config_rss,
+       .config_hw_lro = qlcnic_83xx_config_hw_lro,
+       .config_promisc_mode = qlcnic_83xx_nic_set_promisc,
+       .change_l2_filter = qlcnic_83xx_change_l2_filter,
+       .get_board_info = qlcnic_83xx_get_port_info,
+};
+
+static void
+qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, u32 data[]);
+static void
+qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter, u32 data[]);
+
+void
+qlcnic_83xx_register_map(struct qlcnic_hardware_context *ahw)
+{
+       ahw->hw_ops = &qlcnic_83xx_hw_ops;
+       ahw->reg_tbl = (u32 *) qlcnic_83xx_reg_tbl;
+       ahw->ext_reg_tbl = (u32 *) qlcnic_83xx_ext_reg_tbl;
+}
+
+int
+qlcnic_83xx_get_fw_version(struct qlcnic_adapter *adapter)
+{
+       u32 fw_major, fw_minor, fw_build;
+       struct pci_dev *pdev = adapter->pdev;
+
+       fw_major = QLCRD(adapter, QLCNIC_FW_VERSION_MAJOR);
+       fw_minor = QLCRD(adapter, QLCNIC_FW_VERSION_MINOR);
+       fw_build = QLCRD(adapter, QLCNIC_FW_VERSION_SUB);
+       adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
+
+       dev_info(&pdev->dev, "Driver v%s, firmware version %d.%d.%d\n",
+               QLCNIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build);
+
+       return adapter->fw_version;
+}
+
+void
+qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
+{
+       u32 prev_version, current_version;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
+       struct pci_dev *pdev = adapter->pdev;
+
+       prev_version = adapter->fw_version;
+       current_version = qlcnic_83xx_get_fw_version(adapter);
+
+       if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
+               if (fw_dump->tmpl_hdr)
+                       vfree(fw_dump->tmpl_hdr);
+               if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
+                       dev_info(&pdev->dev,
+                               "Supports FW dump capability\n");
+       }
+}
+
+/* Caller needs to use locking before accessing this function */
+static int
+__qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)
+{
+       void __iomem *base;
+       u32 val;
+
+       base = adapter->ahw->pci_base0 +
+               QLC_83XX_CRB_WIN_FUNC(adapter->ahw->pci_func);
+       writel(addr, base);
+       val = readl(base);
+       if (val != addr)
+               return -EIO;
+
+       return 0;
+}
+
+u32
+qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter,
+                                               ulong addr, int *err)
+{
+       int ret;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       ret = __qlcnic_set_win_base(adapter, (u32) addr);
+       if (!ret) {
+               *err = 0;
+               return QLCRDX(ahw, QLCNIC_WILDCARD);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "%s failed, addr = 0x%x\n", __func__, (int)addr);
+               if (err)
+                       *err = -EIO;
+
+               return -1;
+       }
+}
+
+/* Caller needs to use locking before accessing this function */
+int
+qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
+               u32 data)
+{
+       int err;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       err = __qlcnic_set_win_base(adapter, (u32) addr);
+       if (!err) {
+               QLCWRX(ahw, QLCNIC_WILDCARD, data);
+               return 0;
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "%s failed, addr = 0x%x data = 0x%x\n",
+                                               __func__, (int)addr, data);
+               return err;
+       }
+}
+
+int
+qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
+{
+       int err, i, num_msix;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (!num_intr)
+               num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+       num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
+                               num_intr));
+
+       /* account for AEN interrupt MSI-X based interrupts */
+       num_msix += 1;
+       num_msix += adapter->max_drv_tx_rings;
+       err = qlcnic_enable_msix(adapter, num_msix);
+       if (err == -ENOMEM)
+               return err;
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               num_msix = adapter->ahw->num_msix;
+       else
+               num_msix = 1;
+       /* setup interrupt mapping table for fw */
+       ahw->intr_tbl = (struct qlcnic_intrpt_config *) vmalloc(num_msix *
+               sizeof(struct qlcnic_intrpt_config));
+       if (!ahw->intr_tbl)
+               return -ENOMEM;
+       if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               /* MSI-X enablement failed, use legacy interrupt */
+               adapter->tgt_status_reg = ahw->pci_base0 + QLCNIC_83XX_INTX_PTR;
+               adapter->tgt_mask_reg = ahw->pci_base0 + QLCNIC_83XX_INTX_MASK;
+               adapter->isr_int_vec = ahw->pci_base0 + QLCNIC_83XX_INTX_TRGR;
+               adapter->msix_entries[0].vector = adapter->pdev->irq;
+               dev_info(&adapter->pdev->dev, "using legacy interrupt\n");
+       }
+       memset(ahw->intr_tbl, 0, sizeof(struct qlcnic_intrpt_config));
+       for (i = 0; i < num_msix; i++) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       ahw->intr_tbl[i].type = QLCNIC_INTRPT_MSIX;
+               else
+                       ahw->intr_tbl[i].type = QLCNIC_INTRPT_INTX;
+               ahw->intr_tbl[i].id = i;
+               ahw->intr_tbl[i].src = 0;
+       }
+       return 0;
+}
+
+inline void
+qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
+       struct qlcnic_host_sds_ring *sds_ring)
+{
+       writel(0, sds_ring->crb_intr_mask);
+       if (!QLCNIC_IS_MSI_FAMILY(adapter))
+               writel(0, adapter->tgt_mask_reg);
+}
+
+inline void
+qlcnic_83xx_enable_tx_intr(struct qlcnic_adapter *adapter,
+       struct qlcnic_host_tx_ring *tx_ring)
+{
+       writel(0, tx_ring->crb_intr_mask);
+}
+
+inline void
+qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
+                       struct qlcnic_cmd_args *cmd)
+{
+       int i;
+       for (i = 0; i < cmd->rsp.num; i++)
+               cmd->rsp.arg[i] = readl(QLCNIC_MBX_FW(adapter->ahw, i));
+}
+
+inline void
+qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter,
+       struct qlcnic_host_tx_ring *tx_ring)
+{
+       writel(1, tx_ring->crb_intr_mask);
+}
+
+irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
+{
+       u32 intr_val;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       intr_val = readl(adapter->tgt_status_reg);
+
+       if (!QLCNIC_83XX_VALID_INTX_BIT31(intr_val))
+               return IRQ_NONE;
+
+       if (QLCNIC_83XX_INTX_FUNC(intr_val) != adapter->ahw->pci_func) {
+               adapter->stats.spurious_intr++;
+               return IRQ_NONE;
+       }
+       /* The barrier is required to ensure writes to the registers */
+       wmb();
+
+       /* clear the interrupt trigger control register */
+       writel(0, adapter->isr_int_vec);
+       intr_val = readl(adapter->isr_int_vec);
+
+       /* Legacy Workaround for A0 & B0 */
+       do {
+               intr_val = readl(adapter->tgt_status_reg);
+               if (QLCNIC_83XX_INTX_FUNC(intr_val) != ahw->pci_func)
+                       break;
+       } while (QLCNIC_83XX_VALID_INTX_BIT30(intr_val));
+
+       return IRQ_HANDLED;
+}
+
+irqreturn_t qlcnic_83xx_tmp_intr(int irq, void *data)
+{
+       struct qlcnic_host_sds_ring *sds_ring = data;
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               goto done;
+
+       if (qlcnic_83xx_clear_legacy_intr(adapter) == IRQ_NONE)
+               return IRQ_NONE;
+
+done:
+       adapter->ahw->diag_cnt++;
+       qlcnic_83xx_enable_intr(adapter, sds_ring);
+
+       return IRQ_HANDLED;
+}
+
+void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
+{
+       u32 val = 0;
+       u32 num_msix = adapter->ahw->num_msix - 1;
+
+       val = (num_msix << 8);
+
+       QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               free_irq(adapter->msix_entries[num_msix].vector, adapter);
+}
+
+int
+qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
+{
+       irq_handler_t handler;
+       u32 val;
+       char name[32];
+       int err = 0;
+       unsigned long flags = 0;
+
+       if (!(adapter->flags & QLCNIC_MSI_ENABLED) &&
+               !(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               flags |= IRQF_SHARED;
+       }
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               handler = qlcnic_83xx_handle_aen;
+               val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
+               snprintf(name, (IFNAMSIZ+4),
+                       "%s[%s]", adapter->netdev->name, "aen");
+               err = request_irq(val, handler, flags, name, adapter);
+               if (err) {
+                       dev_err(&adapter->pdev->dev,
+                               "failed to register MBX interrupt\n");
+                       return err;
+               }
+       }
+
+       /* Enable mailbox interrupt */
+       qlcnic_83xx_enable_mbx_intrpt(adapter);
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               err = qlcnic_83xx_config_intrpt(adapter, 1);
+
+       return err;
+}
+
+void qlcnic_83xx_get_func_no(struct qlcnic_adapter *adapter)
+{
+       u32 val = QLCRDX(adapter->ahw, QLCNIC_INFORMANT);
+       adapter->ahw->pci_func = val & 0xf;
+}
+
+int qlcnic_83xx_cam_lock(struct qlcnic_adapter *adapter)
+{
+       void __iomem *addr;
+       u32 val;
+       u32 timeo = 0;
+
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       addr = ahw->pci_base0 + QLC_83XX_SEM_LOCK_FUNC(ahw->pci_func);
+       do {
+               val = readl(addr);
+               if (val) {
+                       /* write the function number to register */
+                       QLCWR(adapter, QLCNIC_FLASH_LOCK_OWNER, ahw->pci_func);
+                       return 0;
+               }
+               msleep(1);
+       } while (++timeo <= QLCNIC_PCIE_SEM_TIMEOUT);
+
+       return -EIO;
+}
+
+void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)
+{
+       void __iomem *addr;
+       u32 val;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       addr = ahw->pci_base0 + QLC_83XX_SEM_UNLOCK_FUNC(ahw->pci_func);
+       val = readl(addr);
+}
+
+static void
+qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
+       struct qlcnic_cmd_args *cmd)
+{
+       int i;
+
+       dev_info(&adapter->pdev->dev,
+               "Host MBX regs(%d)\n", cmd->req.num);
+       for (i = 0; i < cmd->req.num; i++) {
+               if (i && !(i % 8))
+                       printk(KERN_INFO "\n");
+               printk(KERN_INFO "%08x ", le32_to_cpu(cmd->req.arg[i]));
+       }
+       printk(KERN_INFO "\n");
+       dev_info(&adapter->pdev->dev,
+               "FW MBX regs(%d)\n", cmd->rsp.num);
+       for (i = 0; i < cmd->rsp.num; i++) {
+               if (i && !(i % 8))
+                       printk(KERN_INFO "\n");
+               printk(KERN_INFO "%08x ", le32_to_cpu(cmd->rsp.arg[i]));
+       }
+       printk(KERN_INFO "\n");
+}
+
+static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
+{
+       u32 fw_data;
+       u8 mac_cmd_rcode;
+
+       fw_data = readl(QLCNIC_MBX_FW(adapter->ahw, 2));
+       mac_cmd_rcode = (u8)le32_to_cpu(fw_data);
+       if (mac_cmd_rcode == QLCNIC_NO_CARD_RESOURCE ||
+               mac_cmd_rcode == QLCNIC_MAC_ALREADY_EXISTS ||
+               mac_cmd_rcode == QLCNIC_MAC_DOES_NOT_EXIST)
+               return QLCNIC_RCODE_SUCCESS;
+       return 1;
+}
+
+/* Wait for a single mailbox command to complete */
+static u32 qlcnic_83xx_wait_mbx_cmd_cmplt(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       u32 data;
+       int count = QLCNIC_MBX_POLL_CNT;
+
+       /* wait for mailbox completion */
+       do {
+               data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
+               if (data)
+                       return data;
+               mdelay(QLCNIC_MBX_POLL_DELAY_MSEC);
+       } while (--count);
+       return QLCNIC_RCODE_TIMEOUT;
+}
+
+int
+qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       unsigned long flags, count;
+       u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd;
+       u16 opcode;
+       u8 mbx_err_code;
+       int i;
+
+       opcode = LSW(le32_to_cpu(cmd->req.arg[0]));
+       if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+               QLCDB(adapter, DRV,
+                     "Mailbox cmd attempted, 0x%x\n", opcode);
+               QLCDB(adapter, DRV, "Mailbox detached\n");
+               return 0;
+       }
+
+       spin_lock_irqsave(&ahw->mbx_lock, flags);
+
+       mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+       if (mbx_val) {
+               QLCDB(adapter, DRV,
+                     "Mailbox cmd attempted, 0x%x\n", opcode);
+               QLCDB(adapter, DRV,
+                     "Mailbox not available, 0x%x, collect FW dump\n",
+                     mbx_val);
+               /* Take FW dump */
+               qlcnic_83xx_dev_request_reset(adapter,
+                       QLCNIC_FORCE_FW_DUMP_KEY);
+               cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+               spin_unlock_irqrestore(&ahw->mbx_lock, flags);
+
+               return cmd->rsp.arg[0];
+       }
+
+       /* Fill in mailbox registers */
+       mbx_cmd = cpu_to_le32(cmd->req.arg[0]);
+       writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
+       for (i = 1; i < cmd->req.num; i++)
+               writel(cmd->req.arg[i], QLCNIC_MBX_HOST(ahw, i));
+
+       /* Signal FW about the impending command */
+       QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
+
+       /* Waiting for the mailbox cmd to complete and while waiting here
+        * some AEN might arrive. If more than 5 seconds expire we can
+        * assume something is wrong.
+        */
+       count = jiffies + HZ * QLCNIC_MBX_TIMEOUT;
+       do {
+               rsp = qlcnic_83xx_wait_mbx_cmd_cmplt(adapter);
+               /* Get the FW response data */
+               fw_data = le32_to_cpu(readl(QLCNIC_MBX_FW(ahw, 0)));
+               mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
+               rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
+               opcode = QLCNIC_MBX_RSP(fw_data);
+               qlcnic_83xx_get_mbx_data(adapter, cmd);
+
+               if (rsp != QLCNIC_RCODE_TIMEOUT) {
+                       if (fw_data &  QLCNIC_MBX_ASYNC_EVENT) {
+                               qlcnic_83xx_process_aen(adapter);
+                               continue;
+                       }
+                       switch (mbx_err_code) {
+                       case QLCNIC_MBX_RSP_OK:
+                       case QLCNIC_MBX_PORT_RSP_OK:
+                               rsp = QLCNIC_RCODE_SUCCESS;
+                               break;
+                       default:
+                               if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
+                                       rsp = qlcnic_83xx_mac_rcode(adapter);
+                                       if (!rsp)
+                                               goto out;
+                               }
+                               netdev_err(adapter->netdev,
+                                          "MBX command 0x%x failed with err:0x%x\n",
+                                          opcode, mbx_err_code);
+                               rsp = mbx_err_code;
+                               qlcnic_dump_mbx(adapter, cmd);
+                               break;
+                       }
+                       goto out;
+               }
+       } while (time_before(jiffies, count));
+
+       netdev_err(adapter->netdev, "MBX command 0x%x timed out\n", opcode);
+       rsp = QLCNIC_RCODE_TIMEOUT;
+       qlcnic_dump_mbx(adapter, cmd);
+       /* Take FW dump */
+       qlcnic_83xx_dev_request_reset(adapter, QLCNIC_FORCE_FW_DUMP_KEY);
+out:
+       /* clear fw mbx control register */
+       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+       spin_unlock_irqrestore(&ahw->mbx_lock, flags);
+       return rsp;
+}
+
+/* Allocate mailbox incoming and outgoing registers. It should be used with a
+ * follow up call to qlcnic_free_mbx_args
+ */
+int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+               struct qlcnic_adapter *adapter, u32 type)
+{
+       int i, size;
+       const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+       mbx_tbl = qlcnic_83xx_mbx_tbl;
+       size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
+       for (i = 0; i < size; i++) {
+               if (type == mbx_tbl[i].cmd) {
+                       mbx->req.num = mbx_tbl[i].in_args;
+                       mbx->rsp.num = mbx_tbl[i].out_args;
+                       mbx->req.arg = (u32 *) kcalloc(mbx->req.num,
+                               sizeof(u32), GFP_ATOMIC);
+                       if (!mbx->req.arg)
+                               return -ENOMEM;
+                       mbx->rsp.arg = (u32 *) kcalloc(mbx->rsp.num,
+                               sizeof(u32), GFP_ATOMIC);
+                       if (!mbx->rsp.arg) {
+                               kfree(mbx->req.arg);
+                               mbx->req.arg = NULL;
+                               return -ENOMEM;
+                       }
+                       memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+                       memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+                       mbx->req.arg[0] = (type | (mbx->req.num << 16) |
+                       (adapter->ahw->fw_hal_version << 29));
+                       break;
+               }
+       }
+       return 0;
+}
+
+/* Free up mailbox registers
+ */
+void qlcnic_free_mbx_args(struct qlcnic_cmd_args *cmd)
+{
+       kfree(cmd->req.arg);
+       cmd->req.arg = NULL;
+       kfree(cmd->rsp.arg);
+       cmd->rsp.arg = NULL;
+}
+
+void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
+       loff_t offset, size_t size)
+{
+       u32 data;
+       int err;
+
+       if (adapter->ahw->hw_ops->api_lock(adapter)) {
+               netdev_err(adapter->netdev,
+                       "%s: failed to acquire lock. addr offset 0x%x\n",
+                       __func__, (u32)offset);
+               return;
+       }
+
+       data = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset, &err);
+       adapter->ahw->hw_ops->api_unlock(adapter);
+
+       if (err == -EIO) {
+               netdev_err(adapter->netdev,
+                       "%s: failed. addr offset 0x%x\n",
+                                       __func__, (u32)offset);
+               return;
+       }
+       memcpy(buf, &data, size);
+}
+
+void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
+       loff_t offset, size_t size)
+{
+       u32 data;
+
+       memcpy(&data, buf, size);
+       qlcnic_83xx_wrt_reg_indirect(adapter, (u32) offset, data);
+}
+
+static void
+qlcnic_83xx_recover_driver_lock(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       u32 id;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+
+       /* Check if recovery need to be performed by the calling function */
+       if ((val & QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK) == 0) {
+               val = val & ~0x3F;
+               val = val | ((adapter->portnum << 2) |
+                               QLC_83XX_NEED_DRV_LOCK_RECOVERY);
+               QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+               netdev_info(adapter->netdev,
+                       "%s: lock recovery initiated\n", __func__);
+               msleep(QLC_83XX_DRV_LOCK_RECOVERY_DELAY);
+               val = QLCRDX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK);
+               id = ((val >> 2) & 0xF);
+               if (id == adapter->portnum) {
+                       val = val & ~QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK;
+                       val = val | QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS;
+                       QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+                       /* Force release the lock */
+                       QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+                       /* Clear recovery bits */
+                       val = val & ~0x3F;
+                       QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, val);
+                       netdev_info(adapter->netdev,
+                               "%s: lock recovery completed\n", __func__);
+               } else {
+                       netdev_info(adapter->netdev,
+                               "%s: func %d to resume lock recovery process\n",
+                                        __func__, id);
+               }
+       } else {
+               netdev_info(adapter->netdev,
+                       "%s: lock recovery initiated by other functions\n",
+                                        __func__);
+       }
+}
+
+int
+qlcnic_83xx_lock_driver(struct qlcnic_adapter *adapter)
+{
+       u32 lock_alive_counter, val, id, i = 0, status = 0, temp = 0;
+       int max_attempt = 0;
+
+       while (status == 0) {
+               status = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK);
+               if (status)
+                       break;
+
+               msleep(QLC_83XX_DRV_LOCK_WAIT_DELAY);
+               i++;
+
+               if (i == 1)
+                       temp = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+
+               if (i == QLC_83XX_DRV_LOCK_WAIT_COUNTER) {
+                       val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+                       if (val == temp) {
+                               id = val & 0xFF;
+                               netdev_info(adapter->netdev,
+                                       "%s: lock to be recovered from %d\n",
+                                                                __func__, id);
+                               qlcnic_83xx_recover_driver_lock(adapter);
+                               i = 0;
+                               max_attempt++;
+                       } else {
+                               netdev_info(adapter->netdev,
+                               "%s: failed to acquire lock\n", __func__);
+                               return -EIO;
+                       }
+               }
+
+               /* Force exit from while loop after few attempts */
+               if (max_attempt == QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT) {
+                       netdev_info(adapter->netdev,
+                               "%s: failed to acquire lock\n", __func__);
+                       return -EIO;
+               }
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+       lock_alive_counter = val >> 8;
+       lock_alive_counter++;
+       val = lock_alive_counter << 8 | adapter->portnum;
+       QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+
+       return 0;
+}
+
+void
+qlcnic_83xx_unlock_driver(struct qlcnic_adapter *adapter)
+{
+       u32 val, lock_alive_counter, id;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+       id = val & 0xFF;
+       lock_alive_counter = val >> 8;
+
+       if (id != adapter->portnum)
+               netdev_err(adapter->netdev,
+                       "%s: Warning! func %d is unlocking lock owned by %d\n",
+                                       __func__, adapter->portnum, id);
+
+       val = (lock_alive_counter << 8) | 0xFF;
+       QLCWRX(adapter->ahw, QLC_83XX_DRV_LOCK_ID, val);
+       QLCRDX(adapter->ahw, QLC_83XX_DRV_UNLOCK);
+}
+
+int
+qlcnic_83xx_lock_flash(struct qlcnic_adapter *adapter)
+{
+       int id, timeout = 0;
+       u32 status = 0;
+
+       while (status == 0) {
+               status = QLCRD(adapter, QLCNIC_FLASH_LOCK);
+               if (status)
+                       break;
+
+               if (++timeout >= QLC_83XX_FLASH_LOCK_TIMEOUT) {
+                       id = QLCRD(adapter, QLCNIC_FLASH_LOCK_OWNER);
+                       netdev_err(adapter->netdev,
+                               "%s: failed: lock held by %d\n", __func__, id);
+                       return -EIO;
+               }
+               msleep(1);
+       }
+
+       QLCWR(adapter, QLCNIC_FLASH_LOCK_OWNER, adapter->portnum);
+       return 0;
+}
+
+void
+qlcnic_83xx_unlock_flash(struct qlcnic_adapter *adapter)
+{
+       QLCRD(adapter, QLCNIC_FLASH_UNLOCK);
+       QLCWR(adapter, QLCNIC_FLASH_LOCK_OWNER, 0xFF);
+}
+
+static int
+qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+       u32 status;
+       int err, retries = QLC_83XX_FLASH_READ_RETRY_COUNT;
+
+       do {
+               status = qlcnic_83xx_rd_reg_indirect(adapter,
+                                               QLC_83XX_FLASH_STATUS, &err);
+               if (err == -EIO)
+                       return -EIO;
+
+               if ((status & QLC_83XX_FLASH_STATUS_READY) ==
+                                               QLC_83XX_FLASH_STATUS_READY)
+                       break;
+
+               msleep(QLC_83XX_FLASH_STATUS_REG_POLL_DELAY);
+       } while (--retries);
+
+       if (!retries)
+               return -EIO;
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+       int ret;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                       (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG |
+                       adapter->ahw->flash_fdt.write_statusreg_cmd));
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+                       adapter->ahw->flash_fdt.write_enable_bits);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                       QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret)
+               return -EIO;
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_disable_flash_write_op(struct qlcnic_adapter *adapter)
+{
+       int ret;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                       (QLC_83XX_FLASH_FDT_WRITE_DEF_SIG |
+                       adapter->ahw->flash_fdt.write_statusreg_cmd));
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
+                       adapter->ahw->flash_fdt.write_enable_bits);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                       QLC_83XX_FLASH_SECOND_ERASE_MS_VAL);
+
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret)
+               return -EIO;
+
+       return 0;
+}
+
+int
+qlcnic_83xx_flash_read_u32(struct qlcnic_adapter *adapter, u32 flash_addr,
+                                               u8 *p_data, int u32_word_count)
+{
+       int i, err;
+       u32 u32_word;
+       u32 addr = flash_addr;
+
+       if (qlcnic_83xx_lock_flash(adapter) != 0)
+               return -EIO;
+
+       if (addr & 0x3) {
+               dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+               qlcnic_83xx_unlock_flash(adapter);
+               return -EIO;
+       }
+
+       for (i = 0; i < u32_word_count; i++) {
+               if (qlcnic_83xx_wrt_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_DIRECT_WINDOW, (addr))) {
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+
+               u32_word = qlcnic_83xx_rd_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_DIRECT_DATA(addr), &err);
+               if (err == -EIO) {
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+
+               *(__le32 *)p_data  = le32_to_cpu(u32_word);
+               p_data = p_data + 4;
+               addr = addr + 4;
+       }
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return 0;
+}
+
+int
+qlcnic_83xx_lockless_flash_read_u32(struct qlcnic_adapter *adapter,
+                        u32 flash_addr, u8 *p_data, int u32_word_count)
+{
+       int err;
+       u32 i, u32_word, flash_offset;
+       u32 addr = flash_addr;
+
+       flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);
+
+       if (addr & 0x3) {
+               dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
+               return -EIO;
+       }
+
+       qlcnic_83xx_wrt_reg_indirect(adapter,
+                       QLC_83XX_FLASH_DIRECT_WINDOW, (addr));
+
+       /* Check if data is spread across multiple sectors  */
+       if ((flash_offset + (u32_word_count * sizeof(u32))) >
+                               (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+
+               /* Multi sector read */
+               for (i = 0; i < u32_word_count; i++) {
+                       u32_word = qlcnic_83xx_rd_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_DIRECT_DATA(addr), &err);
+                       if (err == -EIO)
+                               return -EIO;
+
+                       *(__le32 *)p_data  = le32_to_cpu(u32_word);
+                       p_data = p_data + 4;
+                       addr = addr + 4;
+                       flash_offset = flash_offset + 4;
+
+                       if (flash_offset > (QLCNIC_FLASH_SECTOR_SIZE - 1)) {
+                               /* This write is needed once for each sector */
+                               qlcnic_83xx_wrt_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_DIRECT_WINDOW, (addr));
+                               flash_offset = 0;
+                       }
+               }
+       } else {
+               /* Single sector read */
+               for (i = 0; i < u32_word_count; i++) {
+                       u32_word = qlcnic_83xx_rd_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_DIRECT_DATA(addr), &err);
+                       if (err == -EIO)
+                               return -EIO;
+
+                       *(__le32 *)p_data  = cpu_to_le32(u32_word);
+                       p_data = p_data + 4;
+                       addr = addr + 4;
+               }
+       }
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
+{
+       int ret, err;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                               QLC_83XX_FLASH_OEM_READ_SIG);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                               QLC_83XX_FLASH_READ_CONTROL_VAL);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret)
+               return -EIO;
+
+       ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA, &err);
+       return ret&0xFF;
+}
+
+int
+qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
+{
+       int ret, err, mfg_id;
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                       QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                       QLC_83XX_FLASH_READ_CONTROL_VAL);
+
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               qlcnic_83xx_unlock_flash(adapter);
+               return -EIO;
+       }
+
+       mfg_id = qlcnic_83xx_rd_reg_indirect(adapter,
+                               QLC_83XX_FLASH_RDDATA, &err);
+       qlcnic_83xx_unlock_flash(adapter);
+
+       if (err == -EIO)
+               return -EIO;
+
+       adapter->flash_mfg_id = (mfg_id & 0xFF);
+
+       return 0;
+}
+
+int
+qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter)
+{
+       int count, fdt_size, ret = 0;
+
+       fdt_size = sizeof(struct qlcnic_flash_desc_table);
+       count = fdt_size/sizeof(u32);
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       memset(&adapter->ahw->flash_fdt, 0, fdt_size);
+       ret = qlcnic_83xx_lockless_flash_read_u32(adapter,
+                               QLCNIC_FDT_LOCATION,
+                               (u8 *)&adapter->ahw->flash_fdt,
+                               count);
+
+       qlcnic_83xx_unlock_flash(adapter);
+       return ret;
+}
+
+int
+qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
+                                       u32 sector_start_addr)
+{
+       u32 reversed_addr;
+       int ret = -EIO;
+
+       if (qlcnic_83xx_lock_flash(adapter) != 0)
+               return -EIO;
+
+       if (adapter->ahw->flash_fdt.flash_manuf == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_enable_flash_write_op(adapter);
+               if (ret) {
+                       qlcnic_83xx_unlock_flash(adapter);
+                       netdev_err(adapter->netdev,
+                               "%s failed at %d\n",
+                               __func__, __LINE__);
+                       return ret;
+               }
+       }
+
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               qlcnic_83xx_unlock_flash(adapter);
+               dev_err(&adapter->pdev->dev,
+                        " %s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       reversed_addr = (((sector_start_addr & 0xFF) << 16) |
+                       ((sector_start_addr & 0xFF0000) >> 16));
+
+       qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLC_83XX_FLASH_WRDATA, reversed_addr);
+
+       if (adapter->ahw->flash_fdt.flash_manuf == adapter->flash_mfg_id)
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                       (QLC_83XX_FLASH_FDT_ERASE_DEF_SIG |
+                       adapter->ahw->flash_fdt.erase_cmd));
+       else
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                               QLC_83XX_FLASH_OEM_ERASE_SIG);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                               QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               qlcnic_83xx_unlock_flash(adapter);
+               dev_err(&adapter->pdev->dev,
+                        " %s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       if (adapter->ahw->flash_fdt.flash_manuf == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_disable_flash_write_op(adapter);
+               if (ret) {
+                       qlcnic_83xx_unlock_flash(adapter);
+                       netdev_err(adapter->netdev,
+                                " %s: failed at %d\n", __func__, __LINE__);
+                       return ret;
+               }
+       }
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return 0;
+}
+
+/* Note: User should take appropriate locks */
+int
+qlcnic_83xx_flash_write_u32(struct qlcnic_adapter *adapter, u32 addr,
+                                       u32 *p_data)
+{
+       int ret = -EIO;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                                               0x00800000 | (addr >> 2));
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                               QLC_83XX_FLASH_LAST_ERASE_MS_VAL);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                        " %s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/* Use this API to write data in bulk mode. */
+/* Note: User should take appropriate locks */
+/* min size = 2 4 byte words, max size = 64 4 byte words */
+
+int
+qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
+                                       u32 *p_data, int u32_word_count)
+{
+       u32 temp;
+       int ret = -EIO, err;
+
+       if ((u32_word_count <  QLC_83XX_FLASH_BULK_WRITE_MIN) ||
+       (u32_word_count >  QLC_83XX_FLASH_BULK_WRITE_MAX)) {
+               dev_err(&adapter->pdev->dev,
+                        " %s: Invalid word count\n", __func__);
+               return -EIO;
+       }
+
+       temp = qlcnic_83xx_rd_reg_indirect(adapter,
+                               QLC_83XX_FLASH_SPI_CONTROL, &err);
+       if (err == -EIO)
+               return -EIO;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLC_83XX_FLASH_SPI_CONTROL,
+                               (temp | QLC_83XX_FLASH_SPI_CONTROL_VAL));
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                               QLC_83XX_FLASH_ADDR_TEMP_VAL);
+
+       /* First DWORD write */
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                               QLC_83XX_FLASH_FIRST_WRITE_MS_PATTERN);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               netdev_err(adapter->netdev,
+                        " %s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       u32_word_count--;
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                       QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL);
+
+       /* Second to N-1 DWORD writes */
+       while (u32_word_count != 1) {
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_WRDATA, *p_data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_CONTROL,
+                                       QLC_83XX_FLASH_SECOND_WRITE_MS_PATTERN);
+               ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+               if (ret) {
+                       dev_err(&adapter->pdev->dev,
+                                " %s: failed at %d\n", __func__, __LINE__);
+                       return -EIO;
+               }
+               u32_word_count--;
+       }
+
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
+                               QLC_83XX_FLASH_ADDR_TEMP_VAL | (addr >> 2));
+       /* Last DWORD write */
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, *p_data++);
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_CONTROL,
+                               QLC_83XX_FLASH_LAST_WRITE_MS_PATTERN);
+       ret = qlcnic_83xx_poll_flash_status_reg(adapter);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                        " %s: failed at %d\n", __func__, __LINE__);
+               return -EIO;
+       }
+
+       ret = qlcnic_83xx_rd_reg_indirect(adapter,
+                               QLC_83XX_FLASH_SPI_STATUS, &err);
+       if (err == -EIO)
+               return -EIO;
+
+       if ((ret & QLC_83XX_FLASH_SPI_CONTROL_VAL) ==
+       QLC_83XX_FLASH_SPI_CONTROL_VAL) {
+               dev_err(&adapter->pdev->dev,
+                        " %s: failed at %d\n", __func__, __LINE__);
+               /* Operation failed, clear error bit */
+               temp = qlcnic_83xx_rd_reg_indirect(adapter,
+                                       QLC_83XX_FLASH_SPI_CONTROL, &err);
+               if (err == -EIO)
+                       return -EIO;
+
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLC_83XX_FLASH_SPI_CONTROL,
+                               (temp | QLC_83XX_FLASH_SPI_CONTROL_VAL));
+       }
+
+       return 0;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               u8 ring, u64 sts_data[])
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length, cksum;
+       u16 vid = 0xffff;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_83xx_hndl(sts_data[0]);
+       if (unlikely(index >= rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       length = qlcnic_83xx_pktln(sts_data[0]);
+       cksum  = qlcnic_83xx_csum_status(sts_data[1]);
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+       if (!skb)
+               return buffer;
+
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
+
+       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+               adapter->stats.rxdropped++;
+               dev_kfree_skb(skb);
+               return buffer;
+       }
+
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       if ((vid != 0xffff) && netdev->vlgrp)
+               vlan_gro_receive(&sds_ring->napi, netdev->vlgrp, vid, skb);
+       else
+               napi_gro_receive(&sds_ring->napi, skb);
+
+       adapter->stats.rx_pkts++;
+       adapter->stats.rxbytes += length;
+
+       return buffer;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               u8 ring, u64 sts_data[])
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct iphdr *iph;
+       struct ipv6hdr *ipv6h;
+       struct tcphdr *th;
+       bool push;
+       int l2_hdr_offset, l4_hdr_offset;
+       int index;
+       u16 lro_length, length, data_offset;
+       u16 vid = 0xffff;
+
+       if (unlikely(ring > adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_83xx_hndl(sts_data[0]);
+       if (unlikely(index > rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       lro_length = qlcnic_83xx_lro_pktln(sts_data[0]);
+       l2_hdr_offset = qlcnic_83xx_l2_hdr_off(sts_data[1]);
+       l4_hdr_offset = qlcnic_83xx_l4_hdr_off(sts_data[1]);
+       push = qlcnic_83xx_is_psh_bit(sts_data[1]);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+       if (!skb)
+               return buffer;
+       if (qlcnic_83xx_is_tstamp(sts_data[1]))
+               data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
+       else
+               data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
+
+       skb_put(skb, lro_length + data_offset);
+
+       skb_pull(skb, l2_hdr_offset);
+
+       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+               adapter->stats.rxdropped++;
+               dev_kfree_skb(skb);
+               return buffer;
+       }
+
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       if (htons(skb->protocol) == ETH_P_IPV6) {
+               ipv6h = (struct ipv6hdr *)skb->data;
+               th = (struct tcphdr *)(skb->data + sizeof(struct ipv6hdr));
+
+               length = (th->doff << 2) + lro_length;
+               ipv6h->payload_len = htons(length);
+       } else {
+               iph = (struct iphdr *)skb->data;
+               th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+
+               length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+               iph->tot_len = htons(length);
+               iph->check = 0;
+               iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+       }
+
+
+       th->psh = push;
+
+       length = skb->len;
+
+       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+               skb_shinfo(skb)->gso_size =
+                       qlcnic_83xx_get_lro_sts_mss(sts_data[0]);
+
+       if ((vid != 0xffff) && netdev->vlgrp)
+               vlan_hwaccel_receive_skb(skb, netdev->vlgrp, vid);
+       else
+               netif_receive_skb(skb);
+
+       adapter->stats.lro_pkts++;
+       adapter->stats.lrobytes += length;
+       return buffer;
+}
+
+static int
+qlcnic_83xx_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct list_head *cur;
+       struct status_desc *desc;
+       struct qlcnic_rx_buffer *rxbuf = NULL;
+       u64 sts_data[2];
+
+       int count = 0, opcode;
+       u8 ring;
+       u32 consumer = sds_ring->consumer;
+
+       while (count < max) {
+               desc = &sds_ring->desc_head[consumer];
+               sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+               opcode = qlcnic_83xx_opcode(sts_data[1]);
+               if (!opcode)
+                       break;
+               sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+               ring = QLCNIC_FETCH_RING_ID(sts_data[0]);
+
+               switch (opcode) {
+               case QLCNIC_83XX_REG_DESC:
+                       rxbuf = qlcnic_83xx_process_rcv(adapter, sds_ring,
+                                       ring, sts_data);
+                       break;
+               case QLCNIC_83XX_LRO_DESC:
+                       rxbuf = qlcnic_83xx_process_lro(adapter, sds_ring,
+                                       ring, sts_data);
+                       break;
+               default:
+                       dev_info(&adapter->pdev->dev,
+                               "Unkonwn opcode: 0x%x\n", opcode);
+                       goto skip;
+               }
+
+               if (likely(rxbuf))
+                       list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+               else
+                       adapter->stats.null_rxbuf++;
+
+skip:
+               desc = &sds_ring->desc_head[consumer];
+               /* Reset the descriptor */
+               desc->status_desc_data[1] = 0;
+               consumer = get_next_index(consumer, sds_ring->num_desc);
+               count++;
+       }
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               struct qlcnic_host_rds_ring *rds_ring =
+                       &adapter->recv_ctx->rds_rings[ring];
+
+               if (!list_empty(&sds_ring->free_list[ring])) {
+                       list_for_each(cur, &sds_ring->free_list[ring]) {
+                               rxbuf = list_entry(cur,
+                                               struct qlcnic_rx_buffer, list);
+                               qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+                       }
+                       spin_lock(&rds_ring->lock);
+                       list_splice_tail_init(&sds_ring->free_list[ring],
+                                               &rds_ring->free_list);
+                       spin_unlock(&rds_ring->lock);
+               }
+
+               qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
+       }
+
+       if (count) {
+               sds_ring->consumer = consumer;
+               writel(consumer, sds_ring->crb_sts_consumer);
+       }
+       return count;
+}
+
+void qlcnic_83xx_idc_aen_work(struct work_struct *work)
+{
+       struct qlcnic_adapter *adapter;
+       struct qlcnic_cmd_args cmd;
+       int i, err = 0;
+
+       adapter = container_of(work, struct qlcnic_adapter, idc_aen_work.work);
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_IDC_ACK);
+       for (i = 1; i < QLC_83XX_MBX_AEN_CNT; i++)
+               cmd.req.arg[i] = adapter->ahw->mbox_aen[i];
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
+               netdev_info(adapter->netdev,
+                           "%s: Mailbox IDC ACK failed.\n", __func__);
+       qlcnic_free_mbx_args(&cmd);
+}
+
+static void
+qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter, u32 data[])
+{
+       dev_dbg(&adapter->pdev->dev, "Completion AEN:0x%x.\n",
+                       QLCNIC_MBX_RSP(data[0]));
+       clear_bit(QLC_83XX_IDC_COMP_AEN, &adapter->ahw->idc.status);
+       return;
+}
+
+void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       u32 event[QLC_83XX_MBX_AEN_CNT];
+       int i;
+
+       for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+               event[i] = le32_to_cpu(readl(QLCNIC_MBX_FW(ahw, i)));
+       switch (QLCNIC_MBX_RSP(event[0])) {
+
+       /* This case is only active when we arrive here
+        * as a result of issuing a mailbox command to
+        * the firmware.
+        */
+       case QLCNIC_MBX_LINK_EVENT:
+               /* Link Event */
+               qlcnic_83xx_handle_link_aen(adapter, event);
+               break;
+       case QLCNIC_MBX_COMP_EVENT:
+               /* IDC Completion Notification */
+               qlcnic_83xx_handle_idc_comp_aen(adapter, event);
+               break;
+       case QLCNIC_MBX_REQUEST_EVENT:
+               /* IDC Request Notification */
+               for (i = 0; i < QLC_83XX_MBX_AEN_CNT; i++)
+                       adapter->ahw->mbox_aen[i] = QLCNIC_MBX_RSP(event[i]);
+               queue_delayed_work(adapter->qlcnic_wq,
+                                               &adapter->idc_aen_work, 0);
+               break;
+       case QLCNIC_MBX_TIME_EXTEND_EVENT:
+               /* IDC Time Extend Notification */
+               break;
+       case QLCNIC_MBX_SFP_INSERT_EVENT:
+               /* IDC SFP+ Transceiver Insertion Notification */
+               dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",
+                               QLCNIC_MBX_RSP(event[0]));
+               break;
+       case QLCNIC_MBX_SFP_REMOVE_EVENT:
+               /* IDC SFP+ Transceiver Removal Notification */
+               dev_info(&adapter->pdev->dev, "SFP Removed AEN:0x%x.\n",
+                               QLCNIC_MBX_RSP(event[0]));
+               break;
+       default:
+               dev_dbg(&adapter->pdev->dev, "Unsupported AEN:0x%x.\n",
+                               QLCNIC_MBX_RSP(event[0]));
+               break;
+       }
+       QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+}
+
+static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
+{
+       unsigned long flags;
+       u32 mask, resp, event;
+
+       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+       resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+       if (!(resp & QLCNIC_SET_OWNER))
+               goto out;
+       event = le32_to_cpu(readl(QLCNIC_MBX_FW(adapter->ahw, 0)));
+       if (event &  QLCNIC_MBX_ASYNC_EVENT)
+               qlcnic_83xx_process_aen(adapter);
+out:
+       mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+       writel(0, adapter->ahw->pci_base0 + mask);
+       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+}
+
+static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
+{
+       struct qlcnic_host_sds_ring *sds_ring =
+               container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       /* there is only 1 tx ring in this path */
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+       int tx_complete, work_done;
+
+       if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+               qlcnic_83xx_poll_process_aen(adapter);
+
+       tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+
+       work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+
+       if ((work_done < budget) && tx_complete) {
+               napi_complete(&sds_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+                       qlcnic_83xx_enable_intr(adapter, sds_ring);
+       }
+
+       return work_done;
+}
+
+static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget)
+{
+       struct qlcnic_host_tx_ring *tx_ring =
+               container_of(napi, struct qlcnic_host_tx_ring, napi);
+
+       struct qlcnic_adapter *adapter = tx_ring->adapter;
+       int work_done;
+
+       work_done = qlcnic_process_cmd_ring(adapter, tx_ring,
+                                QLCNIC_TX_POLL_BUDGET);
+
+       if (work_done) {
+               napi_complete(&tx_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP , &adapter->state))
+                       qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+       }
+
+       return work_done;
+}
+
+static int qlcnic_83xx_rx_poll(struct napi_struct *napi, int budget)
+{
+       struct qlcnic_host_sds_ring *sds_ring =
+               container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       int work_done;
+
+       work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+
+       if (work_done < budget) {
+               napi_complete(&sds_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+                       qlcnic_83xx_enable_intr(adapter, sds_ring);
+       }
+
+       return work_done;
+}
+
+void
+qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_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);
+               qlcnic_83xx_enable_intr(adapter, sds_ring);
+       }
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       napi_enable(&tx_ring->napi);
+                       qlcnic_83xx_enable_tx_intr(adapter, tx_ring);
+               }
+       }
+}
+
+void
+qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       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];
+               writel(1, sds_ring->crb_intr_mask);
+               napi_synchronize(&sds_ring->napi);
+               napi_disable(&sds_ring->napi);
+       }
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       qlcnic_83xx_disable_tx_intr(adapter, tx_ring);
+                       napi_synchronize(&tx_ring->napi);
+                       napi_disable(&tx_ring->napi);
+               }
+       }
+}
+
+int
+qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+       if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
+               return -ENOMEM;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       netif_napi_add(netdev, &sds_ring->napi,
+                           qlcnic_83xx_rx_poll, QLCNIC_NETDEV_WEIGHT * 2);
+               else
+                       netif_napi_add(netdev, &sds_ring->napi,
+                           qlcnic_83xx_poll,
+                               QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
+       }
+
+       if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+               qlcnic_free_sds_rings(recv_ctx);
+               return -ENOMEM;
+       }
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       netif_napi_add(netdev, &tx_ring->napi,
+                               qlcnic_83xx_msix_tx_poll,
+                               QLCNIC_NETDEV_WEIGHT);
+               }
+       }
+
+       return 0;
+}
+
+void
+qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               netif_napi_del(&sds_ring->napi);
+       }
+
+       qlcnic_free_sds_rings(adapter->recv_ctx);
+
+       if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       netif_napi_del(&tx_ring->napi);
+               }
+       }
+
+       qlcnic_free_tx_rings(adapter);
+}
+
+void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               int ring, u64 sts_data[])
+{
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length, cksum;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+       index = qlcnic_83xx_hndl(sts_data[0]);
+       if (unlikely(index >= rds_ring->num_desc))
+               return;
+
+       length = qlcnic_83xx_pktln(sts_data[0]);
+       cksum  = qlcnic_83xx_csum_status(sts_data[0]);
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+       if (!skb)
+               return;
+
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
+
+       if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
+               adapter->ahw->diag_cnt++;
+       else
+               dump_skb(skb, adapter);
+
+       dev_kfree_skb_any(skb);
+       return;
+}
+
+void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct status_desc *desc;
+       u64 sts_data[2];
+       int ring, opcode;
+
+       u32 consumer = sds_ring->consumer;
+
+       desc = &sds_ring->desc_head[consumer];
+       sts_data[0] = le64_to_cpu(desc->status_desc_data[0]);
+       sts_data[1] = le64_to_cpu(desc->status_desc_data[1]);
+       opcode = qlcnic_83xx_opcode(sts_data[1]);
+       if (!opcode)
+               return;
+
+       ring = QLCNIC_FETCH_RING_ID(qlcnic_83xx_hndl(sts_data[0]));
+       qlcnic_83xx_process_rcv_diag(adapter, sds_ring, ring, sts_data);
+
+       desc = &sds_ring->desc_head[consumer];
+       desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+       consumer = get_next_index(consumer, sds_ring->num_desc);
+
+       sds_ring->consumer = consumer;
+       writel(consumer, sds_ring->crb_sts_consumer);
+}
+
+/* Configure interrupts command registers interrupt vectors with the FW
+ * @op_type: 1 for creation and 0 for deletion
+ * @type: Interrupt type, INTx or MSI-X
+ * */
+int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)
+
+{
+       int i, index, err;
+       u8 max_ints;
+       u32 val;
+       struct qlcnic_cmd_args cmd;
+
+       max_ints = adapter->ahw->num_msix;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CONFIG_INTRPT);
+       cmd.req.arg[1] = cpu_to_le32(max_ints);
+       for(i = 0, index = 2; i < max_ints; i++) {
+               val = (op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL) |
+                       (adapter->ahw->intr_tbl[i].type << 4);
+               if (adapter->ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
+                       val |= (adapter->ahw->intr_tbl[i].id << 16);
+               cmd.req.arg[index++] = cpu_to_le32(val);
+       }
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to configure interrupts 0x%x\n", err);
+               goto out;
+       }
+
+       max_ints = le32_to_cpu(cmd.rsp.arg[1]);
+       for (i = 0, index = 2; i < max_ints; i++, index += 2) {
+
+               val = le32_to_cpu(cmd.rsp.arg[index]);
+               if (LSB(val)) {
+                       dev_info(&adapter->pdev->dev,
+                               "Can't configure interrupt %d\n",
+                               adapter->ahw->intr_tbl[i].id);
+                       continue;
+               }
+               if (op_type) {
+                       adapter->ahw->intr_tbl[i].id = MSW(val);
+                       adapter->ahw->intr_tbl[i].enabled = 1;
+                       adapter->ahw->intr_tbl[i].src =
+                               le32_to_cpu(cmd.rsp.arg[index + 1]);
+               } else {
+                       adapter->ahw->intr_tbl[i].id = i;
+                       adapter->ahw->intr_tbl[i].enabled = 0;
+                       adapter->ahw->intr_tbl[i].src = 0;
+               }
+       }
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)
+{
+       int index, i, err, sds_mbx_size;
+       u32 *buf, intrpt_id, intr_mask;
+       u16 context_id;
+       u8 num_sds;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_host_sds_ring *sds;
+       struct qlcnic_sds_mbx sds_mbx;
+       struct qlcnic_add_rings_mbx_out *mbx_out;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+       context_id = recv_ctx->context_id;
+
+       num_sds = (adapter->max_sds_rings - QLCNIC_MAX_RING_SETS);
+
+       ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                   QLCNIC_CMD_ADD_RCV_RINGS);
+
+       cmd.req.arg[1] = cpu_to_le32(0 | (num_sds << 8) | (context_id << 16));
+
+       /* set up status rings, mbx 2-81 */
+       index = 2;
+
+       for (i = 8; i < adapter->max_sds_rings; i++) {
+               memset(&sds_mbx, 0, sds_mbx_size);
+               sds = &recv_ctx->sds_rings[i];
+               sds->consumer = 0;
+               memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+               sds_mbx.phy_addr = cpu_to_le64(sds->phys_addr);
+               sds_mbx.sds_ring_size = cpu_to_le16(sds->num_desc);
+
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intrpt_id = ahw->intr_tbl[i].id;
+               else
+                       intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+
+               if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+                       sds_mbx.intrpt_id = cpu_to_le32(intrpt_id);
+               else
+                       sds_mbx.intrpt_id = 0xffff;
+               sds_mbx.intrpt_val = 0;
+               buf = &cmd.req.arg[index];
+               memcpy(buf, &sds_mbx, sds_mbx_size);
+               index += sds_mbx_size/sizeof(u32);
+       }
+
+       /* send the mailbox command */
+       err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to add rings %d\n", err);
+               goto out;
+       }
+       mbx_out = (struct qlcnic_add_rings_mbx_out *) &cmd.rsp.arg[1];
+
+       index = 0;
+       /* status descriptor ring */
+       for (i = 8; i < adapter->max_sds_rings; i++) {
+               sds = &recv_ctx->sds_rings[i];
+               sds->crb_sts_consumer = ahw->pci_base0 +
+                       le32_to_cpu(mbx_out->host_csmr[index]);
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intr_mask = ahw->intr_tbl[i].src;
+               else
+                       intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+               sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+               index++;
+       }
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
+{
+       int i, err, index, sds_mbx_size, rds_mbx_size;
+       u8 num_sds, num_rds;
+       u32 *buf, intrpt_id, intr_mask, cap = 0;
+       struct qlcnic_host_sds_ring *sds;
+       struct qlcnic_host_rds_ring *rds;
+       struct qlcnic_sds_mbx sds_mbx;
+       struct qlcnic_rds_mbx rds_mbx;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_rcv_mbx_out *mbx_out;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       num_rds = adapter->max_rds_rings;
+
+       if (adapter->max_sds_rings <= QLCNIC_MAX_RING_SETS)
+               num_sds = adapter->max_sds_rings;
+       else
+               num_sds = QLCNIC_MAX_RING_SETS;
+
+       sds_mbx_size = sizeof(struct qlcnic_sds_mbx);
+       rds_mbx_size = sizeof(struct qlcnic_rds_mbx);
+       cap = QLCNIC_CAP0_LEGACY_CONTEXT;
+
+       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+               cap |= QLCNIC_FW_83XX_CAP_LRO_MSS;
+
+       /* set mailbox hdr and capabilities */
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CREATE_RX_CTX);
+       cmd.req.arg[1] = cpu_to_le32(cap);
+       cmd.req.arg[5] = cpu_to_le32(1 | (num_rds << 5) | (num_sds << 8) |
+                               (QLCNIC_HOST_83XX_RDS_MODE_UNIQUE << 16));
+       /* set up status rings, mbx 8-57/87 */
+       index = QLCNIC_HOST_SDS_MBX_IDX;
+       for (i = 0; i < num_sds; i++) {
+               memset(&sds_mbx, 0, sds_mbx_size);
+               sds = &recv_ctx->sds_rings[i];
+               sds->consumer = 0;
+               memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
+               sds_mbx.phy_addr = cpu_to_le64(sds->phys_addr);
+               sds_mbx.sds_ring_size = cpu_to_le16(sds->num_desc);
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intrpt_id = ahw->intr_tbl[i].id;
+               else
+                       intrpt_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+               if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+                       sds_mbx.intrpt_id = cpu_to_le32(intrpt_id);
+               else
+                       sds_mbx.intrpt_id = 0xffff;
+               sds_mbx.intrpt_val = 0;
+               buf = &cmd.req.arg[index];
+               memcpy(buf, &sds_mbx, sds_mbx_size);
+               index += sds_mbx_size/sizeof(u32);
+       }
+       /* set up receive rings, mbx 88-111/135 */
+       index = QLCNIC_HOST_RDS_MBX_IDX;
+       rds = &recv_ctx->rds_rings[0];
+       rds->producer = 0;
+       memset(&rds_mbx, 0, rds_mbx_size);
+       rds_mbx.phy_addr_reg = cpu_to_le64(rds->phys_addr);
+       rds_mbx.reg_ring_sz = cpu_to_le16(rds->dma_size);
+       rds_mbx.reg_ring_len = cpu_to_le16(rds->num_desc);
+       /* Jumbo ring */
+       rds = &recv_ctx->rds_rings[1];
+       rds->producer = 0;
+       rds_mbx.phy_addr_jmb = cpu_to_le64(rds->phys_addr);
+       rds_mbx.jmb_ring_sz = cpu_to_le16(rds->dma_size);
+       rds_mbx.jmb_ring_len = cpu_to_le16(rds->num_desc);
+       buf = &cmd.req.arg[index];
+       memcpy(buf, &rds_mbx, rds_mbx_size);
+
+       /* send the mailbox command */
+       err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to create Rx ctx in firmware%d\n", err);
+               goto out;
+       }
+       mbx_out = (struct qlcnic_rcv_mbx_out *) &cmd.rsp.arg[1];
+       recv_ctx->context_id = le16_to_cpu(mbx_out->ctx_id);
+       recv_ctx->state = le32_to_cpu(mbx_out->state);
+       recv_ctx->virt_port = le16_to_cpu(mbx_out->vport_id);
+       dev_info(&adapter->pdev->dev, "Rx Context[%d] Created, state:0x%x\n",
+               recv_ctx->context_id, recv_ctx->state);
+       /* Receive descriptor ring */
+       /* Standard ring */
+       rds = &recv_ctx->rds_rings[0];
+       rds->crb_rcv_producer = ahw->pci_base0 +
+                       le32_to_cpu(mbx_out->host_prod[0].reg_buf);
+       /* Jumbo ring */
+       rds = &recv_ctx->rds_rings[1];
+       rds->crb_rcv_producer = ahw->pci_base0 +
+                       le32_to_cpu(mbx_out->host_prod[0].jmb_buf);
+       /* status descriptor ring */
+       for (i = 0; i < num_sds; i++) {
+               sds = &recv_ctx->sds_rings[i];
+               sds->crb_sts_consumer = ahw->pci_base0 +
+                       le32_to_cpu(mbx_out->host_csmr[i]);
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       intr_mask = ahw->intr_tbl[i].src;
+               else
+                       intr_mask = QLCRDX(ahw, QLCNIC_DEF_INT_MASK);
+               sds->crb_intr_mask = ahw->pci_base0 + intr_mask;
+       }
+
+       if (adapter->max_sds_rings > QLCNIC_MAX_RING_SETS)
+               err = qlcnic_83xx_add_rings(adapter);
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_tx_ring *tx, int ring)
+{
+       int err;
+       u16 msix_id;
+       u32 *buf, intr_mask;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_tx_mbx mbx;
+       struct qlcnic_tx_mbx_out *mbx_out;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Reset host resources */
+       tx->producer = 0;
+       tx->sw_consumer = 0;
+       *(tx->hw_consumer) = 0;
+
+       memset(&mbx, 0, sizeof(struct qlcnic_tx_mbx));
+
+       /* setup mailbox inbox registerss */
+       mbx.phys_addr = cpu_to_le64(tx->phys_addr);
+       mbx.cnsmr_index = cpu_to_le64(tx->hw_cons_phys_addr);
+       mbx.size = cpu_to_le16(tx->num_desc);
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               msix_id = ahw->intr_tbl[adapter->max_sds_rings + ring].id;
+       else
+               msix_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+       if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
+               mbx.intr_id = cpu_to_le16(msix_id);
+       else
+               mbx.intr_id = 0xffff;
+       mbx.src = 0;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CREATE_TX_CTX);
+       cmd.req.arg[1] = cpu_to_le32(QLCNIC_CAP0_LEGACY_CONTEXT);
+       cmd.req.arg[5] = cpu_to_le32(QLCNIC_MAX_TX_QUEUES);
+       buf = &cmd.req.arg[6];
+       memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx));
+       /* send the mailbox command*/
+       err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to create Tx ctx in firmware 0x%x\n", err);
+               goto out;
+       }
+       mbx_out = (struct qlcnic_tx_mbx_out *) &cmd.rsp.arg[2];
+       tx->crb_cmd_producer = ahw->pci_base0 + le32_to_cpu(mbx_out->host_prod);
+       tx->ctx_id = le16_to_cpu(mbx_out->ctx_id);
+       if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+               intr_mask = ahw->intr_tbl[adapter->max_sds_rings + ring].src;
+               tx->crb_intr_mask = ahw->pci_base0 + intr_mask;
+       }
+       dev_info(&adapter->pdev->dev, "Tx Context[0x%x] Created, state:0x%x\n",
+               tx->ctx_id, mbx_out->state);
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_rds_ring *rds_ring;
+       u8 ring;
+       int ret;
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev))
+               __qlcnic_down(adapter, netdev);
+
+       qlcnic_detach(adapter);
+
+       adapter->max_sds_rings = 1;
+       adapter->ahw->diag_test = test;
+       adapter->ahw->linkup = 0;
+
+       ret = qlcnic_attach(adapter);
+       if (ret) {
+               netif_device_attach(netdev);
+               return ret;
+       }
+
+       ret = qlcnic_fw_create_ctx(adapter);
+       if (ret) {
+               qlcnic_detach(adapter);
+               netif_device_attach(netdev);
+               return ret;
+       }
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &adapter->recv_ctx->rds_rings[ring];
+               qlcnic_post_rx_buffers(adapter, rds_ring, ring);
+       }
+
+       if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &adapter->recv_ctx->sds_rings[ring];
+                       qlcnic_83xx_enable_intr(adapter, sds_ring);
+               }
+       }
+
+       if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+               /* disable and free mailbox interrupt */
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+               adapter->ahw->loopback_state = 0;
+               adapter->ahw->hw_ops->setup_link_event(adapter, 1);
+       }
+
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
+       return 0;
+}
+
+static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
+                                       int max_sds_rings)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_sds_ring *sds_ring;
+       int ring, err;
+
+       clear_bit(__QLCNIC_DEV_UP, &adapter->state);
+       if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &adapter->recv_ctx->sds_rings[ring];
+                       writel(1, sds_ring->crb_intr_mask);
+               }
+       }
+
+       qlcnic_fw_destroy_ctx(adapter);
+       qlcnic_detach(adapter);
+
+       if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err) {
+                       netdev_err(netdev,
+                               "%s: failed to setup mbx interrupt\n",
+                               __func__);
+                       goto out;
+               }
+       }
+       adapter->ahw->diag_test = 0;
+       adapter->max_sds_rings = max_sds_rings;
+
+       if (qlcnic_attach(adapter))
+               goto out;
+
+       if (netif_running(netdev))
+               __qlcnic_up(adapter, netdev);
+out:
+       netif_device_attach(netdev);
+}
+
+int qlcnic_83xx_interrupt_test(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_cmd_args cmd;
+       u32 data;
+       u16 intrpt_id, id;
+       u8 val;
+       int ret, max_sds_rings = adapter->max_sds_rings;
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EIO;
+
+       ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
+       if (ret)
+               goto fail_diag_irq;
+
+       ahw->diag_cnt = 0;
+       ahw->hw_ops->alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INTRPT_TEST);
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               intrpt_id = adapter->ahw->intr_tbl[0].id;
+       else
+               intrpt_id = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_ID);
+
+       cmd.req.arg[1] = cpu_to_le32(1);
+       cmd.req.arg[2] = cpu_to_le32(intrpt_id);
+       cmd.req.arg[3] = cpu_to_le32(BIT_0);
+
+       ret = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       data = le32_to_cpu(cmd.rsp.arg[2]);
+       id = LSW(data);
+       val = LSB(MSW(data));
+       if (id != intrpt_id)
+               netdev_info(adapter->netdev,
+                       "Interrupt generated: 0x%x, requested:0x%x\n",
+                       id, intrpt_id);
+       if (val) {
+               netdev_err(adapter->netdev,
+                          "Interrupt test error: 0x%x\n", val);
+       }
+       if (ret)
+               goto done;
+
+       msleep(10);
+       ret = !adapter->ahw->diag_cnt;
+
+done:
+       qlcnic_free_mbx_args(&cmd);
+       qlcnic_83xx_diag_free_res(netdev, max_sds_rings);
+
+fail_diag_irq:
+       adapter->max_sds_rings = max_sds_rings;
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       return ret;
+}
+
+int
+qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 beacon)
+{
+       struct qlcnic_cmd_args cmd;
+       u32 mbx_in;
+       int i, status;
+
+       if (state) {
+               /* Get LED configuration */
+               adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_GET_LED_CONFIG);
+               status = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+               if (status) {
+                       netdev_err(adapter->netdev,
+                                       "Get led config failed.\n");
+                       goto mbx_err;
+               } else {
+                       for (i = 0; i < 4; i++)
+                               adapter->ahw->mbox_reg[i] = cmd.rsp.arg[i+1];
+               }
+               qlcnic_free_mbx_args(&cmd);
+               /* Set LED Configuration */
+               mbx_in = (LSW(QLCNIC_83XX_LED_CONFIG) << 16) |
+                               LSW(QLCNIC_83XX_LED_CONFIG);
+               adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_SET_LED_CONFIG);
+               cmd.req.arg[1] = cpu_to_le32(mbx_in);
+               cmd.req.arg[2] = cpu_to_le32(mbx_in);
+               cmd.req.arg[3] = cpu_to_le32(mbx_in);
+               if (beacon)
+                       cmd.req.arg[4] = QLCNIC_83XX_ENABLE_BEACON;
+               status = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+               if (status) {
+                       netdev_err(adapter->netdev,
+                                       "Set led config failed.\n");
+               }
+mbx_err:
+               qlcnic_free_mbx_args(&cmd);
+               return status;
+       } else {
+               /* Restoring default LED configuration */
+               adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_SET_LED_CONFIG);
+               cmd.req.arg[1] = adapter->ahw->mbox_reg[0];
+               cmd.req.arg[2] = adapter->ahw->mbox_reg[1];
+               cmd.req.arg[3] = adapter->ahw->mbox_reg[2];
+               if (beacon)
+                       cmd.req.arg[4] = adapter->ahw->mbox_reg[3];
+               status = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+               if (status)
+                       netdev_err(adapter->netdev,
+                                       "Restoring led config failed.\n");
+               qlcnic_free_mbx_args(&cmd);
+               return status;
+       }
+}
+
+void
+qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter, int enable)
+{
+       struct qlcnic_cmd_args cmd;
+       int status;
+
+       if (enable) {
+               adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_INIT_NIC_FUNC);
+               cmd.req.arg[1] = cpu_to_le32(1 | BIT_0 | BIT_31);
+       } else {
+               adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_STOP_NIC_FUNC);
+               cmd.req.arg[1] = cpu_to_le32(0 | BIT_0 | BIT_31);
+       }
+       status = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (status) {
+               netdev_err(adapter->netdev,
+                       "Failed to %s in NIC IDC function event.\n",
+                       (enable ? "register" : "unregistered"));
+       }
+       qlcnic_free_mbx_args(&cmd);
+}
+
+static int qlcnic_83xx_set_port_config(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_args cmd;
+       int err;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_SET_PORT_CONFIG);
+       cmd.req.arg[1] = cpu_to_le32(adapter->ahw->port_config);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
+               netdev_err(adapter->netdev, "Set Port Config failed.\n");
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+static int qlcnic_83xx_get_port_config(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_args cmd;
+       int err;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_PORT_CONFIG);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
+               netdev_err(adapter->netdev, "Get Port config failed\n");
+       else
+               adapter->ahw->port_config = le32_to_cpu(cmd.rsp.arg[1]);
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable)
+{
+       int err;
+       struct qlcnic_cmd_args cmd;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_LINK_EVENT);
+       cmd.req.arg[1] = cpu_to_le32((enable ? 1 : 0) | BIT_8 |
+               ((adapter->recv_ctx->context_id) << 16));
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev,
+                       "Setup linkevent mailbox failed\n");
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
+{
+       int err;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return -EIO;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
+       cmd.req.arg[1] = cpu_to_le32((mode ? 1 : 0) |
+               (adapter->recv_ctx->context_id) << 16);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev,
+                       "Promiscous mode config failed\n");
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings;
+
+       QLCDB(adapter, DRV, "%s loopback test in progress\n",
+               mode == QLCNIC_ILB_MODE ? "internal" : "external");
+       if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               netdev_warn(netdev, "Loopback test not supported for non "
+                           "privilege function\n");
+               return ret;
+       }
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EBUSY;
+
+       ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+       if (ret)
+               goto fail_diag_alloc;
+
+       ret = qlcnic_83xx_set_lb_mode(adapter, mode);
+       if (ret)
+               goto free_diag_res;
+
+       /* Poll for link up event before running traffic */
+       do {
+               msleep(500);
+               qlcnic_83xx_process_aen(adapter);
+               if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+                       netdev_info(netdev, "Firmware didn't sent link up "
+                                   "event to loopback request\n");
+                       ret = -QLCNIC_FW_NOT_RESPOND;
+                       qlcnic_83xx_clear_lb_mode(adapter, mode);
+                       goto free_diag_res;
+               }
+       } while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
+
+       ret = qlcnic_do_lb_test(adapter, mode);
+
+       qlcnic_83xx_clear_lb_mode(adapter, mode);
+
+free_diag_res:
+       qlcnic_83xx_diag_free_res(netdev, max_sds_rings);
+
+fail_diag_alloc:
+       adapter->max_sds_rings = max_sds_rings;
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       return ret;
+}
+
+int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0, loop = 0;
+       u32 config;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status)
+               return status;
+
+       config = ahw->port_config;
+       set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+
+       if (mode == QLCNIC_ILB_MODE)
+               ahw->port_config |= QLC_83XX_CFG_LOOPBACK_HSS;
+       if (mode == QLCNIC_ELB_MODE)
+               ahw->port_config |= QLC_83XX_CFG_LOOPBACK_EXT;
+
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               netdev_err(adapter->netdev,
+                       "Failed to Set Loopback Mode = 0x%x.\n",
+                       ahw->port_config);
+               ahw->port_config = config;
+               clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+               return status;
+       }
+
+       /* Poll for Link and IDC Completion AEN */
+       do {
+               msleep(300);
+               qlcnic_83xx_process_aen(adapter);
+               if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+                       netdev_err(adapter->netdev,
+                               "Firmware didn't sent IDC completion AEN\n");
+                       clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+                       qlcnic_83xx_clear_lb_mode(adapter, mode);
+                       return -EIO;
+               }
+       } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+       qlcnic_83xx_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+                                       QLCNIC_MAC_ADD);
+       return status;
+}
+
+int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0, loop = 0;
+       u32 config = ahw->port_config;
+
+       set_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+       if (mode == QLCNIC_ILB_MODE)
+               ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_HSS;
+       if (mode == QLCNIC_ELB_MODE)
+               ahw->port_config &= ~QLC_83XX_CFG_LOOPBACK_EXT;
+
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               netdev_err(adapter->netdev,
+                       "Failed to Clear Loopback Mode = 0x%x.\n",
+                       ahw->port_config);
+               ahw->port_config = config;
+               clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+               return status;
+       }
+
+       /* Poll for Link and IDC Completion AEN */
+       do {
+               msleep(300);
+               qlcnic_83xx_process_aen(adapter);
+               if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
+                       netdev_err(adapter->netdev,
+                               "Firmware didn't sent IDC completion AEN\n");
+                       clear_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status);
+                       return -EIO;
+               }
+       } while (test_bit(QLC_83XX_IDC_COMP_AEN, &ahw->idc.status));
+
+       qlcnic_83xx_sre_macaddr_change(adapter, adapter->mac_addr, 0,
+                                       QLCNIC_MAC_DEL);
+       return status;
+}
+
+void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter,
+                                __be32 ip, int mode)
+{
+       int err;
+       struct qlcnic_cmd_args cmd;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CONFIGURE_IP_ADDR);
+       if (mode == QLCNIC_IP_UP)
+               cmd.req.arg[1] = cpu_to_le32(1 |
+                               adapter->recv_ctx->context_id << 16);
+       else
+               cmd.req.arg[1] = cpu_to_le32(2 |
+                               adapter->recv_ctx->context_id << 16);
+       cmd.req.arg[2] = cpu_to_le32(ip);
+
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err != QLCNIC_RCODE_SUCCESS)
+               dev_err(&adapter->netdev->dev,
+                               "could not notify %s IP 0x%x request\n",
+                               (mode == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
+       qlcnic_free_mbx_args(&cmd);
+}
+
+int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *adapter, int mode)
+{
+       int err;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return 0;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CONFIGURE_HW_LRO);
+       cmd.req.arg[1] = cpu_to_le32((mode ? (BIT_0 | BIT_1 | BIT_3) : 0) |
+                       ((adapter->recv_ctx->context_id) << 16));
+
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
+               dev_info(&adapter->pdev->dev,
+                       "LRO config failed\n");
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable)
+{
+       int err;
+       u32 word;
+       struct qlcnic_cmd_args cmd;
+
+
+       const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+                       0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+                       0x255b0ec26d5a56daULL };
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_CONFIGURE_RSS);
+
+       /*
+        * RSS request:
+        * bits 3-0: Rsvd
+        *      5-4: hash_type_ipv4
+        *      7-6: hash_type_ipv6
+        *        8: enable
+        *        9: use indirection table
+        *    16-31: indirection table mask
+        */
+       word =  ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+               ((u32)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+               ((u32)(enable & 0x1) << 8) |
+               ((0x7ULL) << 16);
+       cmd.req.arg[1] = (adapter->recv_ctx->context_id);
+       cmd.req.arg[2] = cpu_to_le32(word);
+       memcpy(&cmd.req.arg[4], key, sizeof(key));
+
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+       if (err)
+               dev_info(&adapter->pdev->dev,
+                       "RSS config failed\n");
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+
+}
+
+int
+qlcnic_83xx_get_regs_len(struct qlcnic_adapter *adapter)
+{
+       return (ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl) *
+               sizeof(adapter->ahw->ext_reg_tbl)) +
+               (ARRAY_SIZE(qlcnic_83xx_reg_tbl) +
+               sizeof(adapter->ahw->reg_tbl));
+}
+
+int
+qlcnic_83xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)
+{
+       int i, j = 0;
+
+       for (i = QLCNIC_DEV_INFO_SIZE + 1; j < ARRAY_SIZE(qlcnic_83xx_reg_tbl); i++,j++)
+               regs_buff[i] = QLCRD(adapter, j);
+
+       for (j = 0; j < ARRAY_SIZE(qlcnic_83xx_ext_reg_tbl); j++)
+               regs_buff[i++] = QLCRDX(adapter->ahw, j);
+       return i;
+}
+
+int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
+{
+       int status;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status) {
+               dev_info(&adapter->pdev->dev,
+                       "Get Port Info failed\n");
+       } else {
+               if (QLC_83XX_SFP_10G_CAPABLE(adapter->ahw->port_config))
+                       adapter->ahw->port_type = QLCNIC_XGBE;
+               else
+                       adapter->ahw->port_type = QLCNIC_GBE;
+               if (QLC_83XX_AUTONEG(adapter->ahw->port_config))
+                       adapter->ahw->link_autoneg = AUTONEG_ENABLE;
+       }
+       return status;
+}
+
+int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
+{
+       int err;
+       u32 config = 0, state;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(ahw->pci_func));
+       if (!QLC_83xx_FUNC_VAL(state, ahw->pci_func)){
+               dev_info(&adapter->pdev->dev, "link state down\n");
+               return config;
+       }
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_LINK_STATUS);
+       err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                       "Get Link Status Command failed: 0x%x\n", err);
+               goto out;
+       } else {
+               config = le32_to_cpu(cmd.rsp.arg[1]);
+               switch(QLC_83XX_CURRENT_LINK_SPEED(config)) {
+               case QLC_83XX_10M_LINK:
+                       ahw->link_speed = SPEED_10;
+                       break;
+               case QLC_83XX_100M_LINK:
+                       ahw->link_speed = SPEED_100;
+                       break;
+               case QLC_83XX_1G_LINK:
+                       ahw->link_speed = SPEED_1000;
+                       break;
+               case QLC_83XX_10G_LINK:
+                       ahw->link_speed = SPEED_10000;
+                       break;
+               default:
+                       ahw->link_speed = 0;
+                       break;
+               }
+               config = le32_to_cpu(cmd.rsp.arg[3]);
+               if (config & 1)
+                       err = 1;
+       }
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return config;
+}
+
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter)
+{
+       u32 config = 0;
+       int status = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Get port configuration info */
+       status = qlcnic_83xx_get_port_info(adapter);
+       /* Get Link Status related info */
+       config = qlcnic_83xx_test_link(adapter);
+       ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
+       /* hard code until there is a way to get it from flash/fw */
+       ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;
+       return status;
+}
+
+int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
+       struct ethtool_cmd *ecmd)
+{
+       int status = 0;
+       u32 config = adapter->ahw->port_config;
+
+       if (ecmd->autoneg)
+               adapter->ahw->port_config |= BIT_15;
+
+       switch(ethtool_cmd_speed(ecmd)) {
+       case SPEED_10:
+               adapter->ahw->port_config |= BIT_8;
+               break;
+       case SPEED_100:
+               adapter->ahw->port_config |= BIT_9;
+               break;
+       case SPEED_1000:
+               adapter->ahw->port_config |= BIT_10;
+               break;
+       case SPEED_10000:
+               adapter->ahw->port_config |= BIT_11;
+               break;
+       default:
+               return -EIO;
+       }
+
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               dev_info(&adapter->pdev->dev,
+                               "Faild to Set Link Speed and autoneg.\n");
+               adapter->ahw->port_config = config;
+       }
+       return status;
+}
+
+int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter)
+{
+       u32 major, minor, sub;
+
+       major = QLCRD(adapter, QLCNIC_FW_VERSION_MAJOR);
+       minor = QLCRD(adapter, QLCNIC_FW_VERSION_MINOR);
+       sub = QLCRD(adapter, QLCNIC_FW_VERSION_SUB);
+
+       if (adapter->fw_version != QLCNIC_VERSION_CODE(major, minor, sub)) {
+               dev_info(&adapter->pdev->dev, "%s: Reg test failed.\n",
+                        __func__);
+               return 1;
+       }
+       return 0;
+}
+
+int qlcnic_83xx_eeprom_test(struct qlcnic_adapter *adapter)
+{
+       int status;
+
+       status = qlcnic_83xx_read_flash_status_reg(adapter);
+       if (status == -EIO) {
+               dev_info(&adapter->pdev->dev, "%s: EEPROM test failed.\n",
+                       __func__);
+               return 1;
+       }
+       return 0;
+}
+
+void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *adapter,
+                       struct ethtool_pauseparam *pause)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0;
+       u32 config;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status) {
+               netdev_err(adapter->netdev,
+                       "%s: Get Pause Config failed.\n", __func__);
+               return;
+       }
+       config = ahw->port_config;
+       if (config & QLC_83XX_CFG_STD_PAUSE) {
+               if (config & QLC_83XX_CFG_STD_TX_PAUSE)
+                       pause->tx_pause = 1;
+               if (config & QLC_83XX_CFG_STD_RX_PAUSE)
+                       pause->rx_pause = 1;
+       }
+       if (QLC_83XX_AUTONEG(config))
+               pause->autoneg = 1;
+}
+
+int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
+                       struct ethtool_pauseparam *pause)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int status = 0;
+       u32 config;
+
+       status = qlcnic_83xx_get_port_config(adapter);
+       if (status) {
+               netdev_err(adapter->netdev,
+                       "%s: Get Pause Config failed.\n", __func__);
+               return status;
+       }
+       config = ahw->port_config;
+
+       if (ahw->port_type == QLCNIC_GBE) {
+               if (pause->autoneg)
+                       ahw->port_config |= QLC_83XX_ENABLE_AUTONEG;
+               if (!pause->autoneg)
+                       ahw->port_config &= ~QLC_83XX_ENABLE_AUTONEG;
+       } else if ((ahw->port_type == QLCNIC_XGBE) && (pause->autoneg)) {
+                       return -EOPNOTSUPP;
+       }
+
+       if (!(config & QLC_83XX_CFG_STD_PAUSE))
+               ahw->port_config |= QLC_83XX_CFG_STD_PAUSE;
+
+       if (pause->rx_pause && pause->tx_pause) {
+               ahw->port_config |= QLC_83XX_CFG_STD_TX_RX_PAUSE;
+       } else if (pause->rx_pause && !pause->tx_pause) {
+                       ahw->port_config &= ~QLC_83XX_CFG_STD_TX_PAUSE;
+                       ahw->port_config |= QLC_83XX_CFG_STD_RX_PAUSE;
+       } else if (pause->tx_pause && !pause->rx_pause) {
+                       ahw->port_config &= ~QLC_83XX_CFG_STD_RX_PAUSE;
+                       ahw->port_config |= QLC_83XX_CFG_STD_TX_PAUSE;
+       } else if (!pause->rx_pause && !pause->tx_pause) {
+                       ahw->port_config &= ~QLC_83XX_CFG_STD_TX_RX_PAUSE;
+       }
+       status = qlcnic_83xx_set_port_config(adapter);
+       if (status) {
+               netdev_err(adapter->netdev,
+                       "%s: Set Pause Config failed.\n", __func__);
+               ahw->port_config = config;
+       }
+       return status;
+}
+
+void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+
+       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+               val = BIT_2 | ((adapter->ahw->num_msix - 1) << 8);
+       else
+               val = BIT_2;
+       QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
+}
+
+void qlcnic_set_npar_data(struct qlcnic_adapter *adapter,
+       const struct qlcnic_info *nic_info, struct qlcnic_info *npar_info)
+{
+       npar_info->pci_func = (le16_to_cpu(nic_info->pci_func)) & 0xF;
+       npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
+       npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
+       npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
+       npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+       npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+       npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+       npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+       npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
+       npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
+
+       dev_info(&adapter->pdev->dev,
+               "phy port: %d switch_mode: %d,\n"
+               "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
+               "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
+               npar_info->phys_port, npar_info->switch_mode,
+               npar_info->max_tx_ques, npar_info->max_rx_ques,
+               npar_info->min_tx_bw, npar_info->max_tx_bw,
+               npar_info->max_mtu, npar_info->capabilities);
+}
+
+int
+qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
+                               __le16 vlan_id, u8 op)
+{
+       int err;
+       u32 *buf;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_macvlan_mbx mv;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return -EIO;
+
+       err = adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_CONFIG_MAC_VLAN);
+       if (err)
+               return err;
+       cmd.req.arg[1] = cpu_to_le32(op | (1 << 8) |
+                       (adapter->recv_ctx->context_id << 16));
+
+       mv.vlan = cpu_to_le16(vlan_id);
+       memcpy(&mv.mac, addr, ETH_ALEN);
+       buf = &cmd.req.arg[2];
+       memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
+
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
+               netdev_err(adapter->netdev,
+                       "MAC-VLAN %s to CAM failed, err=%d.\n",
+                       ((op == 1) ? "add " : "delete "), err);
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
+               __le16 vlan_id)
+{
+       u8 mac[ETH_ALEN];
+       memcpy(&mac, addr, ETH_ALEN);
+       qlcnic_83xx_sre_macaddr_change(adapter, mac, vlan_id, QLCNIC_MAC_ADD);
+}
+
+void qlcnic_83xx_configure_mac(struct qlcnic_adapter *adapter, u8 *mac,
+       u8 type, struct qlcnic_cmd_args *cmd)
+{
+       switch (type) {
+       case QLCNIC_SET_STATION_MAC:
+       case QLCNIC_SET_FAC_DEF_MAC:
+               memcpy(&cmd->req.arg[2], mac, sizeof(u32));
+               memcpy(&cmd->req.arg[3], &mac[4], sizeof(u16));
+               break;
+       }
+       cmd->req.arg[1] = cpu_to_le32(type);
+}
+
+/* Get MAC address of a NIC partition */
+int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+       int err, i;
+       struct qlcnic_cmd_args cmd;
+       u32 mac_low, mac_high;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_MAC_ADDRESS);
+       qlcnic_83xx_configure_mac(adapter, mac, QLCNIC_GET_CURRENT_MAC, &cmd);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               mac_low = cmd.rsp.arg[1];
+               mac_high = cmd.rsp.arg[2];
+
+               for (i = 0; i < 2; i++)
+                       mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+               for (i = 2; i < 6; i++)
+                       mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get mac address%d\n", err);
+               err = -EIO;
+       }
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
+{
+       int err;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
+
+       if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
+               return;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_CONFIG_INTR_COAL);
+       cmd.req.arg[1] = cpu_to_le32(1 | (adapter->recv_ctx->context_id << 16));
+       cmd.req.arg[3] = cpu_to_le32(coal->flag);
+       cmd.req.arg[2] = cpu_to_le32(coal->rx_packets |
+               (coal->rx_time_us << 16));
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err != QLCNIC_RCODE_SUCCESS)
+               dev_info(&adapter->pdev->dev,
+                       "Can not send interrupt coalescence parameters\n");
+       qlcnic_free_mbx_args(&cmd);
+}
+
+static void
+qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, u32 data[])
+{
+       u8 link_status, duplex;
+       /* link speed */
+       link_status = LSB(data[3]) & 1;
+       adapter->ahw->link_speed = MSW(data[2]);
+       adapter->ahw->link_autoneg = MSB(MSW(data[3]));
+       adapter->ahw->module_type = MSB(LSW(data[3]));
+       duplex = LSB(MSW(data[3]));
+       if (duplex)
+               adapter->ahw->link_duplex = DUPLEX_FULL;
+       else
+               adapter->ahw->link_duplex = DUPLEX_HALF;
+       adapter->ahw->has_link_events = 1;
+       qlcnic_advert_link_change(adapter, link_status);
+}
+
+irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
+{
+       struct qlcnic_adapter *adapter = data;
+       unsigned long flags;
+       u32 mask, resp, event;
+
+       spin_lock_irqsave(&adapter->ahw->mbx_lock, flags);
+       resp = QLCRDX(adapter->ahw, QLCNIC_FW_MBX_CTRL);
+       if (!(resp & QLCNIC_SET_OWNER))
+               goto out;
+       event = le32_to_cpu(readl(QLCNIC_MBX_FW(adapter->ahw, 0)));
+       if (event &  QLCNIC_MBX_ASYNC_EVENT)
+               qlcnic_83xx_process_aen(adapter);
+out:
+       mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
+       writel(0, adapter->ahw->pci_base0 + mask);
+       spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+int qlcnic_enable_eswitch(struct qlcnic_adapter *adapter, u8 port, u8 enable)
+{
+       int err = -EIO;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Error, invoked by non management func\n",
+                                                               __func__);
+               return err;
+       }
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_TOGGLE_ESWITCH);
+
+       cmd.req.arg[1] = (port & 0xf) | BIT_4;
+
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to enable eswitch%d\n", err);
+               err = -EIO;
+       }
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+
+}
+
+/* Configure a NIC partition */
+int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *adapter,
+                                       struct qlcnic_info *nic)
+{
+       int i, err = -EIO;
+       struct qlcnic_cmd_args cmd;
+
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Error, invoked by non management func\n",
+                                                               __func__);
+               return err;
+       }
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_SET_NIC_INFO);
+
+       cmd.req.arg[1] = (nic->pci_func << 16);
+       cmd.req.arg[2] = 0x1 << 16;
+       cmd.req.arg[3] = nic->phys_port | (nic->switch_mode << 16);
+       cmd.req.arg[4] = nic->capabilities;
+       cmd.req.arg[5] = (nic->max_mac_filters & 0xFF) | ((nic->max_mtu) << 16);
+       cmd.req.arg[6] = (nic->max_tx_ques) | ((nic->max_rx_ques) << 16);
+       cmd.req.arg[7] = (nic->min_tx_bw) | ((nic->max_tx_bw) << 16);
+       for (i = 8; i < 32; i++)
+               cmd.req.arg[i] = 0;
+
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to set nic info%d\n", err);
+               err = -EIO;
+       }
+
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *adapter,
+                       struct qlcnic_info *npar_info, u8 func_id)
+{
+       int err;
+       u8 op = 0;
+       struct qlcnic_cmd_args cmd;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+       if (func_id != adapter->ahw->pci_func) {
+               cmd.req.arg[1] = cpu_to_le32(op | BIT_31 |
+                       (func_id << 16));
+       } else {
+               cmd.req.arg[1] = cpu_to_le32(adapter->ahw->pci_func << 16);
+       }
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                       "Failed to get nic info %d\n", err);
+               goto out;
+       }
+
+       npar_info->op_type = cmd.rsp.arg[1];
+       npar_info->pci_func = cmd.rsp.arg[2] & 0xFFFF;
+       npar_info->op_mode = (cmd.rsp.arg[2] & 0xFFFF0000) >> 16;
+       npar_info->phys_port = cmd.rsp.arg[3] & 0xFFFF;
+       npar_info->switch_mode = (cmd.rsp.arg[3] & 0xFFFF0000) >> 16;
+       npar_info->capabilities = cmd.rsp.arg[4];
+       npar_info->max_mac_filters = cmd.rsp.arg[5] & 0xFF;
+       npar_info->max_mtu = (cmd.rsp.arg[5] & 0xFFFF0000) >> 16;
+       npar_info->max_tx_ques =  cmd.rsp.arg[6] & 0xFFFF;
+       npar_info->max_rx_ques = (cmd.rsp.arg[6] & 0xFFFF0000) >> 16;
+       npar_info->min_tx_bw = cmd.rsp.arg[7] & 0xFFFF;
+       npar_info->max_tx_bw = (cmd.rsp.arg[7] & 0xFFFF0000) >> 16;
+       if (cmd.rsp.arg[8] & 0x1)
+               npar_info->max_bw_reg_offset = (cmd.rsp.arg[8] & 0x7FFE) >> 1;
+       if (cmd.rsp.arg[8] & 0x10000)
+               npar_info->max_linkspeed_reg_offset =
+                               (cmd.rsp.arg[8] & 0x7FFE0000) >> 17;
+
+       dev_info(&adapter->pdev->dev,
+               "\n\top_type: %d, phy port: %d switch_mode: %d,\n"
+               "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x, max_tx_bw: %d,\n"
+               "\tmax_bw_offset: 0x%x max_link_speed_offset: 0x%x,\n"
+               "\tmax_mtu:0x%x, capabilities: 0x%x\n",
+               npar_info->op_type,
+               npar_info->phys_port, npar_info->switch_mode,
+               npar_info->max_tx_ques, npar_info->max_rx_ques,
+               npar_info->min_tx_bw, npar_info->max_tx_bw,
+               npar_info->max_bw_reg_offset,
+               npar_info->max_linkspeed_reg_offset,
+               npar_info->max_mtu, npar_info->capabilities);
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+/* Get PCI Info of a partition */
+int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
+                               struct qlcnic_pci_info *pci_info)
+{
+       int i, err = 0, j = 0;
+       struct qlcnic_cmd_args cmd;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_GET_PCI_INFO);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+       adapter->ahw->act_pci_func = 0;
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               pci_info->func_count = cmd.rsp.arg[1] & 0xFF;
+               QLCDB(adapter, DRV, "%s: total functions = %d\n",
+                     __func__, pci_info->func_count);
+               for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) {
+                       pci_info->id = cmd.rsp.arg[i] & 0xFFFF;
+                       pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+                       i++;
+                       pci_info->type = cmd.rsp.arg[i] & 0xFFFF;
+                       if (pci_info->type == QLCNIC_TYPE_NIC)
+                               adapter->ahw->act_pci_func++;
+                       pci_info->default_port =
+                               (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+                       i++;
+                       pci_info->tx_min_bw = cmd.rsp.arg[i] & 0xFFFF;
+                       pci_info->tx_max_bw =
+                               (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
+                       i = i + 2;
+                       memcpy(pci_info->mac, &cmd.rsp.arg[i], ETH_ALEN - 2);
+                       i++;
+                       memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);
+                       i = i + 3;
+
+                       QLCDB(adapter, DRV, "%s:\n"
+                             "\tid = %d active = %d type = %d\n"
+                             "\tport = %d min bw = %d max bw = %d\n"
+                             "\tmac_addr =  %pM\n", __func__,
+                             pci_info->id, pci_info->active, pci_info->type,
+                             pci_info->default_port, pci_info->tx_min_bw,
+                             pci_info->tx_max_bw, pci_info->mac);
+               }
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to get PCI Info%d\n", err);
+               err = -EIO;
+       }
+
+       qlcnic_free_mbx_args(&cmd);
+
+       return err;
+}
+
+int
+qlcnic_83xx_ms_mem_write_128b(struct qlcnic_adapter *adapter,
+                                       u64 addr, u32 *data, u32 count)
+{
+       int i, j, err, ret = 0;
+       u32 temp;
+
+       /* Only 128-bit aligned access */
+       if (addr & 0xF)
+               return -EIO;
+
+       mutex_lock(&adapter->ahw->mem_lock);
+
+       /* Write address */
+       qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_ADDR_HI, 0);
+
+       for (i = 0 ; i < count ; i++, addr += 16) {
+               if (!((ADDR_IN_RANGE(addr, QLCNIC_ADDR_QDR_NET,
+                       QLCNIC_ADDR_QDR_NET_MAX)) ||
+                               (ADDR_IN_RANGE(addr, QLCNIC_ADDR_DDR_NET,
+                                       QLCNIC_ADDR_DDR_NET_MAX)))){
+                       mutex_unlock(&adapter->ahw->mem_lock);
+                       return -EIO;
+               }
+
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLCNIC_MS_ADDR_LO, addr);
+
+               /* Write data */
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLCNIC_MS_WRTDATA_LO, *data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLCNIC_MS_WRTDATA_HI, *data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLCNIC_MS_WRTDATA_ULO, *data++);
+               qlcnic_83xx_wrt_reg_indirect(adapter,
+                               QLCNIC_MS_WRTDATA_UHI, *data++);
+
+               /* Check write status */
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+                                               QLC_TA_WRITE_ENABLE);
+               qlcnic_83xx_wrt_reg_indirect(adapter, QLCNIC_MS_CTRL,
+                                               QLC_TA_WRITE_START);
+
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = qlcnic_83xx_rd_reg_indirect(adapter,
+                                               QLCNIC_MS_CTRL, &err);
+                       if (err == -EIO) {
+                               mutex_unlock(&adapter->ahw->mem_lock);
+                               return -EIO;
+                       }
+
+                       if ((temp & TA_CTL_BUSY) == 0)
+                               break;
+               }
+
+               /* Status check failed */
+               if (j >= MAX_CTL_CHECK) {
+                       if (printk_ratelimit()) {
+                               dev_err(&adapter->pdev->dev,
+                                       "MS memory write failed.\n");
+                               mutex_unlock(&adapter->ahw->mem_lock);
+                               return -EIO;
+                       }
+               }
+       }
+
+       mutex_unlock(&adapter->ahw->mem_lock);
+
+       return ret;
+}
+
+void
+qlcnic_83xx_cancel_idc_work(struct qlcnic_adapter *adapter)
+{
+       int id;
+       u32 val;
+
+       while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               msleep(10);
+
+       id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+       id = id & 0xFF;
+
+       if (id == adapter->portnum) {
+               dev_err(&adapter->pdev->dev,
+                       "%s: wait for lock recovery.. %d\n", __func__, id);
+               msleep(20);
+               id = QLCRDX(adapter->ahw, QLC_83XX_DRV_LOCK_ID);
+               id = id & 0xFF;
+       }
+
+       /* Clear driver presence bit */
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+       val = val & ~(1 << adapter->portnum);
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+
+       clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+
+       cancel_delayed_work_sync(&adapter->fw_work);
+}
+
+void
+qlcnic_83xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
+{
+       u32 val;
+
+       if (qlcnic_83xx_lock_driver(adapter)) {
+               netdev_err(adapter->netdev,
+                       "%s:failed, please retry\n", __func__);
+               return;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+       if ((val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY) || !auto_fw_reset) {
+               netdev_err(adapter->netdev,
+                       "%s:failed, device in non reset mode\n", __func__);
+               qlcnic_83xx_unlock_driver(adapter);
+               return;
+       }
+
+       if (key == QLCNIC_FORCE_FW_RESET) {
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val = val | QLC_83XX_IDC_GRACEFULL_RESET;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+       } else if (key == QLCNIC_FORCE_FW_DUMP_KEY) {
+               adapter->ahw->idc.collect_dump = 1;
+       }
+
+       qlcnic_83xx_unlock_driver(adapter);
+       return;
+}
+
+static int
+qlcnic_sysfs_validate_bar(struct qlcnic_adapter *adapter, loff_t offset,
+       size_t size)
+{
+       size_t bar = 4;
+
+       if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+               return -EIO;
+
+       if (offset >= QLCNIC_83XX_BAR0_LENGTH || (offset & (bar - 1)) ||
+               (size != bar))
+               return -EINVAL;
+       return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_read_bar(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t offset, size_t size)
+{
+       u32 data;
+       int ret;
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       ret = qlcnic_sysfs_validate_bar(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       mutex_lock(&adapter->ahw->mem_lock);
+       data = readl(adapter->ahw->pci_base0 + offset);
+       mutex_unlock(&adapter->ahw->mem_lock);
+
+       memcpy(buf, &data, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_write_bar(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t offset, size_t size)
+{
+       u32 data;
+       int ret;
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       ret = qlcnic_sysfs_validate_bar(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       memcpy(&data, buf, size);
+       mutex_lock(&adapter->ahw->mem_lock);
+       writel(data, adapter->ahw->pci_base0 + offset);
+       mutex_unlock(&adapter->ahw->mem_lock);
+
+       return size;
+}
+
+static ssize_t
+qlcnic_83xx_sysfs_flash_read_handler(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t offset, size_t size)
+{
+       unsigned char *p_read_buf;
+       int  ret, u32_word_count;
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       if (!size)
+               return QL_STATUS_INVALID_PARAM;
+       if (!buf)
+               return QL_STATUS_INVALID_PARAM;
+
+       u32_word_count = size/sizeof(u32);
+
+       if (size%sizeof(u32))
+               u32_word_count++;
+
+       p_read_buf = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
+       if (!p_read_buf)
+               return -ENOMEM;
+       if (qlcnic_83xx_lock_flash(adapter) != 0) {
+               kfree(p_read_buf);
+               return -EIO;
+       }
+
+       ret = qlcnic_83xx_lockless_flash_read_u32(adapter, offset,
+                                       p_read_buf, u32_word_count);
+
+       if (ret) {
+               qlcnic_83xx_unlock_flash(adapter);
+               kfree(p_read_buf);
+               return ret;
+       }
+
+       qlcnic_83xx_unlock_flash(adapter);
+       memcpy(buf, p_read_buf, size);
+       kfree(p_read_buf);
+
+       return size;
+}
+
+static int
+qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter,
+                               char *buf, loff_t offset, size_t size)
+{
+       int  i, ret, u32_word_count;
+       unsigned char *p_cache, *p_src;
+
+       p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
+       if (!p_cache)
+               return -ENOMEM;
+
+       memcpy(p_cache, buf, size);
+       p_src = p_cache;
+       u32_word_count = size/sizeof(u32);
+
+       if (qlcnic_83xx_lock_flash(adapter) != 0) {
+               kfree(p_cache);
+               return -EIO;
+       }
+
+       if (adapter->ahw->flash_fdt.flash_manuf == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_enable_flash_write_op(adapter);
+               if (ret) {
+                       kfree(p_cache);
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+       }
+
+       for (i = 0; i < u32_word_count/QLC_83XX_FLASH_BULK_WRITE_MAX; i++) {
+               ret = qlcnic_83xx_flash_bulk_write(adapter, offset,
+                       (u32 *)p_src, QLC_83XX_FLASH_BULK_WRITE_MAX);
+
+               if (ret) {
+                       if (adapter->ahw->flash_fdt.flash_manuf ==
+                       adapter->flash_mfg_id) {
+                               ret =
+                               qlcnic_83xx_disable_flash_write_op(adapter);
+                               if (ret) {
+                                       kfree(p_cache);
+                                       qlcnic_83xx_unlock_flash(adapter);
+                                       return -EIO;
+                               }
+                       }
+                       kfree(p_cache);
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+
+               p_src = p_src + sizeof(u32)*QLC_83XX_FLASH_BULK_WRITE_MAX;
+               offset = offset + sizeof(u32)*QLC_83XX_FLASH_BULK_WRITE_MAX;
+       }
+
+       if (adapter->ahw->flash_fdt.flash_manuf == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_disable_flash_write_op(adapter);
+               if (ret) {
+                       kfree(p_cache);
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+       }
+       kfree(p_cache);
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter,
+                               char *buf, loff_t offset, size_t size)
+{
+       int  i, ret, u32_word_count;
+       unsigned char *p_cache, *p_src;
+
+       p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
+       if (!p_cache)
+               return -ENOMEM;
+
+       memcpy(p_cache, buf, size);
+       p_src = p_cache;
+       u32_word_count = size/sizeof(u32);
+
+       if (qlcnic_83xx_lock_flash(adapter) != 0) {
+               kfree(p_cache);
+               return -EIO;
+       }
+
+       if (adapter->ahw->flash_fdt.flash_manuf == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_enable_flash_write_op(adapter);
+               if (ret) {
+                       kfree(p_cache);
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+       }
+
+       for (i = 0; i < u32_word_count; i++) {
+               ret = qlcnic_83xx_flash_write_u32(adapter,
+                                       offset, (u32 *)p_src);
+               if (ret) {
+                       if (adapter->ahw->flash_fdt.flash_manuf ==
+                               adapter->flash_mfg_id) {
+                               ret =
+                               qlcnic_83xx_disable_flash_write_op(adapter);
+                               if (ret) {
+                                       kfree(p_cache);
+                                       qlcnic_83xx_unlock_flash(adapter);
+                                       return -EIO;
+                               }
+                       }
+                       kfree(p_cache);
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+               p_src = p_src + sizeof(u32);
+               offset = offset + sizeof(u32);
+       }
+
+       if (adapter->ahw->flash_fdt.flash_manuf == adapter->flash_mfg_id) {
+               ret = qlcnic_83xx_disable_flash_write_op(adapter);
+               if (ret) {
+                       kfree(p_cache);
+                       qlcnic_83xx_unlock_flash(adapter);
+                       return -EIO;
+               }
+       }
+
+       kfree(p_cache);
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return 0;
+}
+
+static ssize_t
+qlcnic_83xx_sysfs_flash_write_handler(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t offset, size_t size)
+{
+       int  ret;
+       static int flash_mode;
+       unsigned long data;
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       if (!buf)
+               return QL_STATUS_INVALID_PARAM;
+
+       data = simple_strtoul(buf, NULL, 16);
+
+       switch (data) {
+       case QLC_83XX_FLASH_SECTOR_ERASE_CMD:
+               flash_mode = QLC_83XX_ERASE_MODE;
+               ret = qlcnic_83xx_erase_flash_sector(adapter, offset);
+               if (ret) {
+                       dev_err(&adapter->pdev->dev,
+                               "%s failed at %d\n", __func__, __LINE__);
+                       return -EIO;
+               }
+               break;
+
+       case QLC_83XX_FLASH_BULK_WRITE_CMD:
+               flash_mode = QLC_83XX_BULK_WRITE_MODE;
+               break;
+
+       case QLC_83XX_FLASH_WRITE_CMD:
+               flash_mode = QLC_83XX_WRITE_MODE;
+               break;
+       default:
+               if (flash_mode == QLC_83XX_BULK_WRITE_MODE) {
+                       ret = qlcnic_83xx_sysfs_flash_bulk_write(adapter,
+                                                       buf, offset, size);
+                       if (ret) {
+                               dev_err(&adapter->pdev->dev,
+                               "%s failed at %d\n", __func__, __LINE__);
+                               return -EIO;
+                       }
+               }
+
+               if (flash_mode == QLC_83XX_WRITE_MODE) {
+                       ret = qlcnic_83xx_sysfs_flash_write(adapter,
+                                               buf, offset, size);
+                       if (ret) {
+                               dev_err(&adapter->pdev->dev,
+                               "%s failed at %d\n", __func__, __LINE__);
+                               return -EIO;
+                       }
+               }
+
+       }
+
+       return size;
+}
+
+static struct bin_attribute bin_attr_bar = {
+       .attr = {.name = "membar", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_bar,
+       .write = qlcnic_sysfs_write_bar,
+};
+
+static struct bin_attribute bin_attr_flash = {
+       .attr = {.name = "flash", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_83xx_sysfs_flash_read_handler,
+       .write = qlcnic_83xx_sysfs_flash_write_handler,
+};
+
+/*Note: add new bin_attribute structures above this line */
+
+void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+       qlcnic_create_diag_entries(adapter);
+       if (sysfs_create_bin_file(&dev->kobj, &bin_attr_bar))
+               dev_info(dev, "failed to create mem bar sysfs entry\n");
+       if (sysfs_create_bin_file(&dev->kobj, &bin_attr_flash))
+               dev_info(dev, "failed to create flash sysfs entry\n");
+}
+
+void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+       qlcnic_remove_diag_entries(adapter);
+       sysfs_remove_bin_file(&dev->kobj, &bin_attr_bar);
+       sysfs_remove_bin_file(&dev->kobj, &bin_attr_flash);
+}
diff --git a/drivers/net/qlcnic/qlcnic_83xx.h b/drivers/net/qlcnic/qlcnic_83xx.h
new file mode 100644 (file)
index 0000000..c0c30d1
--- /dev/null
@@ -0,0 +1,488 @@
+#ifndef __QLCNIC_83XX_H
+#define __QLCNIC_83XX_H
+
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include "qlcnic_hw.h"
+
+/* Directly mapped registers */
+#define QLC_83XX_CRB_WIN_BASE          0x3800
+#define QLC_83XX_CRB_WIN_FUNC(f)       (QLC_83XX_CRB_WIN_BASE+((f)*4))
+#define QLC_83XX_SEM_LOCK_BASE         0x3840
+#define QLC_83XX_SEM_UNLOCK_BASE       0x3844
+#define QLC_83XX_SEM_LOCK_FUNC(f)      (QLC_83XX_SEM_LOCK_BASE+((f)*8))
+#define QLC_83XX_SEM_UNLOCK_FUNC(f)    (QLC_83XX_SEM_UNLOCK_BASE+((f)*8))
+#define QLC_83XX_LINK_STATE(f)         (0x3698+((f) > 7 ? 4:0))
+#define QLC_83XX_LINK_SPEED(f)         (0x36E0+(((f) >> 2) * 4))
+#define QLC_83XX_LINK_SPEED_FACTOR     10
+#define QLC_83xx_FUNC_VAL(v, f)        ((v) & (1 << (f * 4)))
+#define QLCNIC_83XX_INTX_PTR           0x38C0
+#define QLCNIC_83XX_INTX_TRGR          0x38C4
+#define QLCNIC_83XX_INTX_MASK          0x38C8
+
+/* Indirectly mapped registers */
+#define QLC_83XX_FLASH_SPI_STATUS      0x2808E010
+#define QLC_83XX_FLASH_SPI_CONTROL     0x2808E014
+#define QLC_83XX_FLASH_STATUS          0x42100004
+#define QLC_83XX_FLASH_CONTROL         0x42110004
+#define QLC_83XX_FLASH_ADDR            0x42110008
+#define QLC_83XX_FLASH_WRDATA          0x4211000C
+#define QLC_83XX_FLASH_RDDATA          0x42110018
+#define QLC_83XX_FLASH_DIRECT_WINDOW           0x42110030
+#define QLC_83XX_FLASH_DIRECT_DATA(DATA)       (0x42150000 | (0x0000FFFF&DATA))
+
+#define QLC_83XX_FLASH_SECTOR_ERASE_CMD                0xdeadbeef
+#define QLC_83XX_FLASH_WRITE_CMD               0xdacdacda
+#define QLC_83XX_FLASH_BULK_WRITE_CMD          0xcadcadca
+#define QLC_83XX_FLASH_READ_RETRY_COUNT                5000
+#define QLC_83XX_FLASH_STATUS_READY            0x6
+#define        QLC_83XX_FLASH_BULK_WRITE_MIN           2
+#define        QLC_83XX_FLASH_BULK_WRITE_MAX           64
+#define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY   1
+#define QLC_83XX_ERASE_MODE                    1
+#define QLC_83XX_WRITE_MODE                    2
+#define QLC_83XX_BULK_WRITE_MODE               3
+
+/* Peg PC status registers */
+#define QLC_83XX_CRB_PEG_NET_0         0x3400003c
+#define QLC_83XX_CRB_PEG_NET_1         0x3410003c
+#define QLC_83XX_CRB_PEG_NET_2         0x3420003c
+#define QLC_83XX_CRB_PEG_NET_3         0x3430003c
+#define QLC_83XX_CRB_PEG_NET_4         0x34b0003c
+
+/* QLCNIC_CMD_CONFIG_MAC_VLAN [0x45] error codes */
+#define QLCNIC_NO_CARD_RESOURCE                0x5
+#define QLCNIC_MAC_ALREADY_EXISTS      0xC
+#define QLCNIC_MAC_DOES_NOT_EXIST      0xD
+
+/* Pause control registers */
+#define QLC_83XX_SRE_SHIM_REG          0x0D200284
+#define QLC_83XX_PORT0_THRESHOLD       0x0B2003A4
+#define QLC_83XX_PORT1_THRESHOLD       0x0B2013A4
+#define QLC_83XX_PORT0_TC_MC_REG       0x0B200388
+#define QLC_83XX_PORT1_TC_MC_REG       0x0B201388
+#define QLC_83XX_PORT0_TC_STATS                0x0B20039C
+#define QLC_83XX_PORT1_TC_STATS                0x0B20139C
+#define QLC_83XX_PORT2_IFB_THRESHOLD   0x0B200704
+#define QLC_83XX_PORT3_IFB_THRESHOLD   0x0B201704
+
+/* Flash Operations Misc Signatures*/
+#define QLC_83XX_FLASH_FDT_WRITE_DEF_SIG       0xFD0100
+#define QLC_83XX_FLASH_FDT_ERASE_DEF_SIG       0xFD0300
+#define QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL     0xFD009F
+
+#define QLC_83XX_FLASH_OEM_ERASE_SIG           0xFD03D8
+#define QLC_83XX_FLASH_OEM_WRITE_SIG           0xFD0101
+#define QLC_83XX_FLASH_OEM_READ_SIG            0xFD0005
+
+#define QLC_83XX_FLASH_ADDR_TEMP_VAL           0x00800000
+#define QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL    0x00800001
+
+#define QLC_83XX_FLASH_WRDATA_DEF_VAL          0x0
+#define QLC_83XX_FLASH_READ_CONTROL_VAL                0x3F
+#define QLC_83XX_FLASH_SPI_CONTROL_VAL         0x4
+
+#define QLC_83XX_FLASH_FIRST_ERASE_MS_VAL      0x2
+#define QLC_83XX_FLASH_SECOND_ERASE_MS_VAL     0x5
+#define QLC_83XX_FLASH_LAST_ERASE_MS_VAL       0x3D
+
+#define QLC_83XX_FLASH_FIRST_WRITE_MS_PATTERN  0x43
+#define QLC_83XX_FLASH_SECOND_WRITE_MS_PATTERN 0x7F
+#define QLC_83XX_FLASH_LAST_WRITE_MS_PATTERN   0x7D
+
+/* FLASH API defines */
+#define QLC_83xx_FLASH_MAX_WAIT_USEC   100
+#define QLC_83XX_FLASH_LOCK_TIMEOUT    10000
+#define QLC_83XX_DRV_LOCK_WAIT_COUNTER 100
+#define QLC_83XX_DRV_LOCK_WAIT_DELAY   20
+#define QLC_83XX_NEED_DRV_LOCK_RECOVERY        1
+#define QLC_83XX_DRV_LOCK_RECOVERY_IN_PROGRESS 2
+#define QLC_83XX_MAX_DRV_LOCK_RECOVERY_ATTEMPT 3
+#define QLC_83XX_DRV_LOCK_RECOVERY_DELAY       200
+#define QLC_83XX_DRV_LOCK_RECOVERY_STATUS_MASK 0x3
+
+#define QLC_83XX_FLASH_SECTOR_SIZE     (64 * 1024)
+
+
+/* PEG status definitions */
+#define QLC_83xx_CMDPEG_COMPLETE        0xff01
+
+/* Firmware image definitions */
+#define QLC_83XX_BOOTLOADER_FLASH_ADDR 0x10000
+#define QLC_83XX_FW_FILE_NAME          "83xx_fw.bin"
+
+#define QLC_83XX_BOOT_FROM_FLASH       0
+#define QLC_83XX_BOOT_FROM_FILE                0x12345678
+
+/* Reset template definitions */
+#define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16
+#define QLC_83XX_RESTART_TEMPLATE_SIZE 0x2000
+#define QLC_83XX_RESET_TEMPLATE_ADDR   0x4F0000
+#define QLC_83XX_RESET_SEQ_VERSION     0x0101
+
+#define OPCODE_NOP                     0x0000
+#define OPCODE_WRITE_LIST              0x0001
+#define OPCODE_READ_WRITE_LIST         0x0002
+#define OPCODE_POLL_LIST               0x0004
+#define OPCODE_POLL_WRITE_LIST         0x0008
+#define OPCODE_READ_MODIFY_WRITE       0x0010
+#define OPCODE_SEQ_PAUSE               0x0020
+#define OPCODE_SEQ_END                 0x0040
+#define OPCODE_TMPL_END                0x0080
+#define OPCODE_POLL_READ_LIST          0x0100
+
+#define qlcnic_83xx_pktln(sts) \
+       ((sts >> 32) & 0x3FFF)
+#define qlcnic_83xx_hndl(sts)  \
+       ((sts >> 48) & 0x7FFF)
+#define qlcnic_83xx_csum_status(sts)   \
+       ((sts >> 39) & 7)
+#define qlcnic_83xx_opcode(sts)        \
+       ((sts >> 42) & 0xF)
+#define qlcnic_83xx_vlan_tag(sts)      \
+       (((sts) >> 48) & 0xFFFF)
+#define qlcnic_83xx_lro_pktln(sts)     \
+       (((sts) >> 32) & 0xFFFF)
+#define qlcnic_83xx_l2_hdr_off(sts)    \
+       (((sts) >> 16) & 0xFF)
+#define qlcnic_83xx_l4_hdr_off(sts)    \
+       (((sts) >> 24) & 0xFF)
+#define qlcnic_83xx_pkt_cnt(sts)       \
+       (((sts) >> 16) & 0x7)
+#define qlcnic_83xx_get_lro_sts_mss(sts) \
+       ((sts) & 0xFFFFFFFF)
+
+#define qlcnic_83xx_is_tstamp(sts)     \
+       (((sts) >> 40) & 1)
+#define qlcnic_83xx_is_psh_bit(sts)    \
+       (((sts) >> 41) & 1)
+#define qlcnic_83xx_is_ip_align(sts)   \
+       (((sts) >> 46) & 1)
+#define qlcnic_83xx_has_vlan_tag(sts)  \
+       (((sts) >> 47) & 1)
+
+#define QLCNIC_83XX_VALID_INTX_BIT30(val)\
+       ((val) & BIT_30)
+#define QLCNIC_83XX_VALID_INTX_BIT31(val)\
+       ((val) & BIT_31)
+#define QLCNIC_83XX_INTX_FUNC(val)     \
+       ((val) & 0xFF)
+
+#define QLC_83XX_LEGACY_INTX_DELAY     4
+
+#define QLCNIC_83XX_REG_DESC   1
+#define QLCNIC_83XX_LRO_DESC   2
+#define QLCNIC_83XX_CTRL_DESC  3
+
+#define QLCNIC_FW_83XX_CAPABILITY_TSO  BIT_6
+#define QLCNIC_FW_83XX_CAP_LRO_MSS     BIT_17
+
+#define QLCNIC_HOST_83XX_RDS_MODE_UNIQUE 0
+#define QLCNIC_HOST_SDS_MBX_IDX        8
+/* status descriptor mailbox data
+ * @phy_addr: physical address of buffer
+ * @sds_ring_size: buffer size
+ * @intrpt_id: interrupt id
+ * @intrpt_val: source of interrupt
+ */
+struct qlcnic_sds_mbx {
+       __le64  phy_addr;
+       u8      rsvd1[16];
+       __le16  sds_ring_size;
+       __le16  rsvd2[3];
+       __le16  intrpt_id;
+       u8      intrpt_val;
+       u8      rsvd3[5];
+} __packed;
+
+#define QLCNIC_HOST_RDS_MBX_IDX        88
+/* receive descriptor buffer data
+ * phy_addr_reg: physical address of regular buffer
+ * phy_addr_jmb: physical address of jumbo buffer
+ * reg_ring_sz: size of regular buffer
+ * reg_ring_len: no. of entries in regular buffer
+ * jmb_ring_len: no. of entries in jumbo buffer
+ * jmb_ring_sz: size of jumbo buffer
+ */
+struct qlcnic_rds_mbx {
+       __le64  phy_addr_reg;
+       __le64  phy_addr_jmb;
+       __le16  reg_ring_sz;
+       __le16  reg_ring_len;
+       __le16  jmb_ring_sz;
+       __le16  jmb_ring_len;
+} __packed;
+
+/* host producers for regular and jumbo rings */
+struct __host_producer_mbx {
+       __le32  reg_buf;
+       __le32  jmb_buf;
+} __packed;
+
+#define QLCNIC_MAX_RING_SETS   8
+/* Receive context mailbox data outbox registers
+ * @state: state of the context
+ * @vport_id: virtual port id
+ * @context_id: receive context id
+ * @num_pci_func: number of pci functions of the port
+ * @phy_port: physical port id
+ */
+struct qlcnic_rcv_mbx_out {
+       u8      rcv_num;
+       u8      sts_num;
+       __le16  ctx_id;
+       u8      state;
+       u8      num_pci_func;
+       u8      phy_port;
+       u8      vport_id;
+       __le32  host_csmr[QLCNIC_MAX_RING_SETS];
+       struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+struct qlcnic_add_rings_mbx_out {
+       u8      rcv_num;
+       u8      sts_num;
+       __le16  ctx_id;
+       __le32  host_csmr[QLCNIC_MAX_RING_SETS];
+       struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+/* Transmit context mailbox inbox registers
+ * @phys_addr: DMA address of the transmit buffer
+ * @cnsmr_index: host consumer index
+ * @size: legth of transmit buffer ring
+ * @intr_id: interrput id
+ * @src: src of interrupt
+ */
+struct qlcnic_tx_mbx {
+       __le64  phys_addr;
+       __le64  cnsmr_index;
+       __le16  size;
+       __le16  intr_id;
+       u8      src;
+       u8      rsvd[3];
+} __packed;
+
+/* Transmit context mailbox outbox registers
+ * @host_prod: host producer index
+ * @ctx_id: transmit context id
+ * @state: state of the transmit context
+ */
+struct qlcnic_tx_mbx_out {
+       __le32  host_prod;
+       __le16  ctx_id;
+       u8      state;
+       u8      rsvd;
+} __packed;
+
+struct qlcnic_intrpt_config {
+       u8      type;
+       u8      enabled;
+       u16     id;
+       u32     src;
+};
+
+struct qlcnic_macvlan_mbx {
+       u8      mac[ETH_ALEN];
+       __le16  vlan;
+};
+
+/* Template Header */
+struct qlcnic_83xx_reset_template_hdr {
+       __le16  version;
+       __le16  signature;
+       __le16  size;
+       __le16  entries;
+       __le16  hdr_size;
+       __le16  checksum;
+       __le16  init_seq_offset;
+       __le16  start_seq_offset;
+} __packed;
+
+/* Common Entry Header. */
+struct qlcnic_83xx_reset_entry_hdr {
+       __le16 cmd;
+       __le16 size;
+       __le16 count;
+       __le16 delay;
+} __packed;
+
+/* Generic poll entry type. */
+struct qlcnic_83xx_poll {
+       __le32  test_mask;
+       __le32  test_value;
+} __packed;
+
+/* Read modify write entry type. */
+struct qlcnic_83xx_rmw {
+       __le32  test_mask;
+       __le32  xor_value;
+       __le32  or_value;
+       u8      shl;
+       u8      shr;
+       u8      index_a;
+       u8      rsvd;
+} __packed;
+
+/* Generic Entry Item with 2 DWords. */
+struct qlcnic_83xx_entry {
+       __le32 arg1;
+       __le32 arg2;
+} __packed;
+
+/* Generic Entry Item with 4 DWords.*/
+struct qlcnic_83xx_quad_entry {
+       __le32 dr_addr;
+       __le32 dr_value;
+       __le32 ar_addr;
+       __le32 ar_value;
+} __packed;
+
+struct qlcnic_83xx_reset {
+       int seq_index;
+       int seq_error ;
+       int array_index;
+       u32 array[QLC_83XX_MAX_RESET_SEQ_ENTRIES];
+       u8 *buff;
+       u8 *stop_offset;
+       u8 *start_offset;
+       u8 *init_offset;
+       struct qlcnic_83xx_reset_template_hdr *hdr;
+       u8 seq_end;
+       u8 template_end;
+};
+
+struct qlcnic_83xx_fw_info {
+       u16 major_fw_version;
+       u8  minor_fw_version;
+       u8  sub_fw_version;
+       u8  fw_build_num;
+       const struct firmware *fw;
+};
+
+/* IDC Device States */
+enum qlc_83xx_states {
+       QLC_83XX_IDC_DEV_UNKNOWN,
+       QLC_83XX_IDC_DEV_COLD,
+       QLC_83XX_IDC_DEV_INIT,
+       QLC_83XX_IDC_DEV_READY,
+       QLC_83XX_IDC_DEV_NEED_RESET,
+       QLC_83XX_IDC_DEV_NEED_QUISCENT,
+       QLC_83XX_IDC_DEV_FAILED,
+       QLC_83XX_IDC_DEV_QUISCENT
+};
+
+#define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1
+#define QLC_83XX_IDC_GRACEFULL_RESET    0x2
+
+
+#define QLC_83XX_IDC_TIMESTAMP                 0
+#define QLC_83XX_IDC_DURATION                  1
+
+#define QLC_83XX_IDC_INIT_TIMEOUT_SECS         30
+#define QLC_83XX_IDC_RESET_ACK_TIMEOUT_SECS    10
+#define QLC_83XX_IDC_RESET_TIMEOUT_SECS                10
+#define QLC_83XX_IDC_QUIESCE_ACK_TIMEOUT_SECS  20
+#define QLC_83XX_IDC_FW_POLL_DELAY             (1 * HZ)
+#define QLC_83XX_IDC_FW_FAIL_THRESH            2
+
+#define QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO 8
+#define QLC_83XX_IDC_MAX_CNA_FUNCTIONS 16
+
+#define QLC_83XX_IDC_MAJOR_VERSION 1
+#define QLC_83XX_IDC_MINOR_VERSION 0
+
+#define QLC_83XX_IDC_FLASH_PARAM_ADDR 0x3e8020
+#define QLC_83XX_MBX_AEN_CNT 5                 /* Mailbox process AEN count */
+
+struct qlcnic_adapter;
+struct qlcnic_83xx_idc {
+       u64 sec_counter;
+       u64 delay;
+       unsigned long status;
+       int err_code;
+       int collect_dump;
+       u8 curr_state;
+       u8 prev_state;
+       u8 vnic_state;
+       u8 vnic_wait_limit;
+       u8 quiesce_req;
+       int (*ready_state_entry_action) (struct qlcnic_adapter *);
+       char **name;
+#define QLC_83XX_MODULE_LOADED 1
+#define QLC_83XX_MBX_READY     2
+#define QLC_83XX_IDC_COMP_AEN  3
+};
+
+#define IS_QLCNIC_83XX_USED(a, b, c)   \
+       (((1 << a->portnum) & b) || ((c >> 6) & 0x1))
+
+#define QLC_83XX_SFP_PRESENT(data) ((data) & 3)
+#define QLC_83XX_SFP_ERR(data) (((data) >> 2) & 3)
+#define QLC_83XX_SFP_MODULE_TYPE(data) (((data) >> 4) & 0x1F)
+#define QLC_83XX_SFP_CU_LENGTH(data) (LSB((data) >> 16))
+#define QLC_83XX_SFP_TX_FAULT(data) ((data) & BIT_10)
+#define QLC_83XX_SFP_10G_CAPABLE(data) ((data) & BIT_11)
+#define QLC_83XX_LINK_STATS(data) ((data) & BIT_0)
+#define QLC_83XX_CURRENT_LINK_SPEED(data) (((data) >> 3) & 7)
+#define QLC_83XX_LINK_PAUSE(data) (((data) >> 6) & 3)
+#define QLC_83XX_LINK_LB(data) (((data) >> 8) & 7)
+#define QLC_83XX_LINK_FEC(data) ((data) & BIT_12)
+#define QLC_83XX_LINK_EEE(data) ((data) & BIT_13)
+#define QLC_83XX_DCBX(data) (((data) >> 28) & 7)
+#define QLC_83XX_AUTONEG(data) ((data) & BIT_15)
+#define QLC_83XX_CFG_STD_PAUSE (1 << 5)                /* Standard Pause config */
+#define QLC_83XX_CFG_STD_TX_PAUSE (1 << 20)    /* Transmit Pause enabled */
+#define QLC_83XX_CFG_STD_RX_PAUSE (2 << 20)    /* Receive Pause enabled */
+#define QLC_83XX_CFG_STD_TX_RX_PAUSE (3 << 20)         /* Tx and Rx Pause enabled */
+#define QLC_83XX_ENABLE_AUTONEG (1 << 15)      /* Auto-negotiation enabled */
+#define QLC_83XX_CFG_LOOPBACK_HSS (2 << 1)     /* HSS Internal Loopback Mode */
+#define QLC_83XX_CFG_LOOPBACK_PHY (3 << 1)     /* PHY Internal Loopback Mode */
+#define QLC_83XX_CFG_LOOPBACK_EXT (4 << 1)     /* External Loopback Mode */
+
+/* LED configuration settings */
+#define QLCNIC_83XX_ENABLE_BEACON 0xe
+#define QLCNIC_83XX_LED_RATE 0xff
+#define QLCNIC_83XX_LED_ACT (1 << 10)
+#define QLCNIC_83XX_LED_MOD (0 << 13)
+#define QLCNIC_83XX_LED_CONFIG (QLCNIC_83XX_LED_RATE | QLCNIC_83XX_LED_ACT |\
+                               QLCNIC_83XX_LED_MOD)
+
+#define QLC_83XX_10M_LINK      1
+#define QLC_83XX_100M_LINK     2
+#define QLC_83XX_1G_LINK       3
+#define QLC_83XX_10G_LINK      4
+
+#define QLCNIC_83XX_STAT_TX    3
+#define QLCNIC_83XX_STAT_RX    2
+
+#define QLCNIC_83XX_STAT_MAC   1
+
+#define QLCNIC_83XX_TX_STAT_REGS       14
+#define QLCNIC_83XX_RX_STAT_REGS       40
+#define QLCNIC_83XX_MAC_STAT_REGS      80
+
+#define QLCNIC_GET_VPORT_INFO  1
+
+#define QLC_83XX_GET_FUNC_PRIVILEGE_LEVEL(VAL, FN) (0x3 & ((VAL) >> (FN * 2)))
+#define QLC_83XX_SET_FUNC_OPMODE(VAL, FN)   ((VAL) << (FN * 2))
+#define QLC_83XX_DEFAULT_OPMODE 0x55555555
+#define QLC_83XX_PRIVLEGED_FUNC 0x1
+#define QLC_83XX_VIRTUAL_FUNC 0x2
+
+#define QLC_83XX_GET_FUNC_MODE_FROM_NPAR_INFO(val) (val & 0x80000000)
+#define QLC_83XX_GET_LRO_CAPABILITY(val) (val & 0x20)
+#define QLC_83XX_GET_LSO_CAPABILITY(val) (val & 0x40)
+#define QLC_83XX_GET_LSO_CAPABILITY(val) (val & 0x40)
+#define QLC_83XX_GET_HW_LRO_CAPABILITY(val) (val & 0x400)
+#define QLC_83XX_GET_VLAN_ALIGN_CAPABILITY(val) (val & 0x4000)
+#define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val) (val & 0x20000)
+
+#define QLC_83XX_VIRTUAL_NIC_MODE 0xFF
+#define QLC_83XX_DEFAULT_MODE 0x0
+#define QLC_83XX_MINIMUM_VECTOR 3
+
+#define QLC_83XX_LB_MAX_FILTERS 2048
+#define QLC_83XX_LB_BUCKET_SIZE 256
+
+#endif
diff --git a/drivers/net/qlcnic/qlcnic_83xx_init.c b/drivers/net/qlcnic/qlcnic_83xx_init.c
new file mode 100644 (file)
index 0000000..2ceb4db
--- /dev/null
@@ -0,0 +1,2195 @@
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+static const char *qlcnic_83xx_idc_states[] =  {
+       "Unknown",
+       "Cold",
+       "Init",
+       "Ready",
+       "Need Reset",
+       "Need Quiesce",
+       "Failed",
+       "Quiesced"
+};
+
+static int
+qlcnic_83xx_init_driver(struct qlcnic_adapter *adapter);
+
+static int
+qlcnic_83xx_copy_bootloader(struct qlcnic_adapter *adapter)
+{
+       u8 *p_cache;
+       u32 src, count, size;
+       u64 dest;
+       int ret = -EIO;
+
+       src = QLC_83XX_BOOTLOADER_FLASH_ADDR;
+       dest = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_ADDR);
+       size = QLCRDX(adapter->ahw, QLCNIC_BOOTLOADER_SIZE);
+
+       /* 128 bit alignmnet check */
+       if (size & 0xF)
+               size = (size + 16) & ~0xF;
+
+       /* 16 byte count */
+       count = size/16;
+
+       p_cache = kzalloc(size, GFP_KERNEL);
+       if (p_cache == NULL) {
+               dev_err(&adapter->pdev->dev,
+                       "Failed to allocate memory for boot loader cache\n");
+               return -ENOMEM;
+       }
+
+       ret = qlcnic_83xx_lockless_flash_read_u32(adapter, src,
+                                       p_cache, size/sizeof(u32));
+       if (ret) {
+               kfree(p_cache);
+               return ret;
+       }
+
+       /* 128 bit/16 byte write to MS memory */
+       ret = qlcnic_83xx_ms_mem_write_128b(adapter, dest,
+                                       (u32 *)p_cache, size/16);
+       if (ret) {
+               kfree(p_cache);
+               return ret;
+       }
+
+       kfree(p_cache);
+
+       return ret;
+}
+
+static int
+qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
+{
+       u32 dest, *p_cache;
+       u64 addr ;
+       u8 data[16] ;
+       size_t size ;
+       int i, ret = -EIO;
+
+       dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
+
+       size = (adapter->ahw->fw_info.fw->size & ~0xF);
+       p_cache = (u32 *)adapter->ahw->fw_info.fw->data;
+       addr = (u64)dest;
+
+       ret = qlcnic_83xx_ms_mem_write_128b(adapter, addr,
+                                       (u32 *)p_cache, size/16);
+       if (ret) {
+               dev_err(&adapter->pdev->dev, "MS memory write failed\n");
+               release_firmware(adapter->ahw->fw_info.fw);
+               adapter->ahw->fw_info.fw = NULL;
+               return -EIO;
+       }
+
+       /* Check 128 bit alignment  */
+       if (adapter->ahw->fw_info.fw->size & 0xF) {
+               addr = dest + size;
+               for (i = 0; i < (adapter->ahw->fw_info.fw->size & 0xF); i++)
+                       data[i] = adapter->ahw->fw_info.fw->data[size + i];
+
+               for (; i < 16 ; i++)
+                       data[i] = 0;
+
+               ret = qlcnic_83xx_ms_mem_write_128b(adapter, addr,
+                                                       (u32 *)data, 1);
+               if (ret) {
+                       dev_err(&adapter->pdev->dev,
+                                       "MS memory write failed\n");
+                       release_firmware(adapter->ahw->fw_info.fw);
+                       adapter->ahw->fw_info.fw = NULL;
+                       return -EIO;
+               }
+       }
+
+       release_firmware(adapter->ahw->fw_info.fw);
+       adapter->ahw->fw_info.fw = NULL;
+
+       return 0 ;
+}
+
+static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
+{
+       u32 val = 0, val1 = 0, reg = 0;
+       int i, j, err;
+       val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG, &err);
+       QLCDB(adapter, DRV, "SRE-Shim Ctrl:0x%x\n", val);
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       /* Port 0 RxB Pause Threshold Registers. */
+                       QLCDB(adapter, DRV,
+                               "Port 0 RxB Pause Threshold Registers[TC7..TC0]:");
+                       reg = QLC_83XX_PORT0_THRESHOLD;
+               } else if (j == 1) {
+                       /* Port 1 RxB Pause Threshold Registers. */
+                       QLCDB(adapter, DRV,
+                               "Port 1 RxB Pause Threshold Registers[TC7..TC0]:");
+                       reg = QLC_83XX_PORT1_THRESHOLD;
+               }
+               for (i = 0; i < 8; i++) {
+                       val = QLCRD32(adapter, reg + (i * 0x4), &err);
+                       QLCDB(adapter, DRV, "0x%x  ", val);
+               }
+               QLCDB(adapter, DRV, "\n");
+       }
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       /* Port 0 RxB Traffic Class Max Cell Registers. */
+                       QLCDB(adapter, DRV,
+                               "Port 0 RxB Traffic Class Max Cell Registers[4..1]:");
+                       reg = QLC_83XX_PORT0_TC_MC_REG;
+               } else if (j == 1) {
+                       /* Port 1 RxB Traffic Class Max Cell Registers. */
+                       QLCDB(adapter, DRV,
+                               "Port 1 RxB Traffic Class Max Cell Registers[4..1]:");
+                       reg = QLC_83XX_PORT1_TC_MC_REG;
+               }
+               for (i = 0; i < 4; i++) {
+                       val = QLCRD32(adapter, reg + (i * 0x4), &err);
+                       QLCDB(adapter, DRV, "0x%x  ", val);
+               }
+               QLCDB(adapter, DRV, "\n");
+       }
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       /* Port 0 RxB Rx Traffic Class Stats. */
+                       QLCDB(adapter, DRV,
+                               "Port 0 RxB Rx Traffic Class Stats[TC7..TC0]:");
+                       reg = QLC_83XX_PORT0_TC_STATS;
+               } else if (j == 1) {
+                       /* Port 1 RxB Rx Traffic Class Stats. */
+                       QLCDB(adapter, DRV,
+                               "Port 1 RxB Rx Traffic Class Stats[TC7..TC0]:");
+                       reg = QLC_83XX_PORT1_TC_STATS;
+               }
+               for (i = 7; i >= 0; i--) {
+                       val = QLCRD32(adapter, reg, &err);
+                       val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
+                       QLCWR32(adapter, reg, (val | (i << 29)));
+                       val = QLCRD32(adapter, reg, &err);
+                       QLCDB(adapter, DRV, "0x%x  ", val);
+               }
+               QLCDB(adapter, DRV, "\n");
+       }
+       val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, &err);
+       val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, &err);
+       QLCDB(adapter, DRV, "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
+               val, val1);
+}
+
+
+static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
+{
+       u32 reg = 0, i, j;
+
+       if (qlcnic_83xx_lock_driver(adapter)) {
+               netdev_err(adapter->netdev,
+                       "%s:failed to acquire driver lock\n", __func__);
+               return;
+       }
+
+       qlcnic_83xx_dump_pause_control_regs(adapter);
+
+       /* SRE-Shim Control Register */
+       QLCWR32(adapter, QLC_83XX_SRE_SHIM_REG, 0x0);
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       /* Port 0 RxB Pause Threshold Registers. */
+                       reg = QLC_83XX_PORT0_THRESHOLD;
+               } else if (j == 1) {
+                       /* Port 1 RxB Pause Threshold Registers. */
+                       reg = QLC_83XX_PORT1_THRESHOLD;
+               }
+               for (i = 0; i < 8; i++)
+                       QLCWR32(adapter, reg + (i * 0x4), 0x0);
+       }
+
+       for (j = 0; j < 2; j++) {
+               if (j == 0) {
+                       /* Port 0 RxB Traffic Class Max Cell Registers. */
+                       reg = QLC_83XX_PORT0_TC_MC_REG;
+               } else if (j == 1) {
+                       /* Port 1 RxB Traffic Class Max Cell Registers. */
+                       reg = QLC_83XX_PORT1_TC_MC_REG;
+               }
+               for (i = 0; i < 4; i++)
+                       QLCWR32(adapter, reg + (i * 0x4), 0x03FF03FF);
+       }
+
+       /* Port 2 IFB Pause Thresholds Register */
+       QLCWR32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, 0);
+       /* Port 3 IFB Pause Thresholds Register */
+       QLCWR32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, 0);
+       netdev_info(adapter->netdev,
+                       "Disabled pause frames successfully on all ports\n");
+
+       qlcnic_83xx_unlock_driver(adapter);
+}
+
+static int
+qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
+{
+       u32 heartbeat, peg_status;
+       int retries, err, ret = -EIO;
+       retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
+
+       p_dev->heartbeat = QLCRD(p_dev, QLCNIC_PEG_ALIVE_COUNTER);
+
+       do {
+               msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
+               heartbeat = QLCRD(p_dev, QLCNIC_PEG_ALIVE_COUNTER);
+               if (heartbeat != p_dev->heartbeat) {
+                       ret = QLCNIC_RCODE_SUCCESS;
+                       break;
+               }
+       } while (--retries);
+
+       if (ret) {
+               netdev_err(p_dev->netdev, "firmware hang detected\n");
+               qlcnic_83xx_disable_pause_frames(p_dev);
+               peg_status = QLCRD(p_dev, QLCNIC_PEG_HALT_STATUS1);
+               netdev_info(p_dev->netdev, "Dumping hw/fw registers\n"
+                       "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
+                       "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
+                       "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
+                       "PEG_NET_4_PC: 0x%x\n", peg_status,
+                       QLCRD(p_dev, QLCNIC_PEG_HALT_STATUS2),
+                       QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0, &err),
+                       QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1, &err),
+                       QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2, &err),
+                       QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3, &err),
+                       QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4, &err));
+
+               if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
+                       netdev_err(p_dev->netdev,
+                       "Firmware aborted with error code 0x00006700."
+                       "Device is being reset.\n");
+
+       }
+
+       return ret;
+}
+
+static int
+qlcnic_83xx_check_cmd_peg_status(struct qlcnic_adapter *p_dev)
+{
+       int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
+       u32 val;
+
+       do {
+               val = QLCRD(p_dev, QLCNIC_CMDPEG_STATE);
+               if (val == QLC_83xx_CMDPEG_COMPLETE)
+                       return 0;
+
+               msleep(QLCNIC_CMDPEG_CHECK_DELAY);
+       } while (--retries);
+
+       dev_err(&p_dev->pdev->dev, "%s: failed, state = 0x%x\n", __func__, val);
+       return -EIO;
+}
+
+int
+qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
+{
+       int err;
+
+       err = qlcnic_83xx_check_cmd_peg_status(p_dev);
+       if (err)
+               return err;
+
+       err = qlcnic_83xx_check_heartbeat(p_dev);
+       if (err)
+               return err;
+
+       return err;
+}
+
+static int
+qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr, int duration,
+                                               u32 test_mask, u32 test_result)
+{
+       u32 value;
+       int err, timeout_error;
+       u8 retries;
+
+       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr, &err);
+       if (err == -EIO)
+               return -EIO;
+
+       /* poll every 1/10 of the total duration */
+       retries = duration/10;
+
+       do {
+               if ((value & test_mask) != test_result) {
+                       timeout_error = 1;
+                       msleep(duration/10);
+                       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr, &err);
+                       if (err == -EIO)
+                               return -EIO;
+               } else {
+                       timeout_error = 0;
+                       break;
+               }
+       } while (retries--);
+
+       if (timeout_error) {
+               p_dev->ahw->reset.seq_error++ ;
+               dev_err(&p_dev->pdev->dev,
+                       "%s: 0x%08x 0x%08x 0x%08x\n",
+                               __func__, value, test_mask, test_result);
+       }
+
+       return timeout_error;
+}
+
+static int
+qlcnic_83xx_validate_reset_template_checksum(struct qlcnic_adapter *p_dev)
+{
+       u32 sum =  0;
+       u16 *buff = (u16 *)p_dev->ahw->reset.buff;
+       int count =  p_dev->ahw->reset.hdr->size / sizeof(u16);
+
+       while (count-- > 0)
+               sum += *buff++;
+
+       while (sum >> 16)
+               sum = (sum & 0xFFFF) +  (sum >> 16);
+
+       if (~sum) {
+               return 0;
+       } else {
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+               return -1;
+       }
+}
+
+static int
+qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
+{
+       u8 *p_buff;
+       u32 addr, u32_count;
+
+       p_dev->ahw->reset.seq_error = 0;
+       p_dev->ahw->reset.buff =
+                       kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
+
+       if (p_dev->ahw->reset.buff == NULL) {
+               dev_err(&p_dev->pdev->dev,
+                       "%s: resource allocation failed\n", __func__);
+               return -ENOMEM;
+       }
+
+       p_buff = p_dev->ahw->reset.buff;
+       addr = QLC_83XX_RESET_TEMPLATE_ADDR;
+
+       u32_count = sizeof(struct qlcnic_83xx_reset_template_hdr) / sizeof(u32);
+
+       /* Copy template header from flash */
+       if (qlcnic_83xx_flash_read_u32(p_dev, addr, p_buff, u32_count)) {
+               dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+               return -EIO;
+       }
+
+       p_dev->ahw->reset.hdr =
+        (struct qlcnic_83xx_reset_template_hdr *) p_dev->ahw->reset.buff;
+
+       addr = QLC_83XX_RESET_TEMPLATE_ADDR + p_dev->ahw->reset.hdr->hdr_size;
+       p_buff = p_dev->ahw->reset.buff + p_dev->ahw->reset.hdr->hdr_size;
+       u32_count = (p_dev->ahw->reset.hdr->size -
+                       p_dev->ahw->reset.hdr->hdr_size)/sizeof(u32);
+
+       /* Copy rest of the template */
+       if (qlcnic_83xx_flash_read_u32(p_dev, addr, p_buff, u32_count)) {
+               dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
+               return -EIO;
+       }
+
+       /* Integrity check */
+       if (qlcnic_83xx_validate_reset_template_checksum(p_dev))
+               return -EIO;
+
+       /* Get STOP, START, INIT sequence offsets */
+       p_dev->ahw->reset.init_offset = p_dev->ahw->reset.buff +
+                       p_dev->ahw->reset.hdr->init_seq_offset;
+
+       p_dev->ahw->reset.start_offset = p_dev->ahw->reset.buff +
+                       p_dev->ahw->reset.hdr->start_seq_offset;
+
+       p_dev->ahw->reset.stop_offset = p_dev->ahw->reset.buff +
+                       p_dev->ahw->reset.hdr->hdr_size;
+       return 0;
+}
+
+void
+qlcnic_83xx_free_reset_template(struct qlcnic_adapter *p_dev)
+{
+       kfree(p_dev->ahw->reset.buff);
+}
+
+static void
+qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev, u32 raddr,
+                                                       u32 waddr)
+{
+       int err, value;
+
+       value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr, &err);
+       if (err == -EIO)
+               return;
+
+       qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+}
+
+/* Read Modify Write CRB register. */
+static void
+qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
+                       u32 raddr, u32 waddr, struct qlcnic_83xx_rmw *p_rmw_hdr)
+{
+       int value, err;
+       if (p_rmw_hdr->index_a)
+               value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
+       else {
+               value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr, &err);
+               if (err == -EIO)
+                       return;
+       }
+
+       value &= p_rmw_hdr->test_mask;
+       value <<= p_rmw_hdr->shl;
+       value >>= p_rmw_hdr->shr;
+       value |= p_rmw_hdr->or_value;
+       value ^= p_rmw_hdr->xor_value;
+       qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
+       return;
+}
+
+static void
+qlcnic_83xx_write_list(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       int i;
+       struct qlcnic_83xx_entry *p_entry;
+
+       p_entry = (struct qlcnic_83xx_entry *)((char *)p_hdr +
+                               sizeof(struct qlcnic_83xx_reset_entry_hdr));
+
+       for (i = 0; i < p_hdr->count; i++, p_entry++) {
+               qlcnic_83xx_wrt_reg_indirect(p_dev, p_entry->arg1,
+                                               p_entry->arg2);
+               if (p_hdr->delay)
+                       udelay((u32)(p_hdr->delay));
+       }
+}
+
+static void
+qlcnic_83xx_read_write_list(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       int i;
+       struct qlcnic_83xx_entry *p_entry;
+
+       p_entry = (struct qlcnic_83xx_entry *)((char *)p_hdr +
+                               sizeof(struct qlcnic_83xx_reset_entry_hdr));
+
+       for (i = 0; i < p_hdr->count; i++, p_entry++) {
+               qlcnic_83xx_read_write_crb_reg(p_dev, p_entry->arg1,
+                                               p_entry->arg2);
+               if (p_hdr->delay)
+                       udelay((u32)(p_hdr->delay));
+       }
+}
+
+static void
+qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       long delay;
+       struct qlcnic_83xx_entry *p_entry;
+       struct qlcnic_83xx_poll *p_poll;
+       int i, err;
+
+       p_poll = (struct qlcnic_83xx_poll *)
+               ((char *)p_hdr + sizeof(struct qlcnic_83xx_reset_entry_hdr));
+
+       p_entry = (struct qlcnic_83xx_entry *)((char *)p_poll +
+                               sizeof(struct qlcnic_83xx_poll));
+
+       delay = (long)p_hdr->delay;
+
+       if (!delay) {
+               for (i = 0; i < p_hdr->count; i++, p_entry++) {
+                       qlcnic_83xx_poll_reg(p_dev, p_entry->arg1,
+                               delay, p_poll->test_mask, p_poll->test_value);
+               }
+       } else {
+               for (i = 0; i < p_hdr->count; i++, p_entry++) {
+                       if (delay) {
+                               if (qlcnic_83xx_poll_reg(p_dev,
+                                               p_entry->arg1, delay,
+                                               p_poll->test_mask,
+                                               p_poll->test_value)){
+                                       qlcnic_83xx_rd_reg_indirect(p_dev,
+                                                       p_entry->arg1, &err);
+                                       if (err == -EIO)
+                                               return;
+                                       qlcnic_83xx_rd_reg_indirect(p_dev,
+                                                       p_entry->arg2, &err);
+                                       if (err == -EIO)
+                                               return;
+
+                               dev_err(&p_dev->pdev->dev,
+                                       "Timeout Error: poll list ");
+                               dev_err(&p_dev->pdev->dev,
+                                       "item_num = %d entry_num = %d\n",
+                                       i, p_dev->ahw->reset.seq_index);
+                               }
+                       }
+               }
+       }
+}
+
+static void
+qlcnic_83xx_poll_write_list(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       long delay;
+       struct qlcnic_83xx_quad_entry *p_entry;
+       struct qlcnic_83xx_poll *p_poll;
+       int i;
+
+       p_poll = (struct qlcnic_83xx_poll *)((char *)p_hdr +
+                               sizeof(struct qlcnic_83xx_reset_entry_hdr));
+       p_entry = (struct qlcnic_83xx_quad_entry *)((char *)p_poll +
+                               sizeof(struct qlcnic_83xx_poll));
+
+       delay = (long)p_hdr->delay;
+
+       for (i = 0; i < p_hdr->count; i++, p_entry++) {
+               qlcnic_83xx_wrt_reg_indirect(p_dev,
+                       p_entry->dr_addr, p_entry->dr_value);
+               qlcnic_83xx_wrt_reg_indirect(p_dev,
+                       p_entry->ar_addr, p_entry->ar_value);
+               if (delay) {
+                       if (qlcnic_83xx_poll_reg(p_dev,
+                                               p_entry->ar_addr, delay,
+                                               p_poll->test_mask,
+                                               p_poll->test_value)){
+                               dev_err(&p_dev->pdev->dev,
+                                       "Timeout Error: poll list ");
+                               dev_err(&p_dev->pdev->dev,
+                                       "item_num = %d entry_num = %d\n",
+                                       i, p_dev->ahw->reset.seq_index);
+                       }
+               }
+       }
+}
+
+static void
+qlcnic_83xx_read_modify_write(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       struct qlcnic_83xx_entry *p_entry;
+       struct qlcnic_83xx_rmw *p_rmw_hdr;
+       int i;
+
+       p_rmw_hdr = (struct qlcnic_83xx_rmw *)((char *)p_hdr +
+                               sizeof(struct qlcnic_83xx_reset_entry_hdr));
+
+       p_entry = (struct qlcnic_83xx_entry *)((char *)p_rmw_hdr +
+                                       sizeof(struct qlcnic_83xx_rmw));
+
+       for (i = 0; i < p_hdr->count; i++, p_entry++) {
+               qlcnic_83xx_rmw_crb_reg(p_dev, p_entry->arg1,
+                                       p_entry->arg2, p_rmw_hdr);
+               if (p_hdr->delay)
+                       udelay((u32)(p_hdr->delay));
+       }
+}
+
+static void
+qlcnic_83xx_pause(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       if (p_hdr->delay)
+               mdelay((u32)((long)p_hdr->delay));
+}
+
+static void
+qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       long delay;
+       int index, i, err;
+       struct qlcnic_83xx_quad_entry *p_entry;
+       struct qlcnic_83xx_poll *p_poll;
+
+       p_poll = (struct qlcnic_83xx_poll *)
+               ((char *)p_hdr + sizeof(struct qlcnic_83xx_reset_entry_hdr));
+
+       p_entry = (struct qlcnic_83xx_quad_entry *)
+               ((char *)p_poll + sizeof(struct qlcnic_83xx_poll));
+
+       delay = (long)p_hdr->delay;
+
+       for (i = 0; i < p_hdr->count; i++, p_entry++) {
+               qlcnic_83xx_wrt_reg_indirect(p_dev, p_entry->ar_addr,
+                                               p_entry->ar_value);
+               if (delay) {
+                       if (qlcnic_83xx_poll_reg(p_dev, p_entry->ar_addr, delay,
+                               p_poll->test_mask, p_poll->test_value)){
+                               dev_err(&p_dev->pdev->dev,
+                                               "Timeout Error: poll list");
+                               dev_err(&p_dev->pdev->dev,
+                                       "item_num = %d entry_num = %d\n", i,
+                                               p_dev->ahw->reset.seq_index);
+                       } else {
+                               index = p_dev->ahw->reset.array_index;
+                               p_dev->ahw->reset.array[index++] =
+                                       qlcnic_83xx_rd_reg_indirect(p_dev,
+                                                       p_entry->dr_addr, &err);
+                               if (err == -EIO)
+                                       return;
+                               if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
+                                       p_dev->ahw->reset.array_index = 1;
+                       }
+               }
+       }
+}
+
+static inline void
+qlcnic_83xx_seq_end(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       p_dev->ahw->reset.seq_end = 1;
+}
+
+static void
+qlcnic_83xx_template_end(struct qlcnic_adapter *p_dev,
+                       struct qlcnic_83xx_reset_entry_hdr  *p_hdr)
+{
+       p_dev->ahw->reset.template_end = 1;
+
+       if (p_dev->ahw->reset.seq_error == 0)
+               dev_err(&p_dev->pdev->dev,
+                       "HW restart process completed successfully.\n");
+       else
+               dev_err(&p_dev->pdev->dev,
+                       "HW restart completed with timeout errors.\n");
+}
+
+static void
+qlcnic_83xx_execute_template_instructions(struct qlcnic_adapter *p_dev,
+                                                               char *p_buff)
+{
+       int index, entries;
+       struct qlcnic_83xx_reset_entry_hdr  *p_hdr;
+       char *p_entry = p_buff;
+
+       p_dev->ahw->reset.seq_end = 0;
+       p_dev->ahw->reset.template_end = 0;
+       entries = p_dev->ahw->reset.hdr->entries;
+       index = p_dev->ahw->reset.seq_index;
+
+       for ( ; (!p_dev->ahw->reset.seq_end) && (index  < entries); index++) {
+
+               p_hdr = (struct qlcnic_83xx_reset_entry_hdr *)p_entry;
+
+               switch (p_hdr->cmd) {
+               case OPCODE_NOP:
+                       break;
+               case OPCODE_WRITE_LIST:
+                       qlcnic_83xx_write_list(p_dev, p_hdr);
+                       break;
+               case OPCODE_READ_WRITE_LIST:
+                       qlcnic_83xx_read_write_list(p_dev, p_hdr);
+                       break;
+               case OPCODE_POLL_LIST:
+                       qlcnic_83xx_poll_list(p_dev, p_hdr);
+                       break;
+               case OPCODE_POLL_WRITE_LIST:
+                       qlcnic_83xx_poll_write_list(p_dev, p_hdr);
+                       break;
+               case OPCODE_READ_MODIFY_WRITE:
+                       qlcnic_83xx_read_modify_write(p_dev, p_hdr);
+                       break;
+               case OPCODE_SEQ_PAUSE:
+                       qlcnic_83xx_pause(p_dev, p_hdr);
+                       break;
+               case OPCODE_SEQ_END:
+                       qlcnic_83xx_seq_end(p_dev, p_hdr);
+                       break;
+               case OPCODE_TMPL_END:
+                       qlcnic_83xx_template_end(p_dev, p_hdr);
+                       break;
+               case OPCODE_POLL_READ_LIST:
+                       qlcnic_83xx_poll_read_list(p_dev, p_hdr);
+                       break;
+               default:
+                       dev_err(&p_dev->pdev->dev,
+                       "%s: Unknown opcode 0x%04x in template entry %d\n",
+                                               __func__, p_hdr->cmd, index);
+                       break;
+               }
+
+               /* Set pointer to next entry in the sequence. */
+               p_entry += p_hdr->size;
+       }
+
+       p_dev->ahw->reset.seq_index = index;
+}
+
+static void
+qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
+{
+       p_dev->ahw->reset.seq_index = 0;
+       qlcnic_83xx_execute_template_instructions(p_dev,
+                       p_dev->ahw->reset.stop_offset);
+
+       if (p_dev->ahw->reset.seq_end != 1)
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void
+qlcnic_83xx_start_hw(struct qlcnic_adapter *p_dev)
+{
+       qlcnic_83xx_execute_template_instructions(p_dev,
+                       p_dev->ahw->reset.start_offset);
+
+       if (p_dev->ahw->reset.template_end != 1)
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static void
+qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
+{
+       qlcnic_83xx_execute_template_instructions(p_dev,
+                       p_dev->ahw->reset.init_offset);
+
+       if (p_dev->ahw->reset.seq_end != 1)
+               dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
+}
+
+static int
+qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       int err = -EIO;
+
+       qlcnic_83xx_stop_hw(adapter);
+
+       /* Collect FW register dump if required */
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+       if (!(val & QLC_83XX_IDC_GRACEFULL_RESET) &&
+           test_bit(__QLCNIC_RESETTING, &adapter->state))
+               qlcnic_dump_fw(adapter);
+
+       qlcnic_83xx_init_hw(adapter);
+       if (qlcnic_83xx_copy_bootloader(adapter))
+               return err;
+       /* Boot either flash image or firmware image from host file system */
+       if (load_fw_file) {
+               if (request_firmware(&adapter->ahw->fw_info.fw,
+                               QLC_83XX_FW_FILE_NAME, &(adapter->pdev->dev))) {
+                       dev_err(&adapter->pdev->dev,
+                               "No file FW image, loading flash FW image.\n");
+                       QLCWR(adapter, QLCNIC_FW_IMG_VALID,
+                                       QLC_83XX_BOOT_FROM_FLASH);
+               } else {
+                       if (qlcnic_83xx_copy_fw_file(adapter))
+                               return err;
+                       QLCWR(adapter, QLCNIC_FW_IMG_VALID,
+                                       QLC_83XX_BOOT_FROM_FILE);
+               }
+       } else {
+               QLCWR(adapter, QLCNIC_FW_IMG_VALID, QLC_83XX_BOOT_FROM_FLASH);
+       }
+       qlcnic_83xx_start_hw(adapter);
+       if (qlcnic_83xx_check_hw_status(adapter))
+               return -EIO;
+
+       return 0;
+}
+
+/**
+* qlcnic_83xx_config_default_opmode
+*
+* @adapter: adapter structure
+*
+* Returns:
+* None
+* */
+static int
+qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *adapter)
+{
+       u32 op_mode;
+       struct pci_dev *pdev = adapter->pdev;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       ahw->hw_ops->get_func_no(adapter);
+       op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+       if (op_mode == QLC_83XX_DEFAULT_OPMODE) {
+               dev_info(&pdev->dev, "Default opmode %d\n", adapter->ahw->op_mode);
+               adapter->nic_ops->init_driver = qlcnic_83xx_init_driver;
+               adapter->ahw->idc.ready_state_entry_action =
+                               qlcnic_83xx_idc_ready_state_entry_action;
+       } else {
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static inline int
+qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+
+       if ((val & 0xFFFF))
+               return 1;
+       else
+               return 0;
+}
+
+static inline void
+qlcnic_83xx_idc_log_state_history(struct qlcnic_adapter *adapter)
+{
+       u32 cur, prev;
+       cur = adapter->ahw->idc.curr_state;
+       prev = adapter->ahw->idc.prev_state;
+
+       netdev_info(adapter->netdev,
+               "current state  = %s,  prev state = %s\n",
+                       adapter->ahw->idc.name[cur],
+                               adapter->ahw->idc.name[prev]);
+}
+
+static int
+qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter *adapter, u8 mode,
+                                                               int lock)
+{
+       u32 val;
+       int seconds;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = adapter->portnum & 0xf;
+       val |= mode << 7;
+       if (mode)
+               seconds = jiffies/HZ - adapter->ahw->idc.sec_counter;
+       else
+               seconds = jiffies/HZ;
+
+       val |= seconds << 8;
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT, val);
+       adapter->ahw->idc.sec_counter = jiffies/HZ;
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static inline void
+qlcnic_83xx_idc_update_minor_version(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION);
+       val = val & ~(0x3 << (adapter->portnum * 2));
+       val = val | (QLC_83XX_IDC_MINOR_VERSION << (adapter->portnum * 2));
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_MIN_VERSION, val);
+}
+
+static inline int
+qlcnic_83xx_idc_update_major_version(struct qlcnic_adapter *adapter, int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+       val = val & ~0xFF;
+       val = val | QLC_83XX_IDC_MAJOR_VERSION;
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION, val);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_idc_update_drv_presence_reg(struct qlcnic_adapter *adapter,
+                                               int status, int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+
+       if (status)
+               val = val | (1 << adapter->portnum);
+       else
+               val = val & ~(1 << adapter->portnum);
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+
+       qlcnic_83xx_idc_update_minor_version(adapter);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static inline int
+qlcnic_83xx_idc_check_major_version(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       u8 version;
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_MAJ_VERSION);
+       version = val & 0xFF;
+
+       if (version != QLC_83XX_IDC_MAJOR_VERSION) {
+               netdev_info(adapter->netdev,
+                       "%s: mismatch. version 0x%x, expected version 0x%x\n",
+                                __func__, version, QLC_83XX_IDC_MAJOR_VERSION);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_idc_clear_registers(struct qlcnic_adapter *adapter, int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, 0);
+       /* Clear gracefull reset bit */
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+       val &= ~QLC_83XX_IDC_GRACEFULL_RESET;
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_update_drv_ack_reg
+ *
+ * @adapter: adapter structure
+ * @flag: control set or clear operation
+ *
+ * Clear or set bit corresponding to function ID in ACK register
+ *
+ *
+ * Returns: None
+ **/
+static int
+qlcnic_83xx_idc_update_drv_ack_reg(struct qlcnic_adapter *adapter,
+                                               int flag, int lock)
+{
+       u32 val;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+       if (flag)
+               val = val | (1 << adapter->portnum);
+       else
+               val = val & ~(1 << adapter->portnum);
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_ACK, val);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_check_timeout
+ *
+ *  @adapter: adapter structure
+ *  @time_limit: max time limit value
+ *
+ *  Returns -EBUSY if time exceeds max limit, else 0
+ *
+ **/
+static inline int
+qlcnic_83xx_idc_check_timeout(struct qlcnic_adapter *adapter, int time_limit)
+{
+       u64 seconds;
+
+       seconds = jiffies/HZ - adapter->ahw->idc.sec_counter;
+       if (seconds <= time_limit)
+               return 0;
+       else
+               return -EBUSY;
+}
+
+/**
+ * qlcnic_83xx_idc_check_reset_ack_reg
+ *
+ * @adapter: adapter structure
+ *
+ * Return 0 if all functions have acknowledged the reset request.
+ * Check ACK wait limit and clear the functions which failed to ACK
+ *
+ **/
+static int
+qlcnic_83xx_idc_check_reset_ack_reg(struct qlcnic_adapter *adapter)
+{
+       u32 ack, presence, val;
+
+       ack = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_ACK);
+       presence = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+       dev_info(&adapter->pdev->dev,
+               "%s: ack = 0x%x, presence = 0x%x\n", __func__, ack, presence);
+       if (!((ack & presence) == presence)) {
+               if (qlcnic_83xx_idc_check_timeout(adapter,
+                       QLC_83XX_IDC_RESET_TIMEOUT_SECS)) {
+                       /* Clear functions which failed to ACK */
+                       dev_info(&adapter->pdev->dev,
+                               "%s: ACK wait exceeds time limit\n", __func__);
+                       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+                       val = val & ~(ack^presence);
+                       if (qlcnic_83xx_lock_driver(adapter))
+                               return -EBUSY;
+                       QLCWRX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE, val);
+                       dev_info(&adapter->pdev->dev,
+                               "%s: updated drv presence reg = 0x%x\n",
+                                                       __func__, val);
+                       qlcnic_83xx_unlock_driver(adapter);
+                       return 0;
+
+               } else {
+                       return 1;
+               }
+       } else {
+               netdev_info(adapter->netdev,
+                       "%s: Reset ACK received from all functions\n",
+                                                               __func__);
+               return 0;
+       }
+}
+
+/**
+ * qlcnic_83xx_idc_tx_soft_reset
+ *
+ * @adapter: adapter structure
+ *
+ * Handle context deletion and recreation request from transmit routine
+ *
+ * Returns -EBUSY  or SUCCESS (0)
+ *
+ **/
+static int
+qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               return -EBUSY;
+
+       netif_device_detach(netdev);
+       qlcnic_down(adapter, netdev);
+       qlcnic_up(adapter, netdev);
+       netif_device_attach(netdev);
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       dev_err(&adapter->pdev->dev, "%s:\n", __func__);
+
+       adapter->netdev->trans_start = jiffies;
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_detach_driver
+ *
+ * @adapter: adapter structure
+ * Detach net interface, stop TX and cleanup resources before the HW reset.
+ * Returns:
+ *
+ **/
+static void
+qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter)
+{
+       int i;
+
+       struct net_device *netdev = adapter->netdev;
+
+       netif_device_detach(netdev);
+       /* Disable mailbox interrupt */
+       QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0);
+       qlcnic_down(adapter, netdev);
+       for (i = 0; i < adapter->ahw->num_msix; i++) {
+                       adapter->ahw->intr_tbl[i].id = i;
+                       adapter->ahw->intr_tbl[i].enabled = 0;
+                       adapter->ahw->intr_tbl[i].src = 0;
+       }
+}
+
+/**
+ * qlcnic_83xx_idc_attach_driver
+ *
+ * @adapter: adapter structure
+ *
+ * Re-attach and re-enable net interface
+ * Returns:
+ *
+ **/
+static void
+qlcnic_83xx_idc_attach_driver(struct qlcnic_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+
+       if (netif_running(netdev)) {
+               if (qlcnic_up(adapter, netdev))
+                       goto done;
+
+               qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+       }
+done:
+       netif_device_attach(netdev);
+       if (netif_running(netdev)) {
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
+       }
+}
+
+static int
+qlcnic_83xx_idc_enter_failed_state(struct qlcnic_adapter *adapter,
+                                                        int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       qlcnic_83xx_idc_clear_registers(adapter, 0);
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+                                       QLC_83XX_IDC_DEV_FAILED);
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_FAILED;
+
+       qlcnic_83xx_idc_log_state_history(adapter);
+       netdev_info(adapter->netdev, "Device will enter failed state\n");
+
+       return 0;
+}
+
+static inline int
+qlcnic_83xx_idc_enter_cold_state(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_COLD);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static inline int
+qlcnic_83xx_idc_enter_init_state(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE, QLC_83XX_IDC_DEV_INIT);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static inline int
+qlcnic_83xx_idc_enter_need_quiscent(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+                               QLC_83XX_IDC_DEV_NEED_QUISCENT);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static inline int
+qlcnic_83xx_idc_enter_need_reset_state(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+                               QLC_83XX_IDC_DEV_NEED_RESET);
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static inline int
+qlcnic_83xx_idc_enter_ready_state(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+                               QLC_83XX_IDC_DEV_READY);
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_info nic_info;
+       int err;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       memset(&nic_info, 0, sizeof(struct qlcnic_info));
+
+       err = ahw->hw_ops->get_nic_info(adapter, &nic_info, ahw->pci_func);
+       if (err)
+               return -EIO;
+
+       ahw->physical_port = (u8) nic_info.phys_port;
+       ahw->switch_mode = nic_info.switch_mode;
+       ahw->max_tx_ques = nic_info.max_tx_ques;
+       ahw->max_rx_ques = nic_info.max_rx_ques;
+       ahw->capabilities = nic_info.capabilities;
+       ahw->max_mac_filters = nic_info.max_mac_filters;
+       ahw->max_mtu = nic_info.max_mtu;
+
+       if (ahw->capabilities & BIT_23)
+               ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE;
+       else
+               ahw->nic_mode = QLC_83XX_DEFAULT_MODE;
+
+       return ahw->nic_mode;
+}
+
+/**
+ * qlcnic_83xx_idc_find_reset_owner_id
+ *
+ * @adapter: adapter structure
+ *
+ * NIC gets precedence over ISCSI and ISCSI has precedence over FCOE.
+ * Within the same class, function with lowest PCI ID assumes ownership
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_find_reset_owner_id(struct qlcnic_adapter *adapter)
+{
+       u32 reg, reg1, reg2, i, j, owner, class;
+
+       reg1 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_1);
+       reg2 = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_PARTITION_INFO_2);
+       owner = QLCNIC_TYPE_NIC;
+       i = 0;
+       j = 0;
+       reg = reg1;
+
+       do {
+               class = (((reg & (0xF << j*4)) >> j*4) & 0x3);
+               if (class == owner)
+                       break;
+               if (i == (QLC_83XX_IDC_MAX_FUNC_PER_PARTITION_INFO - 1)) {
+                       reg = reg2;
+                       j = 0;
+               } else {
+                       j++;
+               }
+
+               if (i == (QLC_83XX_IDC_MAX_CNA_FUNCTIONS - 1)) {
+                       if (owner == QLCNIC_TYPE_NIC)
+                               owner = QLCNIC_TYPE_ISCSI;
+                       else if (owner == QLCNIC_TYPE_ISCSI)
+                               owner = QLCNIC_TYPE_FCOE;
+                       else if (owner == QLCNIC_TYPE_FCOE)
+                               return -EIO;
+
+                       reg = reg1;
+                       j = 0;
+                       i = 0;
+               }
+
+       } while (i < QLC_83XX_IDC_MAX_CNA_FUNCTIONS);
+
+       return i;
+}
+
+static int
+qlcnic_83xx_idc_restart_hw(struct qlcnic_adapter *adapter, int lock)
+{
+       int ret = 0;
+
+       ret = qlcnic_83xx_restart_hw(adapter);
+
+       if (ret) {
+               qlcnic_83xx_idc_enter_failed_state(adapter, lock);
+       } else {
+               qlcnic_83xx_idc_clear_registers(adapter, lock);
+               ret = qlcnic_83xx_idc_enter_ready_state(adapter, lock);
+       }
+
+       return ret;
+}
+
+static int
+qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
+{
+       int ret;
+
+       ret = qlcnic_83xx_get_nic_configuration(adapter);
+       if (ret == -EIO)
+               return -EIO;
+
+       if (ret == QLC_83XX_VIRTUAL_NIC_MODE) {
+               if (qlcnic_83xx_config_vnic_opmode(adapter))
+                       return -EIO;
+       } else if (ret == QLC_83XX_DEFAULT_MODE) {
+               if (qlcnic_83xx_config_default_opmode(adapter))
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter)
+{
+       u32 status;
+
+       status = QLCRD(adapter, QLCNIC_PEG_HALT_STATUS1);
+
+       if (status & QLCNIC_RCODE_FATAL_ERROR) {
+               dev_err(&adapter->pdev->dev,
+                       "peg halt status1=0x%x\n", status);
+               if (QLCNIC_FWERROR_CODE(status) ==
+                                       QLCNIC_FWERROR_FAN_FAILURE) {
+                       dev_err(&adapter->pdev->dev,
+                               "On board active cooling fan failed. "
+                               "Device has been halted.\n");
+                       dev_err(&adapter->pdev->dev,
+                               "Replace the adapter.\n");
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+int
+qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
+{
+       /* register for NIC IDC AEN Events */
+       qlcnic_83xx_register_nic_idc_func(adapter, 1);
+
+       qlcnic_83xx_enable_mbx_intrpt(adapter);
+       if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+               if (qlcnic_83xx_config_intrpt(adapter, 1)) {
+                       netdev_err(adapter->netdev,
+                               "Failed to enable mbx intr\n");
+                       return -EIO;
+               }
+       }
+
+       if (qlcnic_83xx_configure_opmode(adapter)) {
+               qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+                       return -EIO;
+       }
+
+       if (adapter->nic_ops->init_driver(adapter)) {
+               qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+               return -EIO;
+       }
+
+       qlcnic_83xx_idc_attach_driver(adapter);
+
+       return 0;
+}
+
+static void
+qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
+{
+       qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1);
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+       qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+       set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+       adapter->ahw->idc.quiesce_req = 0;
+       adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+       adapter->ahw->idc.err_code = 0;
+       adapter->ahw->idc.collect_dump = 0;
+
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state_entry_action
+ *
+ * @adapter: adapter structure
+ *
+ * Perform ready state initialization, this routine will get invoked only
+ * once from READY state.
+ *
+ * Returns: -EIO or 0
+ *
+ **/
+int
+qlcnic_83xx_idc_ready_state_entry_action(struct qlcnic_adapter *adapter)
+{
+       if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY) {
+               qlcnic_83xx_idc_update_idc_params(adapter);
+               /* Re-attach the device if required */
+               if ((adapter->ahw->idc.prev_state ==
+                               QLC_83XX_IDC_DEV_NEED_RESET) ||
+                       (adapter->ahw->idc.prev_state ==
+                                       QLC_83XX_IDC_DEV_INIT)) {
+                       if (qlcnic_83xx_idc_reattach_driver(adapter))
+                               return -EIO;
+               }
+       }
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_vnic_pf_ready_state_entry_action
+ *
+ * @adapter: adapter structure
+ *
+ * Ensure vNIC mode privileged function becomes ready only when vNIC mode is
+ * set ready by vNIC management function.
+ * If vNIC mode is ready, perform ready state initialization.
+ *
+ * Returns: -EIO or 0
+ *
+ **/
+int
+qlcnic_83xx_idc_vnic_pf_ready_state_entry_action(struct qlcnic_adapter *adapter)
+{
+       u32 state;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Privileged function waits till mgmt function enables VNIC mode */
+       state = QLCRDX(adapter->ahw, QLC_83XX_VNIC_STATE);
+       if (state != QLCNIC_DEV_NPAR_OPER) {
+               if (!ahw->idc.vnic_wait_limit--) {
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+                       return -EIO;
+               }
+
+               netdev_info(adapter->netdev, "vNIC mode disabled\n");
+               return 0;
+
+       } else {
+               /* Perform one time initialization from ready state */
+               if (adapter->ahw->idc.vnic_state != QLCNIC_DEV_NPAR_OPER) {
+                       qlcnic_83xx_idc_update_idc_params(adapter);
+
+                       /* If the previous state is UNKNOWN, device will be
+                          already attached properly */
+                       if (adapter->ahw->idc.prev_state !=
+                                               QLC_83XX_IDC_DEV_UNKNOWN) {
+                               if (qlcnic_83xx_idc_reattach_driver(adapter))
+                                       return -EIO;
+                       }
+
+                       adapter->ahw->idc.vnic_state =  QLCNIC_DEV_NPAR_OPER;
+                       netdev_info(adapter->netdev, "vNIC mode enabled\n");
+               }
+       }
+
+       return 0;
+}
+
+static int
+qlcnic_83xx_idc_unknown_state_handler(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->idc.err_code = -EIO;
+       dev_err(&adapter->pdev->dev,
+                       "%s: Device in unknown state\n", __func__);
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_cold_state_handler
+ *
+ * @adapter: adapter structure
+ *
+ * If HW is up and running device will enter READY state.
+ * If host file system based firmware image needs to be loaded, device is
+ * forced to start with the file firmware image.
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_cold_state_handler(struct qlcnic_adapter *adapter)
+{
+       qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 0);
+       qlcnic_83xx_idc_update_audit_reg(adapter, 1, 0);
+       if (load_fw_file) {
+               qlcnic_83xx_idc_restart_hw(adapter, 0);
+       } else {
+               if (qlcnic_83xx_check_hw_status(adapter)) {
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 0);
+                       return -EIO;
+               } else {
+                       qlcnic_83xx_idc_enter_ready_state(adapter, 0);
+               }
+       }
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_init_state_handler
+ *
+ * @adapter: adapter structure
+ *
+ * Reset owner will restart the device from this state.
+ * Device will enter failed state if it remains
+ * in this state for more than DEV_INIT time limit.
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_init_state_handler(struct qlcnic_adapter *adapter)
+{
+       int ret = 0;
+       u32 owner;
+
+       if (adapter->ahw->idc.prev_state == QLC_83XX_IDC_DEV_NEED_RESET) {
+               owner = qlcnic_83xx_idc_find_reset_owner_id(adapter);
+               if (adapter->ahw->pci_func == owner)
+                       qlcnic_83xx_idc_restart_hw(adapter, 1);
+       } else {
+               qlcnic_83xx_idc_check_timeout(adapter,
+                               QLC_83XX_IDC_INIT_TIMEOUT_SECS);
+               return ret;
+       }
+
+       return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_ready_state_handler
+ *
+ * @adapter: adapter structure
+ *
+ * Perform IDC protocol specicifed actions after monitoring device temperature,
+ * FW status, reset and quiesce requests.
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_ready_state_handler(struct qlcnic_adapter *adapter)
+{
+       u32 val;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int ret = 0;
+
+       /* Perform NIC configuration based ready state entry actions */
+       if (ahw->idc.ready_state_entry_action(adapter))
+               return -EIO;
+
+       /* Check temperature */
+       if (qlcnic_check_temp(adapter)) {
+               if (adapter->ahw->temp == QLCNIC_TEMP_PANIC) {
+                       qlcnic_83xx_idc_check_fan_failure(adapter);
+                       dev_err(&adapter->pdev->dev,
+                               "Error: device temperature %d above limits\n",
+                                                       adapter->ahw->temp);
+                       clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+                       set_bit(__QLCNIC_RESETTING, &adapter->state);
+                       qlcnic_83xx_idc_detach_driver(adapter);
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+                       return -EIO;
+               }
+       }
+
+       val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+
+       /* Check FW hearbeat */
+       ret = qlcnic_83xx_check_heartbeat(adapter);
+       if (ret) {
+               adapter->flags |= QLCNIC_FW_HANG;
+               if (!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+                       clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+                       set_bit(__QLCNIC_RESETTING, &adapter->state);
+                       qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+                       return 0;
+               } else {
+                       clear_bit(QLC_83XX_MBX_READY,
+                                 &adapter->ahw->idc.status);
+                       qlcnic_83xx_idc_enter_failed_state(adapter, 1);
+                       return -EIO;
+               }
+       }
+
+       if ((val & QLC_83XX_IDC_GRACEFULL_RESET) ||
+                               adapter->ahw->idc.collect_dump) {
+               /* Move to need reset state and prepare for reset */
+               qlcnic_83xx_idc_enter_need_reset_state(adapter, 1);
+               return  ret;
+
+       }
+
+       /* Check for soft reset request */
+       if (adapter->ahw->reset_context &&
+                       !(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+               qlcnic_83xx_idc_tx_soft_reset(adapter);
+               return  ret;
+       }
+
+       /* Move to need quiesce state if requested */
+       if (adapter->ahw->idc.quiesce_req) {
+               qlcnic_83xx_idc_enter_need_quiscent(adapter, 1);
+               qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+               return  ret;
+       }
+
+       return ret;
+}
+
+/**
+ * qlcnic_83xx_idc_need_reset_state_handler
+ *
+ * @adapter: adapter structure
+ *
+ * Device will remain in this state until:
+ *     Reset request ACK's are recieved from all the functions
+ *     Wait time exceeds max time limit
+ *
+ * Source States:
+ * Destination States:
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_need_reset_state_handler(struct qlcnic_adapter *adapter)
+{
+       int ret = 0;
+
+       if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
+               qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+               qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+               set_bit(__QLCNIC_RESETTING, &adapter->state);
+               clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+               if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
+                       qlcnic_83xx_set_vnic_non_operational(adapter, 1);
+               qlcnic_83xx_idc_detach_driver(adapter);
+       }
+
+       /* Check ACK from other functions */
+       ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
+       if (ret) {
+               dev_info(&adapter->pdev->dev,
+                       "%s: Waiting for reset ACK\n", __func__);
+               return 0;
+       }
+
+       /* Transit to INIT state and restart the HW */
+       qlcnic_83xx_idc_enter_init_state(adapter, 1);
+
+       return  ret;
+}
+
+/**
+ * qlcnic_83xx_idc_need_quiesce_state_handler
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_need_quiesce_state_handler(struct qlcnic_adapter *adapter)
+{
+       dev_err(&adapter->pdev->dev, "%s: TBD\n", __func__);
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_failed_state_handler
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_failed_state_handler(struct qlcnic_adapter *adapter)
+{
+       dev_err(&adapter->pdev->dev,
+               "%s: please reboot!!\n", __func__);
+       adapter->ahw->idc.err_code = -EIO;
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_quiesce_state_handler
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_quiesce_state_handler(struct qlcnic_adapter *adapter)
+{
+       dev_info(&adapter->pdev->dev,
+               "%s: TBD\n", __func__);
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_check_dev_state_validity
+ *
+ * @adapter: adapter structure
+ * @state: IDC destination state
+ *
+ * Ensure state transitions are according to the IDC protocol.
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_idc_check_dev_state_validity(struct qlcnic_adapter *adapter,
+                                                               u32 state)
+{
+       u32 cur, prev, next;
+
+       cur = adapter->ahw->idc.curr_state;
+       prev = adapter->ahw->idc.prev_state;
+       next = state;
+
+       if ((next < QLC_83XX_IDC_DEV_COLD) ||
+               (next > QLC_83XX_IDC_DEV_QUISCENT)) {
+               netdev_err(adapter->netdev,
+                       "%s: curr %d, prev %d, next state %d is  invalid\n",
+                                               __func__, cur, prev, state);
+               return 1;
+       }
+
+       if ((cur == QLC_83XX_IDC_DEV_UNKNOWN) &&
+               (prev == QLC_83XX_IDC_DEV_UNKNOWN)) {
+               if ((next != QLC_83XX_IDC_DEV_COLD) &&
+                               (next != QLC_83XX_IDC_DEV_READY)) {
+                       dev_err(&adapter->pdev->dev,
+                       "%s: invalid transition, cur %d prev %d next %d\n",
+                                       __func__, cur, prev, next);
+                       return 1;
+               }
+       }
+
+       if (next == QLC_83XX_IDC_DEV_INIT) {
+               if ((prev != QLC_83XX_IDC_DEV_INIT) &&
+                       (prev != QLC_83XX_IDC_DEV_COLD) &&
+                       (prev != QLC_83XX_IDC_DEV_NEED_RESET)) {
+                       dev_err(&adapter->pdev->dev,
+                       "%s: invalid transition, cur %d prev %d next %d\n",
+                                       __func__, cur, prev, next);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/**
+  * qlcnic_83xx_periodic_tasks
+  *
+  * @adapter: adapter structure
+  *
+  * Used for periodic tasks invocation
+  *
+  * Returns: None
+  *
+  **/
+
+static void
+qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
+{
+       if (adapter->fhash.fnum)
+               qlcnic_prune_lb_filters(adapter);
+}
+
+/**
+ * qlcnic_83xx_idc_poll_dev_state
+ *
+ * @work: kernel work queue structure used to schedule the function
+ *
+ * Poll device state periodically and perform state specific
+ * actions defined by Inter Driver Communication (IDC) protocol.
+ *
+ * Returns: None
+ *
+ **/
+static void
+qlcnic_83xx_idc_poll_dev_state(struct work_struct *work)
+{
+       struct qlcnic_adapter *adapter;
+       u32 state;
+
+       adapter = container_of(work, struct qlcnic_adapter, fw_work.work);
+
+       state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+
+       if (qlcnic_83xx_idc_check_dev_state_validity(adapter, state)) {
+               qlcnic_83xx_idc_log_state_history(adapter);
+               adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+       } else {
+               adapter->ahw->idc.curr_state = state;
+       }
+
+       switch (adapter->ahw->idc.curr_state) {
+       case QLC_83XX_IDC_DEV_READY:
+               qlcnic_83xx_idc_ready_state_handler(adapter);
+               break;
+
+       case QLC_83XX_IDC_DEV_NEED_RESET:
+               qlcnic_83xx_idc_need_reset_state_handler(adapter);
+               break;
+
+       case QLC_83XX_IDC_DEV_NEED_QUISCENT:
+               qlcnic_83xx_idc_need_quiesce_state_handler(adapter);
+               break;
+
+       case QLC_83XX_IDC_DEV_FAILED:
+               qlcnic_83xx_idc_failed_state_handler(adapter);
+               return;
+
+       case QLC_83XX_IDC_DEV_INIT:
+               qlcnic_83xx_idc_init_state_handler(adapter);
+               break;
+
+       case QLC_83XX_IDC_DEV_QUISCENT:
+               qlcnic_83xx_idc_quiesce_state_handler(adapter);
+               break;
+
+       default:
+               qlcnic_83xx_idc_unknown_state_handler(adapter);
+               return;
+       }
+
+       adapter->ahw->idc.prev_state = adapter->ahw->idc.curr_state;
+
+       qlcnic_83xx_periodic_tasks(adapter);
+
+       /* Re-schedule the function */
+       if (test_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status))
+               qlcnic_schedule_work(adapter, qlcnic_83xx_idc_poll_dev_state,
+                                               adapter->ahw->idc.delay);
+}
+
+static void
+qlcnic_83xx_setup_idc_parameters(struct qlcnic_adapter *adapter)
+{
+       u32 idc_params, val;
+
+       if (qlcnic_83xx_lockless_flash_read_u32(adapter,
+                       QLC_83XX_IDC_FLASH_PARAM_ADDR,
+                                       (u8 *)&idc_params, 1)) {
+               netdev_info(adapter->netdev,
+                       "%s: failed to get IDC params from flash.\n", __func__);
+               adapter->dev_init_timeo = QLC_83XX_IDC_INIT_TIMEOUT_SECS;
+               adapter->reset_ack_timeo = QLC_83XX_IDC_RESET_TIMEOUT_SECS;
+       } else {
+               adapter->dev_init_timeo = idc_params & 0xFFFF;
+               adapter->reset_ack_timeo = ((idc_params >> 16) & 0xFFFF);
+       }
+
+       adapter->ahw->idc.curr_state = QLC_83XX_IDC_DEV_UNKNOWN;
+       adapter->ahw->idc.prev_state = QLC_83XX_IDC_DEV_UNKNOWN;
+       adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+       adapter->ahw->idc.err_code = 0;
+       adapter->ahw->idc.collect_dump = 0;
+       adapter->ahw->idc.name = (char **)qlcnic_83xx_idc_states;
+
+       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+       set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+
+       /* Check if reset recovery is disabled */
+       if (!auto_fw_reset) {
+               /* Propagate do not reset request to other functions */
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val = val | QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+       }
+}
+
+/**
+ * qlcnic_83xx_idc_first_to_load_function_handler
+ *
+ * @adapter: adapter structure
+ *
+ * Peform first to load function specific initialization
+ *
+ * Returns: Success(0) or Failure(-EIO)
+ *
+ **/
+static int
+qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
+{
+       u32 state, val;
+
+       if (qlcnic_83xx_lock_driver(adapter))
+               return -EIO;
+
+       /* Clear driver lock register */
+       QLCWRX(adapter->ahw, QLC_83XX_RECOVER_DRV_LOCK, 0);
+
+       if (qlcnic_83xx_idc_update_major_version(adapter, 0)) {
+               qlcnic_83xx_unlock_driver(adapter);
+               return -EIO;
+       }
+
+       state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+       if (qlcnic_83xx_idc_check_dev_state_validity(adapter, state)) {
+               qlcnic_83xx_unlock_driver(adapter);
+               return -EIO;
+       }
+
+       if (state != QLC_83XX_IDC_DEV_COLD && load_fw_file) {
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_DEV_STATE,
+                      QLC_83XX_IDC_DEV_COLD);
+               state = QLC_83XX_IDC_DEV_COLD;
+       }
+
+       adapter->ahw->idc.curr_state = state;
+
+       /* First to load function should cold boot the device */
+       if (state == QLC_83XX_IDC_DEV_COLD)
+               qlcnic_83xx_idc_cold_state_handler(adapter);
+
+       /* Check if reset recovery is enabled */
+       if (auto_fw_reset) {
+               val = QLCRDX(adapter->ahw, QLC_83XX_IDC_CTRL);
+               val = val & ~QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY;
+               QLCWRX(adapter->ahw, QLC_83XX_IDC_CTRL, val);
+       }
+
+       qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_idc_init
+ *
+ * @adapter: adapter structure
+ *
+ * Initialize IDC task parameters
+ *
+ * Returns: Success(0) or Failure(-EIO)
+ *
+ **/
+static int
+qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
+{
+       int ret = -EIO;
+
+       qlcnic_83xx_setup_idc_parameters(adapter);
+
+       if (qlcnic_83xx_get_reset_instruction_template(adapter))
+               return ret;
+
+       if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) {
+               if (qlcnic_83xx_idc_first_to_load_function_handler(adapter))
+                       return -EIO;
+       } else {
+               if (qlcnic_83xx_idc_check_major_version(adapter))
+                       return -EIO;
+       }
+
+       qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
+
+       return 0;
+}
+
+static void
+qlcnic_83xx_config_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (ahw->port_type == QLCNIC_XGBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+       } else if (ahw->port_type == QLCNIC_GBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+       }
+       adapter->num_txd = MAX_CMD_DESCRIPTORS;
+       adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+static int
+qlcnic_83xx_init_driver(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       qlcnic_83xx_get_minidump_template(adapter);
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d\n",
+                               adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+
+/*
+ * qlcnic_83xx_clear_function_resources
+ *
+ * @adapter: adapter structure
+ *
+ * clean up the function resources if the function was used before
+ */
+
+static void
+qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_args cmd;
+       u32 presence_mask, audit_mask;
+       int status;
+
+       presence_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_PRESENCE);
+       audit_mask = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
+
+       if (IS_QLCNIC_83XX_USED(adapter, presence_mask, audit_mask)) {
+               qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_STOP_NIC_FUNC);
+               cmd.req.arg[1] = cpu_to_le32(0 | BIT_31);
+
+               status = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+               if (status) {
+                       netdev_err(adapter->netdev,
+                               "Failed to clean up the function resources\n");
+               }
+
+               qlcnic_free_mbx_args(&cmd);
+       }
+}
+
+
+/**
+ * qlcnic_83xx_init
+ *
+ * @adapter: adapter structure
+ *
+ * Init the driver based on NIC configuration mode (VIRTUAL or DEFAULT mode).
+ * Start NIC management tasks.
+ *
+ * Returns: Success(0) or Failure(-EIO)
+ *
+ **/
+int
+qlcnic_83xx_init(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (qlcnic_83xx_check_hw_status(adapter))
+               return -EIO;
+
+       /* Initilaize 83xx mailbox spinlock */
+       spin_lock_init(&ahw->mbx_lock);
+
+       set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+       qlcnic_83xx_clear_function_resources(adapter);
+
+       /* register for NIC IDC AEN Events */
+       qlcnic_83xx_register_nic_idc_func(adapter, 1);
+
+       if (!qlcnic_83xx_read_flash_descriptor_table(adapter))
+               qlcnic_83xx_read_flash_mfg_id(adapter);
+
+       if (qlcnic_83xx_idc_init(adapter))
+               return -EIO;
+
+       /* Configure default, SR-IOV or Virtual NIC mode of operation */
+       if (qlcnic_83xx_configure_opmode(adapter))
+               return -EIO;
+
+       /* Perform operating mode specific initialization */
+       if (adapter->nic_ops->init_driver(adapter))
+               return -EIO;
+
+       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
+       /* Periodically monitor device status */
+       qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
+
+       return adapter->ahw->idc.err_code;
+}
diff --git a/drivers/net/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/qlcnic/qlcnic_83xx_vnic.c
new file mode 100644 (file)
index 0000000..46824a7
--- /dev/null
@@ -0,0 +1,391 @@
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+int qlcnic_83xx_get_vnic_vport_info(struct qlcnic_adapter *adapter,
+                       struct qlcnic_info *npar_info, u8 vport_id)
+{
+       int err;
+       u32 status;
+       struct qlcnic_cmd_args cmd;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_NIC_INFO);
+       cmd.req.arg[1] = cpu_to_le32((vport_id << 16) | 0x1);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                       "Failed to get vport info %d\n", err);
+               goto out;
+       }
+
+       status = cmd.rsp.arg[2] & 0xFFFF;
+       if (status & BIT_0)
+               npar_info->min_tx_bw = (cmd.rsp.arg[2] & 0xFFFF0000) >> 16;
+       if (status & BIT_1)
+               npar_info->max_tx_bw = (cmd.rsp.arg[3] & 0xFFFF);
+       if (status & BIT_2)
+               npar_info->max_tx_ques = (cmd.rsp.arg[3] & 0xFFFF0000) >> 16;
+       if (status & BIT_3)
+               npar_info->max_tx_mac_filters = (cmd.rsp.arg[4] & 0xFFFF);
+       if (status & BIT_4)
+               npar_info->max_rx_mcast_mac_filters =
+                                       (cmd.rsp.arg[4] & 0xFFFF0000) >> 16;
+       if (status & BIT_5)
+               npar_info->max_rx_ucast_mac_filters = (cmd.rsp.arg[5] & 0xFFFF);
+       if (status & BIT_6)
+               npar_info->max_rx_ip_addr =
+                               (cmd.rsp.arg[5] & 0xFFFF0000) >> 16;
+       if (status & BIT_7)
+               npar_info->max_rx_lro_flow = (cmd.rsp.arg[6] & 0xFFFF);
+       if (status & BIT_8)
+               npar_info->max_rx_status_rings =
+                                       (cmd.rsp.arg[6] & 0xFFFF0000) >> 16;
+       if (status & BIT_9)
+               npar_info->max_rx_buf_rings = (cmd.rsp.arg[7] & 0xFFFF);
+
+       npar_info->max_rx_ques = (cmd.rsp.arg[7] & 0xFFFF0000) >> 16;
+       npar_info->max_tx_vlan_keys = (cmd.rsp.arg[8] & 0xFFFF);
+
+       dev_info(&adapter->pdev->dev,
+               "\n\tmin_tx_bw: %d, max_tx_bw: %d max_tx_ques: %d,\n"
+               "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n"
+               "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n"
+               "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n"
+               "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n",
+               npar_info->min_tx_bw,
+               npar_info->max_tx_bw, npar_info->max_tx_ques,
+               npar_info->max_tx_mac_filters, npar_info->max_rx_mcast_mac_filters,
+               npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr,
+               npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings,
+               npar_info->max_rx_buf_rings,
+               npar_info->max_rx_ques, npar_info->max_tx_vlan_keys);
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *adapter,
+                       struct qlcnic_info *npar_info)
+{
+       int err;
+       struct qlcnic_cmd_args cmd;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_GET_NIC_INFO);
+       cmd.req.arg[1] = cpu_to_le32(0x2);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                       "Failed to get vNIC PF info %d\n", err);
+               goto out;
+       }
+
+       npar_info->total_pf = cmd.rsp.arg[2] & 0xFF;
+       npar_info->total_rss_engines = (cmd.rsp.arg[2] & 0xFF00) >> 8;
+       npar_info->max_vports = (cmd.rsp.arg[2] & 0xFFFF0000) >> 16;
+       npar_info->max_tx_ques =  cmd.rsp.arg[3] & 0xFFFF;
+       npar_info->max_tx_mac_filters = (cmd.rsp.arg[3] & 0xFFFF0000) >> 16;
+       npar_info->max_rx_mcast_mac_filters = cmd.rsp.arg[4] & 0xFFFF;
+       npar_info->max_rx_ucast_mac_filters =
+                               (cmd.rsp.arg[4] & 0xFFFF0000) >> 16;
+       npar_info->max_rx_ip_addr = (cmd.rsp.arg[5] & 0xFFFF);
+       npar_info->max_rx_lro_flow = (cmd.rsp.arg[5] & 0xFFFF0000) >> 16;
+       npar_info->max_rx_status_rings = (cmd.rsp.arg[6] & 0xFFFF);
+       npar_info->max_rx_buf_rings = (cmd.rsp.arg[6] & 0xFFFF0000) >> 16;
+       npar_info->max_rx_ques = (cmd.rsp.arg[7] & 0xFFFF) >> 16;
+       npar_info->max_tx_vlan_keys = (cmd.rsp.arg[7] & 0xFFFF0000) >> 16;
+
+       dev_info(&adapter->pdev->dev,
+               "\n\ttotal_pf: %d,\n"
+               "\n\ttotal_rss_engines: %d max_vports: %d max_tx_ques %d,\n"
+               "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n"
+               "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n"
+               "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n"
+               "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n",
+               npar_info->total_pf,
+               npar_info->total_rss_engines, npar_info->max_vports,
+               npar_info->max_tx_ques, npar_info->max_tx_mac_filters,
+               npar_info->max_rx_mcast_mac_filters,
+               npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr,
+               npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings,
+               npar_info->max_rx_buf_rings,
+               npar_info->max_rx_ques, npar_info->max_tx_vlan_keys);
+
+out:
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
+int
+qlcnic_83xx_set_vnic_operational(struct qlcnic_adapter *adapter, int lock)
+{
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_OPER);
+       dev_info(&adapter->pdev->dev,
+                       "vNIC operational state set\n");
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+int
+qlcnic_83xx_set_vnic_non_operational(struct qlcnic_adapter *adapter, int lock)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (lock) {
+               if (qlcnic_83xx_lock_driver(adapter))
+                       return -EBUSY;
+       }
+
+       QLCWRX(adapter->ahw, QLC_83XX_VNIC_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+       ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+       dev_info(&adapter->pdev->dev,
+                       "vNIC non operational state set\n");
+
+       if (lock)
+               qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_set_vnic_opmode
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+       u8 id;
+       int i, ret = -EBUSY;
+       u32 data = QLCNIC_MGMT_FUNC;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (qlcnic_83xx_lock_driver(adapter)) {
+               return ret;
+       }
+
+       if (qlcnic_config_npars) {
+               for (i = 0; i < ahw->act_pci_func; i++) {
+                       id = adapter->npars[i].pci_func;
+                       if (id == ahw->pci_func)
+                               continue;
+                       data |= (qlcnic_config_npars &
+                                       QLC_83XX_SET_FUNC_OPMODE(0x3, id));
+               }
+       } else {
+               data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+               data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
+                       (QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
+                       ahw->pci_func));
+       }
+       QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
+
+       qlcnic_83xx_unlock_driver(adapter);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_config_vnic_buff_descriptors
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static inline void
+qlcnic_83xx_config_vnic_buff_descriptors(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (ahw->port_type == QLCNIC_XGBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+
+       } else if (ahw->port_type == QLCNIC_GBE) {
+               adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+               adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+               adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
+       }
+       adapter->num_txd = MAX_CMD_DESCRIPTORS;
+       adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+
+/**
+ * qlcnic_83xx_init_mgmt_vnic
+ *
+ * @adapter: adapter structure
+ * Management vNIC sets the operational mode of other vNIC's and
+ * configures embedded switch (ESWITCH).
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_init_mgmt_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       qlcnic_83xx_get_minidump_template(adapter);
+       if (!(adapter->flags & QLCNIC_ADAPTER_INITIALIZED)) {
+               if (qlcnic_init_pci_info(adapter))
+                       return err;
+
+               if (qlcnic_83xx_set_vnic_opmode(adapter))
+                       return err;
+
+               if (qlcnic_set_default_offload_settings(adapter))
+                       return err;
+       } else {
+               if (qlcnic_reset_npar_config(adapter))
+                       return err;
+       }
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+       qlcnic_83xx_set_vnic_operational(adapter, 1);
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d, Management function\n",
+                       adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_init_privileged_vnic
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_init_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       qlcnic_83xx_get_minidump_template(adapter);
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       netdev_info(adapter->netdev, "HAL Version: %d, Privileged function\n",
+                       adapter->ahw->fw_hal_version);
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_init_non_privileged_vnic
+ *
+ * @adapter: adapter structure
+ *
+ * Returns:
+ *
+ **/
+static int
+qlcnic_83xx_init_non_privileged_vnic(struct qlcnic_adapter *adapter)
+{
+       int err = -EIO;
+
+       qlcnic_83xx_get_fw_version(adapter);
+       if (qlcnic_set_eswitch_port_config(adapter))
+               return err;
+
+       if (qlcnic_83xx_get_port_info(adapter))
+               return err;
+
+       qlcnic_83xx_config_vnic_buff_descriptors(adapter);
+       adapter->ahw->msix_supported = !!use_msi_x;
+       adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+
+       dev_info(&adapter->pdev->dev, "HAL Version: %d, Virtual function\n",
+                               adapter->ahw->fw_hal_version);
+
+       return 0;
+}
+
+/**
+ * qlcnic_83xx_vnic_opmode
+ *
+ * @adapter: adapter structure
+ * Identify virtual NIC operational modes.
+ *
+ * Returns:
+ *
+ **/
+int
+qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
+{
+       u32 op_mode, priv_level;
+       struct pci_dev *pdev = adapter->pdev;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       ahw->hw_ops->get_func_no(adapter);
+
+       op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+       if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_83XX_GET_FUNC_PRIVILEGE_LEVEL(op_mode,
+                                                       ahw->pci_func);
+
+       if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+               dev_info(&pdev->dev, "vNIC opmode %d\n", adapter->ahw->op_mode);
+               adapter->ahw->idc.ready_state_entry_action =
+                       qlcnic_83xx_idc_ready_state_entry_action;
+               adapter->nic_ops->init_driver =
+                               qlcnic_83xx_init_non_privileged_vnic;
+       } else if (priv_level == QLCNIC_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_PRIV_FUNC;
+               dev_info(&pdev->dev, "vNIC opmode %d\n", adapter->ahw->op_mode);
+               adapter->ahw->idc.ready_state_entry_action =
+                       qlcnic_83xx_idc_vnic_pf_ready_state_entry_action;
+               adapter->nic_ops->init_driver =
+                               qlcnic_83xx_init_privileged_vnic;
+       } else if (priv_level == QLCNIC_MGMT_FUNC) {
+               ahw->op_mode = QLCNIC_MGMT_FUNC;
+               dev_info(&pdev->dev, "vNIC opmode %d\n", adapter->ahw->op_mode);
+               adapter->ahw->idc.ready_state_entry_action =
+                       qlcnic_83xx_idc_ready_state_entry_action;
+               adapter->nic_ops->init_driver =
+                               qlcnic_83xx_init_mgmt_vnic;
+       } else {
+               return -EIO;
+       }
+
+       if (ahw->capabilities & BIT_23) {
+               adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+               dev_info(&pdev->dev, "ESWITCH enabled %d\n",
+                                               adapter->ahw->op_mode);
+       } else {
+               adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+       }
+
+       adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+       adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+
+       return 0;
+}
index 2a179d087207e4375afb0d66f712043a10417786..fefac5cb6e89b94276b52970d3f6614c4fba4d4d 100644 (file)
 
 #include "qlcnic.h"
 
+/* Array of FW control command structs with command type and required
+ * number of input and output arguments respectively.
+*/
+static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
+       { QLCNIC_CMD_CREATE_RX_CTX, 4, 1 },
+       { QLCNIC_CMD_DESTROY_RX_CTX, 2, 1 },
+       { QLCNIC_CMD_CREATE_TX_CTX, 4, 1 },
+       { QLCNIC_CMD_DESTROY_TX_CTX, 2, 1 },
+       { QLCNIC_CMD_INTRPT_TEST, 4, 1 },
+       { QLCNIC_CMD_SET_MTU, 4, 1 },
+       { QLCNIC_CMD_READ_PHY, 4, 2 },
+       { QLCNIC_CMD_WRITE_PHY, 5, 1 },
+       { QLCNIC_CMD_READ_HW_REG, 4, 1 },
+       { QLCNIC_CMD_GET_FLOW_CTL, 4, 2 },
+       { QLCNIC_CMD_SET_FLOW_CTL, 4, 1 },
+       { QLCNIC_CMD_READ_MAX_MTU, 4, 2 },
+       { QLCNIC_CMD_READ_MAX_LRO, 4, 2 },
+       { QLCNIC_CMD_MAC_ADDRESS, 4, 3 },
+       { QLCNIC_CMD_GET_PCI_INFO, 4, 1 },
+       { QLCNIC_CMD_GET_NIC_INFO, 4, 1 },
+       { QLCNIC_CMD_SET_NIC_INFO, 4, 1 },
+       { QLCNIC_CMD_GET_ESWITCH_CAPABILITY, 4, 3 },
+       { QLCNIC_CMD_TOGGLE_ESWITCH, 4, 1 },
+       { QLCNIC_CMD_GET_ESWITCH_STATUS, 4, 3 },
+       { QLCNIC_CMD_SET_PORTMIRRORING, 4, 1 },
+       { QLCNIC_CMD_CONFIGURE_ESWITCH, 4, 1 },
+       { QLCNIC_CMD_GET_MAC_STATS, 4, 1 },
+       { QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG, 4, 3 },
+       { QLCNIC_CMD_GET_ESWITCH_STATS, 5, 1 },
+       { QLCNIC_CMD_CONFIG_PORT, 4, 1 },
+       { QLCNIC_CMD_TEMP_SIZE, 4, 4 },
+       { QLCNIC_CMD_GET_TEMP_HDR, 4, 1 },
+       { QLCNIC_CMD_SET_DRV_VER, 4, 1 },
+};
+
+/* Allocate mailbox incoming and outgoing registers. It should be used with a
+ * follow up call to qlcnic_free_mbx_args
+ */
+int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
+               struct qlcnic_adapter *adapter, u32 type)
+{
+       int i, size;
+       const struct qlcnic_mailbox_metadata *mbx_tbl;
+
+       mbx_tbl = qlcnic_mbx_tbl;
+       size = ARRAY_SIZE(qlcnic_mbx_tbl);
+       for (i = 0; i < size; i++) {
+               if (type == mbx_tbl[i].cmd) {
+                       mbx->req.num = mbx_tbl[i].in_args;
+                       mbx->rsp.num = mbx_tbl[i].out_args;
+                       mbx->req.arg = (u32 *) kcalloc(mbx->req.num,
+                               sizeof(u32), GFP_ATOMIC);
+                       if (!mbx->req.arg)
+                               return -ENOMEM;
+                       mbx->rsp.arg = (u32 *) kcalloc(mbx->rsp.num,
+                               sizeof(u32), GFP_ATOMIC);
+                       if (!mbx->rsp.arg) {
+                               kfree(mbx->req.arg);
+                               mbx->req.arg = NULL;
+                               return -ENOMEM;
+                       }
+                       memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+                       memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+                       mbx->req.arg[0] = type;
+                       break;
+               }
+       }
+       return 0;
+}
+
 static u32
 qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
 {
        u32 rsp;
-       int timeout = 0;
+       int err, timeout = 0;
 
        do {
                /* give atleast 1ms for firmware to respond */
-               mdelay(1);
+               msleep(1);
 
                if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
                        return QLCNIC_CDRP_RSP_TIMEOUT;
 
-               rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET);
+               rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET, &err);
        } while (!QLCNIC_CDRP_IS_RSP(rsp));
 
        return rsp;
 }
 
-void
+int
 qlcnic_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd)
 {
+       int i, err;
        u32 rsp;
        u32 signature;
        struct pci_dev *pdev = adapter->pdev;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       signature = QLCNIC_CDRP_SIGNATURE_MAKE(ahw->pci_func,
-               adapter->fw_hal_version);
+       signature = QLCNIC_CDRP_SIGNATURE_MAKE(ahw);
 
        /* Acquire semaphore before accessing CRB */
-       if (qlcnic_api_lock(adapter)) {
-               cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
-               return;
+       if (ahw->hw_ops->api_lock(adapter)) {
+               cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
+               return cmd->rsp.arg[0];
        }
 
        QLCWR32(adapter, QLCNIC_SIGN_CRB_OFFSET, signature);
-       QLCWR32(adapter, QLCNIC_ARG1_CRB_OFFSET, cmd->req.arg1);
-       QLCWR32(adapter, QLCNIC_ARG2_CRB_OFFSET, cmd->req.arg2);
-       QLCWR32(adapter, QLCNIC_ARG3_CRB_OFFSET, cmd->req.arg3);
+       for (i = 1; i < QLCNIC_CDRP_MAX_ARGS; i++)
+               QLCWR32(adapter, QLCNIC_CDRP_ARG(i), cmd->req.arg[i]);
        QLCWR32(adapter, QLCNIC_CDRP_CRB_OFFSET,
-               QLCNIC_CDRP_FORM_CMD(cmd->req.cmd));
-
+               QLCNIC_CDRP_FORM_CMD(cmd->req.arg[0]));
        rsp = qlcnic_poll_rsp(adapter);
 
        if (rsp == QLCNIC_CDRP_RSP_TIMEOUT) {
-               dev_err(&pdev->dev, "CDRP response timeout.\n");
-               cmd->rsp.cmd = QLCNIC_RCODE_TIMEOUT;
+               dev_err(&pdev->dev, "card response timeout.\n");
+               cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
        } else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
-               cmd->rsp.cmd = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
-               switch (cmd->rsp.cmd) {
-               case QLCNIC_RCODE_INVALID_ARGS:
-                       dev_err(&pdev->dev, "CDRP invalid args: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_NOT_SUPPORTED:
-               case QLCNIC_RCODE_NOT_IMPL:
-                       dev_err(&pdev->dev,
-                               "CDRP command not supported: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_NOT_PERMITTED:
-                       dev_err(&pdev->dev,
-                               "CDRP requested action not permitted: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_INVALID:
-                       dev_err(&pdev->dev,
-                               "CDRP invalid or unknown cmd received: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               case QLCNIC_RCODE_TIMEOUT:
-                       dev_err(&pdev->dev, "CDRP command timeout: 0x%x.\n",
-                               cmd->rsp.cmd);
-                       break;
-               default:
-                       dev_err(&pdev->dev, "CDRP command failed: 0x%x.\n",
-                               cmd->rsp.cmd);
-               }
-       } else if (rsp == QLCNIC_CDRP_RSP_OK) {
-               cmd->rsp.cmd = QLCNIC_RCODE_SUCCESS;
-               if (cmd->rsp.arg2)
-                       cmd->rsp.arg2 = QLCRD32(adapter,
-                               QLCNIC_ARG2_CRB_OFFSET);
-               if (cmd->rsp.arg3)
-                       cmd->rsp.arg3 = QLCRD32(adapter,
-                               QLCNIC_ARG3_CRB_OFFSET);
-       }
-       if (cmd->rsp.arg1)
-               cmd->rsp.arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+               cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err);
+               dev_err(&pdev->dev, "failed card response code:0x%x\n",
+                               cmd->rsp.arg[0]);
+       } else if (rsp == QLCNIC_CDRP_RSP_OK)
+               cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
 
-       /* Release semaphore */
-       qlcnic_api_unlock(adapter);
-
-}
+       for (i = 1; i < cmd->rsp.num; i++)
+               cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i), &err);
 
-static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u16 temp_size)
-{
-       uint64_t sum = 0;
-       int count = temp_size / sizeof(uint32_t);
-       while (count-- > 0)
-               sum += *temp_buffer++;
-       while (sum >> 32)
-               sum = (sum & 0xFFFFFFFF) + (sum >> 32);
-       return ~sum;
+       /* Release semaphore */
+       ahw->hw_ops->api_unlock(adapter);
+       return cmd->rsp.arg[0];
 }
 
-int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+int
+qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
 {
-       int err, i;
-       u16 temp_size;
-       void *tmp_addr;
-       u32 version, csum, *template, *tmp_buf;
+       int err = 0;
        struct qlcnic_cmd_args cmd;
-       struct qlcnic_hardware_context *ahw;
-       struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl;
-       dma_addr_t tmp_addr_t = 0;
-
-       ahw = adapter->ahw;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_TEMP_SIZE;
-       memset(&cmd.rsp, 1, sizeof(struct _cdrp_cmd));
-       qlcnic_issue_cmd(adapter, &cmd);
-       if (cmd.rsp.cmd != QLCNIC_RCODE_SUCCESS) {
-               dev_info(&adapter->pdev->dev,
-                       "Can't get template size %d\n", cmd.rsp.cmd);
-               err = -EIO;
-               return err;
-       }
-       temp_size = cmd.rsp.arg2;
-       version = cmd.rsp.arg3;
-       if (!temp_size)
-               return -EIO;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-       tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
-                       &tmp_addr_t, GFP_KERNEL);
-       if (!tmp_addr) {
-               dev_err(&adapter->pdev->dev,
-                       "Can't get memory for FW dump template\n");
-               return -ENOMEM;
-       }
-       memset(&cmd.rsp, 0, sizeof(struct _cdrp_cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_TEMP_HDR;
-       cmd.req.arg1 = LSD(tmp_addr_t);
-       cmd.req.arg2 = MSD(tmp_addr_t);
-       cmd.req.arg3 = temp_size;
-       qlcnic_issue_cmd(adapter, &cmd);
-
-       err = cmd.rsp.cmd;
-       if (err != QLCNIC_RCODE_SUCCESS) {
-               dev_err(&adapter->pdev->dev,
-                       "Failed to get mini dump template header %d\n", err);
-               err = -EIO;
-               goto error;
-       }
-       tmp_tmpl = tmp_addr;
-       csum = qlcnic_temp_checksum((uint32_t *) tmp_addr, temp_size);
-       if (csum) {
-               dev_err(&adapter->pdev->dev,
-                       "Template header checksum validation failed\n");
-               err = -EIO;
-               goto error;
-       }
-       ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
-       if (!ahw->fw_dump.tmpl_hdr) {
+       if (recv_ctx->state != QLCNIC_HOST_CTX_STATE_ACTIVE)
+               return err;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_SET_MTU);
+       cmd.req.arg[1] = recv_ctx->context_id;
+       cmd.req.arg[2] = mtu;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               netdev_err(adapter->netdev, "Failed to set mtu\n");
                err = -EIO;
-               goto error;
        }
-       tmp_buf = tmp_addr;
-       template = (u32 *) ahw->fw_dump.tmpl_hdr;
-       for (i = 0; i < temp_size/sizeof(u32); i++)
-               *template++ = __le32_to_cpu(*tmp_buf++);
-
-       tmpl_hdr = ahw->fw_dump.tmpl_hdr;
-       tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
-       ahw->fw_dump.enable = 1;
-error:
-       dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
+       qlcnic_free_mbx_args(&cmd);
        return err;
 }
 
 int
-qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
+qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter)
 {
+       int err = 0;
        struct qlcnic_cmd_args cmd;
-       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       char drv_string[12];
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_SET_MTU;
-       cmd.req.arg1 = recv_ctx->context_id;
-       cmd.req.arg2 = mtu;
-       cmd.req.arg3 = 0;
-       if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
-               qlcnic_issue_cmd(adapter, &cmd);
-               if (cmd.rsp.cmd) {
-                       dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
-                       return -EIO;
-               }
-       }
+       memset(drv_string, 0 , sizeof(drv_string));
+       snprintf(drv_string, sizeof(drv_string), "%d"".""%d"".""%d",
+               _QLCNIC_LINUX_MAJOR, _QLCNIC_LINUX_MINOR,
+                       _QLCNIC_LINUX_SUBVERSION);
 
-       return 0;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_SET_DRV_VER);
+       memcpy(&cmd.req.arg[1], drv_string, sizeof(u32));
+       memcpy(&cmd.req.arg[2], drv_string + 4, sizeof(u32));
+       memcpy(&cmd.req.arg[3], drv_string + 8, sizeof(u32));
+
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err) {
+               netdev_err(adapter->netdev, "Failed to drv ver in fw\n");
+               err = -EIO;
+       }
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 }
 
-static int
+int
 qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 {
        void *addr;
@@ -314,20 +291,18 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
        }
 
        phys_addr = hostrq_phys_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = (u32) (phys_addr >> 32);
-       cmd.req.arg2 = (u32) (phys_addr & 0xffffffff);
-       cmd.req.arg3 = rq_size;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_RX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_CREATE_RX_CTX);
+       cmd.req.arg[1] = MSD(phys_addr);
+       cmd.req.arg[2] = LSD(phys_addr);
+       cmd.req.arg[3] = rq_size;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
        if (err) {
                dev_err(&adapter->pdev->dev,
                        "Failed to create rx ctx in firmware%d\n", err);
                goto out_free_rsp;
        }
 
-
        prsp_rds = ((struct qlcnic_cardrsp_rds_ring *)
                         &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
 
@@ -358,6 +333,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 out_free_rsp:
        dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
                cardrsp_phys_addr);
+       qlcnic_free_mbx_args(&cmd);
 out_free_rq:
        dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
        return err;
@@ -366,24 +342,25 @@ out_free_rq:
 static void
 qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
 {
+       int err;
        struct qlcnic_cmd_args cmd;
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = recv_ctx->context_id;
-       cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
-       cmd.req.arg3 = 0;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_RX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       if (cmd.rsp.cmd)
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_DESTROY_RX_CTX);
+       cmd.req.arg[1] = recv_ctx->context_id;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err)
                dev_err(&adapter->pdev->dev,
                        "Failed to destroy rx ctx in firmware\n");
 
        recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
+       qlcnic_free_mbx_args(&cmd);
 }
 
-static int
-qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
+int
+qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
+       struct qlcnic_host_tx_ring *tx_ring, int ring)
 {
        struct qlcnic_hostrq_tx_ctx     *prq;
        struct qlcnic_hostrq_cds_ring   *prq_cds;
@@ -395,7 +372,6 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
        int     err;
        u64     phys_addr;
        dma_addr_t      rq_phys_addr, rsp_phys_addr;
-       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
 
        /* reset host resources */
        tx_ring->producer = 0;
@@ -430,9 +406,9 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
 
        prq->host_int_crb_mode =
                cpu_to_le32(QLCNIC_HOST_INT_CRB_MODE_SHARED);
+       prq->msi_index = 0;
 
        prq->interrupt_ctl = 0;
-       prq->msi_index = 0;
        prq->cmd_cons_dma_addr = cpu_to_le64(tx_ring->hw_cons_phys_addr);
 
        prq_cds = &prq->cds_ring;
@@ -441,20 +417,18 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
        prq_cds->ring_size = cpu_to_le32(tx_ring->num_desc);
 
        phys_addr = rq_phys_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = (u32)(phys_addr >> 32);
-       cmd.req.arg2 = ((u32)phys_addr & 0xffffffff);
-       cmd.req.arg3 = rq_size;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CREATE_TX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CREATE_TX_CTX);
+       cmd.req.arg[1] = MSD(phys_addr);
+       cmd.req.arg[2] = LSD(phys_addr);
+       cmd.req.arg[3] = rq_size;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
 
        if (err == QLCNIC_RCODE_SUCCESS) {
                temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
                tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp;
-
-               adapter->tx_context_id =
-                       le16_to_cpu(prsp->context_id);
+               tx_ring->ctx_id = le16_to_cpu(prsp->context_id);
        } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to create tx ctx in firmware%d\n", err);
@@ -466,44 +440,44 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
 
 out_free_rq:
        dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr);
+       qlcnic_free_mbx_args(&cmd);
 
        return err;
 }
 
 static void
-qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
+qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter,
+       struct qlcnic_host_tx_ring *tx_ring)
 {
        struct qlcnic_cmd_args cmd;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = adapter->tx_context_id;
-       cmd.req.arg2 = QLCNIC_DESTROY_CTX_RESET;
-       cmd.req.arg3 = 0;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_DESTROY_TX_CTX;
-       qlcnic_issue_cmd(adapter, &cmd);
-       if (cmd.rsp.cmd)
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_DESTROY_TX_CTX);
+       cmd.req.arg[1] = tx_ring->ctx_id;
+       if (adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd))
                dev_err(&adapter->pdev->dev,
                        "Failed to destroy tx ctx in firmware\n");
+       qlcnic_free_mbx_args(&cmd);
 }
 
 int
 qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
 {
+       int err;
        struct qlcnic_cmd_args cmd;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = config;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIG_PORT;
-       qlcnic_issue_cmd(adapter, &cmd);
-
-       return cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_CONFIG_PORT);
+       cmd.req.arg[1] = config;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 }
 
 int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
 {
        void *addr;
-       int err;
-       int ring;
+       int err, ring;
        struct qlcnic_recv_context *recv_ctx;
        struct qlcnic_host_rds_ring *rds_ring;
        struct qlcnic_host_sds_ring *sds_ring;
@@ -512,26 +486,29 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
        struct pci_dev *pdev = adapter->pdev;
 
        recv_ctx = adapter->recv_ctx;
-       tx_ring = adapter->tx_ring;
 
-       tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev,
-               sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL);
-       if (tx_ring->hw_consumer == NULL) {
-               dev_err(&pdev->dev, "failed to allocate tx consumer\n");
-               return -ENOMEM;
-       }
-
-       /* cmd desc ring */
-       addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev,
+                       sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL);
+               if (tx_ring->hw_consumer == NULL) {
+                       netdev_err(adapter->netdev,
+                                       "failed to allocate tx consumer\n");
+                       return -ENOMEM;
+               }
+               /* cmd desc ring */
+               addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
                        &tx_ring->phys_addr, GFP_KERNEL);
 
-       if (addr == NULL) {
-               dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
-               err = -ENOMEM;
-               goto err_out_free;
-       }
+               if (addr == NULL) {
+                       netdev_err(adapter->netdev,
+                                "failed to allocate tx desc ring\n");
+                       err = -ENOMEM;
+                       goto err_out_free;
+               }
 
-       tx_ring->desc_head = addr;
+               tx_ring->desc_head = addr;
+       }
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &recv_ctx->rds_rings[ring];
@@ -573,21 +550,29 @@ err_out_free:
 
 int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
 {
-       int err;
+       int i, err, ring;
 
        if (adapter->flags & QLCNIC_NEED_FLR) {
                pci_reset_function(adapter->pdev);
                adapter->flags &= ~QLCNIC_NEED_FLR;
        }
 
-       err = qlcnic_fw_cmd_create_rx_ctx(adapter);
+       err = adapter->ahw->hw_ops->create_rx_ctx(adapter);
        if (err)
                return err;
 
-       err = qlcnic_fw_cmd_create_tx_ctx(adapter);
-       if (err) {
-               qlcnic_fw_cmd_destroy_rx_ctx(adapter);
-               return err;
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               err = adapter->ahw->hw_ops->create_tx_ctx(adapter,
+                        &adapter->tx_ring[ring], ring);
+               if (err) {
+                       qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+                       if (ring == 0)
+                               return err;
+                       for (i = 0; i < ring; i++)
+                               qlcnic_fw_cmd_destroy_tx_ctx(adapter,
+                                        &adapter->tx_ring[i]);
+                       return err;
+               }
        }
 
        set_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
@@ -596,12 +581,16 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *adapter)
 
 void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
 {
+       int ring;
+
        if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
                qlcnic_fw_cmd_destroy_rx_ctx(adapter);
-               qlcnic_fw_cmd_destroy_tx_ctx(adapter);
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
+                       qlcnic_fw_cmd_destroy_tx_ctx(adapter,
+                                       &adapter->tx_ring[ring]);
 
                /* Allow dma queues to drain after context reset */
-               mdelay(20);
+               msleep(20);
        }
 }
 
@@ -615,20 +604,22 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
 
        recv_ctx = adapter->recv_ctx;
 
-       tx_ring = adapter->tx_ring;
-       if (tx_ring->hw_consumer != NULL) {
-               dma_free_coherent(&adapter->pdev->dev,
-                               sizeof(u32),
-                               tx_ring->hw_consumer,
-                               tx_ring->hw_cons_phys_addr);
-               tx_ring->hw_consumer = NULL;
-       }
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               if (tx_ring->hw_consumer != NULL) {
+                       dma_free_coherent(&adapter->pdev->dev,
+                                       sizeof(u32),
+                                       tx_ring->hw_consumer,
+                                       tx_ring->hw_cons_phys_addr);
+                       tx_ring->hw_consumer = NULL;
+               }
 
-       if (tx_ring->desc_head != NULL) {
-               dma_free_coherent(&adapter->pdev->dev,
-                               TX_DESC_RINGSIZE(tx_ring),
-                               tx_ring->desc_head, tx_ring->phys_addr);
-               tx_ring->desc_head = NULL;
+               if (tx_ring->desc_head != NULL) {
+                       dma_free_coherent(&adapter->pdev->dev,
+                                       TX_DESC_RINGSIZE(tx_ring),
+                                       tx_ring->desc_head, tx_ring->phys_addr);
+                       tx_ring->desc_head = NULL;
+               }
        }
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
@@ -656,28 +647,32 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
        }
 }
 
-
 /* Get MAC address of a NIC partition */
 int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
 {
-       int err;
+       int err, i;
        struct qlcnic_cmd_args cmd;
+       u32 mac_low, mac_high;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.arg1 = adapter->ahw->pci_func | BIT_8;
-       cmd.req.cmd = QLCNIC_CDRP_CMD_MAC_ADDRESS;
-       cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_MAC_ADDRESS);
+       cmd.req.arg[1] = adapter->ahw->pci_func | BIT_8;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
 
-       if (err == QLCNIC_RCODE_SUCCESS)
-               qlcnic_fetch_mac(adapter, cmd.rsp.arg1, cmd.rsp.arg2, 0, mac);
-       else {
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               mac_low = cmd.rsp.arg[1];
+               mac_high = cmd.rsp.arg[2];
+
+               for (i = 0; i < 2; i++)
+                       mac[i] = (u8) (mac_high >> ((1 - i) * 8));
+               for (i = 2; i < 6; i++)
+                       mac[i] = (u8) (mac_low >> ((5 - i) * 8));
+       } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get mac address%d\n", err);
                err = -EIO;
        }
-
+       qlcnic_free_mbx_args(&cmd);
        return err;
 }
 
@@ -687,7 +682,7 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
 {
        int     err;
        dma_addr_t nic_dma_t;
-       struct qlcnic_info *nic_info;
+       const struct qlcnic_info *nic_info;
        void *nic_info_addr;
        struct qlcnic_cmd_args cmd;
        size_t  nic_size = sizeof(struct qlcnic_info);
@@ -699,35 +694,16 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
        memset(nic_info_addr, 0, nic_size);
 
        nic_info = nic_info_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_NIC_INFO;
-       cmd.req.arg1 = MSD(nic_dma_t);
-       cmd.req.arg2 = LSD(nic_dma_t);
-       cmd.req.arg3 = (func_id << 16 | nic_size);
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
-
-       if (err == QLCNIC_RCODE_SUCCESS) {
-               npar_info->pci_func = le16_to_cpu(nic_info->pci_func);
-               npar_info->op_mode = le16_to_cpu(nic_info->op_mode);
-               npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
-               npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
-               npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
-               npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
-               npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
-               npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
-               npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
-               npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
 
-               dev_info(&adapter->pdev->dev,
-                       "phy port: %d switch_mode: %d,\n"
-                       "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
-                       "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
-                       npar_info->phys_port, npar_info->switch_mode,
-                       npar_info->max_tx_ques, npar_info->max_rx_ques,
-                       npar_info->min_tx_bw, npar_info->max_tx_bw,
-                       npar_info->max_mtu, npar_info->capabilities);
-       else {
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_NIC_INFO);
+       cmd.req.arg[1] = MSD(nic_dma_t);
+       cmd.req.arg[2] = LSD(nic_dma_t);
+       cmd.req.arg[3] = (func_id << 16 | nic_size);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err == QLCNIC_RCODE_SUCCESS)
+               qlcnic_set_npar_data(adapter, nic_info, npar_info);
+       else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get nic info%d\n", err);
                err = -EIO;
@@ -735,6 +711,8 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
 
        dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
                nic_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
@@ -748,7 +726,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
        struct qlcnic_info *nic_info;
        size_t nic_size = sizeof(struct qlcnic_info);
 
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
                return err;
 
        nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
@@ -770,13 +748,12 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
        nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
        nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_SET_NIC_INFO;
-       cmd.req.arg1 = MSD(nic_dma_t);
-       cmd.req.arg2 = LSD(nic_dma_t);
-       cmd.req.arg3 = ((nic->pci_func << 16) | nic_size);
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_SET_NIC_INFO);
+       cmd.req.arg[1] = MSD(nic_dma_t);
+       cmd.req.arg[2] = LSD(nic_dma_t);
+       cmd.req.arg[3] = ((nic->pci_func << 16) | nic_size);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
 
        if (err != QLCNIC_RCODE_SUCCESS) {
                dev_err(&adapter->pdev->dev,
@@ -786,6 +763,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 
        dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
                nic_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
@@ -808,19 +787,21 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
        memset(pci_info_addr, 0, pci_size);
 
        npar = pci_info_addr;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_PCI_INFO;
-       cmd.req.arg1 = MSD(pci_info_dma_t);
-       cmd.req.arg2 = LSD(pci_info_dma_t);
-       cmd.req.arg3 = pci_size;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
-
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_GET_PCI_INFO);
+       cmd.req.arg[1] = MSD(pci_info_dma_t);
+       cmd.req.arg[2] = LSD(pci_info_dma_t);
+       cmd.req.arg[3] = pci_size;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+       adapter->ahw->act_pci_func = 0;
        if (err == QLCNIC_RCODE_SUCCESS) {
                for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
                        pci_info->id = le16_to_cpu(npar->id);
                        pci_info->active = le16_to_cpu(npar->active);
                        pci_info->type = le16_to_cpu(npar->type);
+                       if (pci_info->type == QLCNIC_TYPE_NIC)
+                               adapter->ahw->act_pci_func++;
                        pci_info->default_port =
                                le16_to_cpu(npar->default_port);
                        pci_info->tx_min_bw =
@@ -837,6 +818,8 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
 
        dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr,
                pci_info_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
@@ -848,28 +831,27 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
        u32 arg1;
        struct qlcnic_cmd_args cmd;
 
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC ||
                !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
                return err;
 
        arg1 = id | (enable_mirroring ? BIT_4 : 0);
        arg1 |= pci_func << 8;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_SET_PORTMIRRORING;
-       cmd.req.arg1 = arg1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_SET_PORTMIRRORING);
+       cmd.req.arg[1] = arg1;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
 
-       if (err != QLCNIC_RCODE_SUCCESS) {
+       if (err != QLCNIC_RCODE_SUCCESS)
                dev_err(&adapter->pdev->dev,
                        "Failed to configure port mirroring%d on eswitch:%d\n",
                        pci_func, id);
-       } else {
+       else
                dev_info(&adapter->pdev->dev,
                        "Configured eSwitch %d for port mirroring:%d\n",
                        id, pci_func);
-       }
+       qlcnic_free_mbx_args(&cmd);
 
        return err;
 }
@@ -888,8 +870,8 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
        if (esw_stats == NULL)
                return -ENOMEM;
 
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC &&
-           func != adapter->ahw->pci_func) {
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC &&
+               func != adapter->ahw->pci_func) {
                dev_err(&adapter->pdev->dev,
                        "Not privilege to query stats for func=%d", func);
                return -EIO;
@@ -906,13 +888,12 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
        arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
        arg1 |= rx_tx << 15 | stats_size << 16;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
-       cmd.req.arg1 = arg1;
-       cmd.req.arg2 = MSD(stats_dma_t);
-       cmd.req.arg3 = LSD(stats_dma_t);
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_ESWITCH_STATS);
+       cmd.req.arg[1] = arg1;
+       cmd.req.arg[2] = MSD(stats_dma_t);
+       cmd.req.arg[3] = LSD(stats_dma_t);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
 
        if (!err) {
                stats = stats_addr;
@@ -932,6 +913,8 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
 
        dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
                stats_dma_t);
+       qlcnic_free_mbx_args(&cmd);
+
        return err;
 }
 
@@ -946,6 +929,9 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
        void *stats_addr;
        int err;
 
+       if (mac_stats == NULL)
+               return -ENOMEM;
+
        stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
                        &stats_dma_t, GFP_KERNEL);
        if (!stats_addr) {
@@ -954,15 +940,12 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
                return -ENOMEM;
        }
        memset(stats_addr, 0, stats_size);
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_MAC_STATS;
-       cmd.req.arg1 = stats_size << 16;
-       cmd.req.arg2 = MSD(stats_dma_t);
-       cmd.req.arg3 = LSD(stats_dma_t);
-
-       qlcnic_issue_cmd(adapter, &cmd);
-       err = cmd.rsp.cmd;
-
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_MAC_STATS);
+       cmd.req.arg[1] = stats_size << 16;
+       cmd.req.arg[2] = MSD(stats_dma_t);
+       cmd.req.arg[3] = LSD(stats_dma_t);
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
        if (!err) {
                stats = stats_addr;
                mac_stats->mac_tx_frames = le64_to_cpu(stats->mac_tx_frames);
@@ -983,11 +966,15 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
                                le64_to_cpu(stats->mac_rx_length_large);
                mac_stats->mac_rx_jabber = le64_to_cpu(stats->mac_rx_jabber);
                mac_stats->mac_rx_dropped = le64_to_cpu(stats->mac_rx_dropped);
-               mac_stats->mac_rx_crc_error = le64_to_cpu(stats->mac_rx_crc_error);
+               mac_stats->mac_FCS_error = le64_to_cpu(stats->mac_FCS_error);
+       } else {
+               dev_err(&adapter->pdev->dev,
+                       "%s: Get mac stats failed, err=%d.\n", __func__, err);
        }
 
        dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
                stats_dma_t);
+       qlcnic_free_mbx_args(&cmd);
        return err;
 }
 
@@ -1000,7 +987,7 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
 
        if (esw_stats == NULL)
                return -ENOMEM;
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
                return -EIO;
        if (adapter->npars == NULL)
                return -EIO;
@@ -1015,12 +1002,13 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
        esw_stats->numbytes = QLCNIC_STATS_NOT_AVAIL;
        esw_stats->context_id = eswitch;
 
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
                if (adapter->npars[i].phy_port != eswitch)
                        continue;
 
                memset(&port_stats, 0, sizeof(struct __qlcnic_esw_statistics));
-               if (qlcnic_get_port_stats(adapter, i, rx_tx, &port_stats))
+               if (qlcnic_get_port_stats(adapter, adapter->npars[i].pci_func,
+                                         rx_tx, &port_stats))
                        continue;
 
                esw_stats->size = port_stats.size;
@@ -1047,11 +1035,11 @@ int qlcnic_get_eswitch_stats(struct qlcnic_adapter *adapter, const u8 eswitch,
 int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
                const u8 port, const u8 rx_tx)
 {
-
+       int err;
        u32 arg1;
        struct qlcnic_cmd_args cmd;
 
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
                return -EIO;
 
        if (func_esw == QLCNIC_STATS_PORT) {
@@ -1070,11 +1058,12 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
        arg1 = port | QLCNIC_STATS_VERSION << 8 | func_esw << 12;
        arg1 |= BIT_14 | rx_tx << 15;
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_STATS;
-       cmd.req.arg1 = arg1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       return cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_ESWITCH_STATS);
+       cmd.req.arg[1] = arg1;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 
 err_ret:
        dev_err(&adapter->pdev->dev, "Invalid argument func_esw=%d port=%d"
@@ -1091,22 +1080,21 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
        u8 pci_func;
        pci_func = (*arg1 >> 8);
 
-       cmd.req.cmd = QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG;
-       cmd.req.arg1 = *arg1;
-       cmd.rsp.arg1 = cmd.rsp.arg2 = 1;
-       qlcnic_issue_cmd(adapter, &cmd);
-       *arg1 = cmd.rsp.arg1;
-       *arg2 = cmd.rsp.arg2;
-       err = cmd.rsp.cmd;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+               QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
+       cmd.req.arg[1] = *arg1;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       *arg1 = cmd.rsp.arg[1];
+       *arg2 = cmd.rsp.arg[2];
+       qlcnic_free_mbx_args(&cmd);
 
-       if (err == QLCNIC_RCODE_SUCCESS) {
+       if (err == QLCNIC_RCODE_SUCCESS)
                dev_info(&adapter->pdev->dev,
                        "eSwitch port config for pci func %d\n", pci_func);
-       } else {
+       else
                dev_err(&adapter->pdev->dev,
                        "Failed to get eswitch port config for pci func %d\n",
                                                                pci_func);
-       }
        return err;
 }
 /* Configure eSwitch port
@@ -1119,15 +1107,18 @@ op_type = 1 for port vlan_id
 int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
                struct qlcnic_esw_func_cfg *esw_cfg)
 {
-       int err = -EIO;
+       int err = -EIO, index;
        u32 arg1, arg2 = 0;
        struct qlcnic_cmd_args cmd;
        u8 pci_func;
 
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
                return err;
        pci_func = esw_cfg->pci_func;
-       arg1 = (adapter->npars[pci_func].phy_port & BIT_0);
+       index = qlcnic_is_valid_nic_func(adapter, pci_func);
+       if (index < 0)
+               return err;
+       arg1 = (adapter->npars[index].phy_port & BIT_0);
        arg1 |= (pci_func << 8);
 
        if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
@@ -1139,7 +1130,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
        case QLCNIC_PORT_DEFAULTS:
                arg1 |= (BIT_4 | BIT_6 | BIT_7);
                arg2 |= (BIT_0 | BIT_1);
-               if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+               if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
                        arg2 |= (BIT_2 | BIT_3);
                if (!(esw_cfg->discard_tagged))
                        arg1 &= ~BIT_4;
@@ -1168,20 +1159,19 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
                return err;
        }
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH;
-       cmd.req.arg1 = arg1;
-       cmd.req.arg2 = arg2;
-       qlcnic_issue_cmd(adapter, &cmd);
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_CONFIGURE_ESWITCH);
+       cmd.req.arg[1] = arg1;
+       cmd.req.arg[2] = arg2;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       qlcnic_free_mbx_args(&cmd);
 
-       err = cmd.rsp.cmd;
-       if (err != QLCNIC_RCODE_SUCCESS) {
+       if (err != QLCNIC_RCODE_SUCCESS)
                dev_err(&adapter->pdev->dev,
                        "Failed to configure eswitch pci func %d\n", pci_func);
-       } else {
+       else
                dev_info(&adapter->pdev->dev,
                        "Configured eSwitch for pci func %d\n", pci_func);
-       }
 
        return err;
 }
@@ -1191,11 +1181,16 @@ qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
                        struct qlcnic_esw_func_cfg *esw_cfg)
 {
        u32 arg1, arg2;
+       int index;
        u8 phy_port;
-       if (adapter->op_mode == QLCNIC_MGMT_FUNC)
-               phy_port = adapter->npars[esw_cfg->pci_func].phy_port;
-       else
-               phy_port = adapter->physical_port;
+
+       if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) {
+               index = qlcnic_is_valid_nic_func(adapter, esw_cfg->pci_func);
+               if (index < 0)
+                       return -EIO;
+               phy_port = adapter->npars[index].phy_port;
+       } else
+               phy_port = adapter->ahw->physical_port;
        arg1 = phy_port;
        arg1 |= (esw_cfg->pci_func << 8);
        if (__qlcnic_get_eswitch_port_config(adapter, &arg1, &arg2))
index 52e9a9136d5ec021e1108c5791266bc7f6ce3c6f..291abc4fac2699717702b4c54065c614a119a374 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/ethtool.h>
 
 #include "qlcnic.h"
-#define ETH_FW_DUMP_DISABLE 0
 
 struct qlcnic_stats {
        char stat_string[ETH_GSTRING_LEN];
@@ -59,6 +58,10 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
                                         QLC_OFF(stats.rx_dma_map_error)},
        {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
                                         QLC_OFF(stats.tx_dma_map_error)},
+       {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
+                               QLC_OFF(stats.mac_filter_limit_overrun)},
+       {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
+        QLC_OFF(stats.spurious_intr)},
 
 };
 
@@ -79,7 +82,14 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
        "tx numbytes",
 };
 
-static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
+static const char qlc_83xx_tx_stats_strings [][ETH_GSTRING_LEN] = {
+       "ctx_tx_bytes",
+       "ctx_tx_pkts",
+       "ctx_tx_errors",
+       "ctx_tx_dropped_pkts",
+       "ctx_tx_num_buffers",
+};
+static const char qlc_83xx_mac_stats_strings [][ETH_GSTRING_LEN] = {
        "mac_tx_frames",
        "mac_tx_bytes",
        "mac_tx_mcast_pkts",
@@ -111,35 +121,171 @@ static const char qlcnic_mac_stats_strings [][ETH_GSTRING_LEN] = {
        "mac_rx_length_large",
        "mac_rx_jabber",
        "mac_rx_dropped",
-       "mac_rx_crc_error",
+       "mac_crc_error",
        "mac_align_error",
 };
+static const char qlc_83xx_rx_stats_strings [][ETH_GSTRING_LEN] = {
+       "ctx_rx_bytes",
+       "ctx_rx_pkts",
+       "ctx_lro_pkt_cnt",
+       "ctx_ip_csum_error",
+       "ctx_rx_pkts_wo_ctx",
+       "ctx_rx_pkts_dropped_wo_sts",
+       "ctx_rx_osized_pkts",
+       "ctx_rx_pkts_dropped_wo_rds",
+       "ctx_rx_unexpected_mcast_pkts",
+       "ctx_invalid_mac_address",
+       "ctx_rx_rds_ring_prim_attemoted",
+       "ctx_rx_rds_ring_prim_success",
+       "ctx_num_lro_flows_added",
+       "ctx_num_lro_flows_removed",
+       "ctx_num_lro_flows_active",
+       "ctx_pkts_dropped_unknown",
+};
 
 #define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
-#define QLCNIC_MAC_STATS_LEN ARRAY_SIZE(qlcnic_mac_stats_strings)
-#define QLCNIC_DEVICE_STATS_LEN        ARRAY_SIZE(qlcnic_device_gstrings_stats)
-#define QLCNIC_TOTAL_STATS_LEN QLCNIC_STATS_LEN + QLCNIC_MAC_STATS_LEN
+#define QLCNIC_83XX_STATS ARRAY_SIZE(qlc_83xx_tx_stats_strings)                \
+                       + ARRAY_SIZE(qlc_83xx_mac_stats_strings)        \
+                       + ARRAY_SIZE(qlc_83xx_rx_stats_strings)
+#define QLCNIC_82XX_STATS QLCNIC_STATS_LEN \
+                       + ARRAY_SIZE(qlc_83xx_mac_stats_strings)
+#define QLCNIC_DEVICE_STATS_LEN(adapter)       \
+       (QLCNIC_IS_83XX(adapter) ?      \
+       QLCNIC_83XX_STATS :\
+       (ARRAY_SIZE(qlc_83xx_mac_stats_strings) \
+       + ARRAY_SIZE(qlcnic_device_gstrings_stats)))
+
+
 
 static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
        "Register_Test_on_offline",
        "Link_Test_on_offline",
        "Interrupt_Test_offline",
        "Internal_Loopback_offline",
-       "External_Loopback_offline"
+       "EEPROM_Test_offline"
 };
 
 #define QLCNIC_TEST_LEN        ARRAY_SIZE(qlcnic_gstrings_test)
+static inline u64*
+qlcnic_83xx_copy_stats(struct qlcnic_cmd_args *cmd, u64 *data, int index)
+{
+       u32 low, hi;
+       u64 val;
+
+       low = le32_to_cpu(cmd->rsp.arg[index]);
+       hi = le32_to_cpu(cmd->rsp.arg[index + 1]);
+       val = (((u64) low) | (((u64) hi) << 32));
+       *data++ = val;
+       return data;
+}
+
+static u64*
+qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
+       struct qlcnic_cmd_args *cmd, u64 *data, int type, int *ret)
+{
+       int err, k, total_regs;
+
+       *ret = 0;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, cmd);
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               dev_info(&adapter->pdev->dev,
+                       "Error in get statistics mailbox command\n");
+               *ret = -EIO;
+               return data;
+       }
+       total_regs = cmd->rsp.num;
+       switch(type) {
+       case QLCNIC_83XX_STAT_MAC:
+               /* fill in MAC tx counters */
+               for (k = 2; k < 28; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 24 bytes of reserved area */
+               /* fill in MAC rx counters */
+               for (k += 6; k < 60; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 24 bytes of reserved area */
+               /* fill in MAC rx frame stats */
+               for (k += 6; k < 80; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               break;
+       case QLCNIC_83XX_STAT_RX:
+               for (k = 2; k < 8; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 8 bytes of reserved data */
+               for (k += 2; k < 24; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 8 bytes containing RE1FBQ error data*/
+               for (k += 2; k < total_regs; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               break;
+       case QLCNIC_83XX_STAT_TX:
+               for (k = 2; k < 10; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               /* skip 8 bytes of reserved data */
+               for (k += 2; k < total_regs; k += 2)
+                       data = qlcnic_83xx_copy_stats(cmd, data, k);
+               break;
+       default:
+               netdev_info(adapter->netdev, "Unknown get statistics mode\n");
+               *ret = -EIO;
+       }
+       return data;
+}
+
+/*
+ * Get statistics of MAC and that of Context/Function/Vport
+ */
+static void
+qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
+{
+       struct qlcnic_cmd_args cmd;
+       int ret = 0;
+
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_STATISTICS);
+       /* Get Tx stats */
+       cmd.req.arg[1] = cpu_to_le32(BIT_1 |
+               (adapter->tx_ring->ctx_id << 16));
+       cmd.rsp.num = QLCNIC_83XX_TX_STAT_REGS;
+       data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+                                       QLCNIC_83XX_STAT_TX, &ret);
+       if (ret) {
+               dev_info(&adapter->pdev->dev,
+                       "Error getting MAC stats\n");
+               goto out;
+       }
+       /* Get MAC stats */
+       cmd.req.arg[1] = cpu_to_le32(BIT_2 | (adapter->portnum << 16));
+       cmd.rsp.num = QLCNIC_83XX_MAC_STAT_REGS;
+       memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+       data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+                                       QLCNIC_83XX_STAT_MAC, &ret);
+       if (ret) {
+               dev_info(&adapter->pdev->dev,
+                       "Error getting Rx stats\n");
+               goto out;
+       }
+       /* Get Rx stats */
+       cmd.req.arg[1] = cpu_to_le32(adapter->recv_ctx->context_id << 16);
+       cmd.rsp.num = QLCNIC_83XX_RX_STAT_REGS;
+       memset(cmd.rsp.arg, 0, sizeof(u32) * cmd.rsp.num);
+       data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
+                                       QLCNIC_83XX_STAT_RX, &ret);
+       if (ret)
+               dev_info(&adapter->pdev->dev,
+                       "Error in getting Tx stats\n");
+out:
+       qlcnic_free_mbx_args(&cmd);
+}
 
 #define QLCNIC_RING_REGS_COUNT 20
 #define QLCNIC_RING_REGS_LEN   (QLCNIC_RING_REGS_COUNT * sizeof(u32))
 #define QLCNIC_MAX_EEPROM_LEN   1024
 
 static const u32 diag_registers[] = {
-       CRB_CMDPEG_STATE,
-       CRB_RCVPEG_STATE,
-       CRB_XG_STATE_P3P,
-       CRB_FW_CAPABILITIES_1,
-       ISR_INT_STATE_REG,
+       QLCNIC_CMDPEG_STATE,
+       QLCNIC_RCVPEG_STATE,
+       QLCNIC_FW_CAPABILITIES,
        QLCNIC_CRB_DRV_ACTIVE,
        QLCNIC_CRB_DEV_STATE,
        QLCNIC_CRB_DRV_STATE,
@@ -149,6 +295,12 @@ static const u32 diag_registers[] = {
        QLCNIC_PEG_ALIVE_COUNTER,
        QLCNIC_PEG_HALT_STATUS1,
        QLCNIC_PEG_HALT_STATUS2,
+       -1
+};
+
+static const u32 ext_diag_registers[] = {
+       CRB_XG_STATE_P3P,
+       ISR_INT_STATE_REG,
        QLCNIC_CRB_PEG_NET_0+0x3c,
        QLCNIC_CRB_PEG_NET_1+0x3c,
        QLCNIC_CRB_PEG_NET_2+0x3c,
@@ -157,12 +309,19 @@ static const u32 diag_registers[] = {
 };
 
 #define QLCNIC_MGMT_API_VERSION        2
-#define QLCNIC_DEV_INFO_SIZE   1
 #define QLCNIC_ETHTOOL_REGS_VER        2
+
 static int qlcnic_get_regs_len(struct net_device *dev)
 {
-       return sizeof(diag_registers) + QLCNIC_RING_REGS_LEN +
-                               QLCNIC_DEV_INFO_SIZE + 1;
+       struct qlcnic_adapter *adapter =netdev_priv(dev);
+       u32 len;
+
+       if (QLCNIC_IS_83XX(adapter))
+               len = qlcnic_83xx_get_regs_len(adapter);
+       else
+               len = sizeof(ext_diag_registers) + sizeof(diag_registers);
+
+       return QLCNIC_RING_REGS_LEN + len + QLCNIC_DEV_INFO_SIZE + 1;
 }
 
 static int qlcnic_get_eeprom_len(struct net_device *dev)
@@ -175,10 +334,9 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 fw_major, fw_minor, fw_build;
-
-       fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
-       fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
-       fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+       fw_major = QLCRD(adapter, QLCNIC_FW_VERSION_MAJOR);
+       fw_minor = QLCRD(adapter, QLCNIC_FW_VERSION_MINOR);
+       fw_build = QLCRD(adapter, QLCNIC_FW_VERSION_SUB);
        snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
                "%d.%d.%d", fw_major, fw_minor, fw_build);
 
@@ -193,10 +351,12 @@ static int
 qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
-       int check_sfp_module = 0;
+       struct qlcnic_hardware_context *ahw= adapter->ahw;
+       int err, check_sfp_module = 0;
+       u16 pcifn = ahw->pci_func;
 
        /* read which mode */
-       if (adapter->ahw->port_type == QLCNIC_GBE) {
+       if (ahw->port_type == QLCNIC_GBE) {
                ecmd->supported = (SUPPORTED_10baseT_Half |
                                   SUPPORTED_10baseT_Full |
                                   SUPPORTED_100baseT_Half |
@@ -209,14 +369,17 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                                     ADVERTISED_1000baseT_Half |
                                     ADVERTISED_1000baseT_Full);
 
-               ethtool_cmd_speed_set(ecmd, adapter->link_speed);
-               ecmd->duplex = adapter->link_duplex;
-               ecmd->autoneg = adapter->link_autoneg;
+               ethtool_cmd_speed_set(ecmd, ahw->link_speed);
+               ecmd->duplex = ahw->link_duplex;
+               ecmd->autoneg = ahw->link_autoneg;
 
-       } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
-               u32 val;
-
-               val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
+       } else if (ahw->port_type == QLCNIC_XGBE) {
+               u32 val = 0;
+               if (QLCNIC_IS_83XX(adapter)) {
+                       qlcnic_83xx_get_settings(adapter);
+               } else {
+                       val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
+               }
                if (val == QLCNIC_PORT_MODE_802_3_AP) {
                        ecmd->supported = SUPPORTED_1000baseT_Full;
                        ecmd->advertising = ADVERTISED_1000baseT_Full;
@@ -225,10 +388,13 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                        ecmd->advertising = ADVERTISED_10000baseT_Full;
                }
 
-               if (netif_running(dev) && adapter->has_link_events) {
-                       ethtool_cmd_speed_set(ecmd, adapter->link_speed);
-                       ecmd->autoneg = adapter->link_autoneg;
-                       ecmd->duplex = adapter->link_duplex;
+               if (netif_running(dev) && ahw->has_link_events) {
+                       if (QLCNIC_IS_82XX(adapter))
+                               ahw->link_speed =
+                               QLCNIC_READ_LINK_SPEED(adapter, pcifn, &err);
+                       ethtool_cmd_speed_set(ecmd, ahw->link_speed);
+                       ecmd->autoneg = ahw->link_autoneg;
+                       ecmd->duplex = ahw->link_duplex;
                        goto skip;
                }
 
@@ -239,10 +405,10 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                return -EIO;
 
 skip:
-       ecmd->phy_address = adapter->physical_port;
+       ecmd->phy_address = adapter->ahw->physical_port;
        ecmd->transceiver = XCVR_EXTERNAL;
 
-       switch (adapter->ahw->board_type) {
+       switch (ahw->board_type) {
        case QLCNIC_BRDTYPE_P3P_REF_QG:
        case QLCNIC_BRDTYPE_P3P_4_GB:
        case QLCNIC_BRDTYPE_P3P_4_GB_MM:
@@ -255,7 +421,7 @@ skip:
                ecmd->supported |= SUPPORTED_TP;
                ecmd->advertising |= ADVERTISED_TP;
                ecmd->port = PORT_TP;
-               ecmd->autoneg =  adapter->link_autoneg;
+               ecmd->autoneg =  ahw->link_autoneg;
                break;
        case QLCNIC_BRDTYPE_P3P_IMEZ:
        case QLCNIC_BRDTYPE_P3P_XG_LOM:
@@ -271,7 +437,7 @@ skip:
                ecmd->advertising |= ADVERTISED_TP;
                ecmd->supported |= SUPPORTED_TP;
                check_sfp_module = netif_running(dev) &&
-                       adapter->has_link_events;
+                       ahw->has_link_events;
        case QLCNIC_BRDTYPE_P3P_10G_XFP:
                ecmd->supported |= SUPPORTED_FIBRE;
                ecmd->advertising |= ADVERTISED_FIBRE;
@@ -279,14 +445,14 @@ skip:
                ecmd->autoneg = AUTONEG_DISABLE;
                break;
        case QLCNIC_BRDTYPE_P3P_10G_TP:
-               if (adapter->ahw->port_type == QLCNIC_XGBE) {
+               if (ahw->port_type == QLCNIC_XGBE) {
                        ecmd->autoneg = AUTONEG_DISABLE;
                        ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
                        ecmd->advertising |=
                                (ADVERTISED_FIBRE | ADVERTISED_TP);
                        ecmd->port = PORT_FIBRE;
                        check_sfp_module = netif_running(dev) &&
-                               adapter->has_link_events;
+                               ahw->has_link_events;
                } else {
                        ecmd->autoneg = AUTONEG_ENABLE;
                        ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
@@ -295,14 +461,21 @@ skip:
                        ecmd->port = PORT_TP;
                }
                break;
+       case QLCNIC_BRDTYPE_83XX_10G:
+               ecmd->autoneg = AUTONEG_DISABLE;
+               ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
+               ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP);
+               ecmd->port = PORT_FIBRE;
+               check_sfp_module = netif_running(dev) && ahw->has_link_events;
+               break;
        default:
                dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
-                       adapter->ahw->board_type);
+                       ahw->board_type);
                return -EIO;
        }
 
        if (check_sfp_module) {
-               switch (adapter->module_type) {
+               switch (adapter->ahw->module_type) {
                case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
                case LINKEVENT_MODULE_OPTICAL_SRLR:
                case LINKEVENT_MODULE_OPTICAL_LRM:
@@ -323,15 +496,10 @@ skip:
 }
 
 static int
-qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+qlcnic_set_port_config(struct qlcnic_adapter *adapter,
+       struct ethtool_cmd *ecmd)
 {
-       u32 config = 0;
-       u32 ret = 0;
-       struct qlcnic_adapter *adapter = netdev_priv(dev);
-
-       if (adapter->ahw->port_type != QLCNIC_GBE)
-               return -EOPNOTSUPP;
-
+       u32 ret = 0, config = 0;
        /* read which mode */
        if (ecmd->duplex)
                config |= 0x1;
@@ -359,10 +527,29 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                return -EOPNOTSUPP;
        else if (ret)
                return -EIO;
+       return ret;
+}
+
+static int
+qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       u32 ret = 0;
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
 
-       adapter->link_speed = ethtool_cmd_speed(ecmd);
-       adapter->link_duplex = ecmd->duplex;
-       adapter->link_autoneg = ecmd->autoneg;
+       if (adapter->ahw->port_type != QLCNIC_GBE)
+               return -EOPNOTSUPP;
+
+       if (QLCNIC_IS_83XX(adapter))
+               ret = qlcnic_83xx_set_settings(adapter, ecmd);
+       else
+               ret = qlcnic_set_port_config(adapter, ecmd);
+
+       if (!ret)
+               return ret;
+
+       adapter->ahw->link_speed = ethtool_cmd_speed(ecmd);
+       adapter->ahw->link_duplex = ecmd->duplex;
+       adapter->ahw->link_autoneg = ecmd->autoneg;
 
        if (!netif_running(dev))
                return 0;
@@ -371,24 +558,42 @@ qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        return dev->netdev_ops->ndo_open(dev);
 }
 
+static int
+qlcnic_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff)
+{
+       int err, i, j = 0;
+
+       for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
+               regs_buff[i] = QLCRD(adapter, diag_registers[j]);
+       j = 0;
+       while (ext_diag_registers[j] != -1)
+               regs_buff[i++] = QLCRD32(adapter,
+                                       ext_diag_registers[j++], &err);
+       return i;
+}
+
 static void
 qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
        struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 *regs_buff = p;
-       int ring, i = 0, j = 0;
+       int ring, i = 0;
 
        memset(p, 0, qlcnic_get_regs_len(dev));
+
        regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
-               (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
+               (ahw->revision_id << 16) | (adapter->pdev)->device;
 
        regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
        regs_buff[1] = QLCNIC_MGMT_API_VERSION;
 
-       for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
-               regs_buff[i] = QLCRD32(adapter, diag_registers[j]);
+       if (QLCNIC_IS_82XX(adapter))
+               i = qlcnic_get_registers(adapter, regs_buff);
+       else
+               i = qlcnic_83xx_get_registers(adapter, regs_buff);
 
        if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
                return;
@@ -413,10 +618,15 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 
 static u32 qlcnic_test_link(struct net_device *dev)
 {
+       int err;
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 val;
 
-       val = QLCRD32(adapter, CRB_XG_STATE_P3P);
+       if (QLCNIC_IS_83XX(adapter)) {
+               val = qlcnic_83xx_test_link(adapter);
+               return (val & 1) ? 0 : 1;
+       }
+       val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err);
        val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
        return (val == XG_LINK_UP_P3P) ? 0 : 1;
 }
@@ -427,8 +637,10 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        int offset;
-       int ret;
+       int ret = -1;
 
+       if (QLCNIC_IS_83XX(adapter))
+               return 0;
        if (eeprom->len == 0)
                return -EINVAL;
 
@@ -436,7 +648,8 @@ qlcnic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        ((adapter->pdev)->device << 16);
        offset = eeprom->offset;
 
-       ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
+       if (QLCNIC_IS_82XX(adapter))
+               ret = qlcnic_rom_fast_read_words(adapter, offset, bytes,
                                                eeprom->len);
        if (ret < 0)
                return ret;
@@ -512,11 +725,11 @@ static void qlcnic_get_channels(struct net_device *dev,
        struct qlcnic_adapter *adapter = netdev_priv(dev);
 
        channel->max_rx = rounddown_pow_of_two(min_t(int,
-                       adapter->max_rx_ques, num_online_cpus()));
-       channel->max_tx = adapter->max_tx_ques;
+                       adapter->ahw->max_rx_ques, num_online_cpus()));
+       channel->max_tx = adapter->ahw->max_tx_ques;
 
        channel->rx_count = adapter->max_sds_rings;
-       channel->tx_count = adapter->max_tx_ques;
+       channel->tx_count = adapter->ahw->max_tx_ques;
 }
 
 static int qlcnic_set_channels(struct net_device *dev,
@@ -529,13 +742,21 @@ static int qlcnic_set_channels(struct net_device *dev,
            channel->tx_count != channel->max_tx)
                return -EINVAL;
 
-       err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
-       if (err)
-               return err;
+       if (!(adapter->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))) {
+               netdev_err(dev, "no msix or msi support, hence no rss\n");
+               return -EINVAL;
+       }
+
+       err = qlcnic_validate_max_rss(channel->max_rx, channel->rx_count);
+       if (err) {
+               netdev_err(dev, "rss_ring valid range[1 - %d] in powers of 2\n",
+                          err);
+               return -EINVAL;
+       }
 
        err = qlcnic_set_max_rss(adapter, channel->rx_count);
        netdev_info(dev, "allocated 0x%x sds rings\n",
-                                adapter->max_sds_rings);
+                   adapter->max_sds_rings);
        return err;
 }
 
@@ -543,17 +764,23 @@ static void
 qlcnic_get_pauseparam(struct net_device *netdev,
                          struct ethtool_pauseparam *pause)
 {
+       int err;
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       int port = adapter->physical_port;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int port = adapter->ahw->physical_port;
        __u32 val;
 
-       if (adapter->ahw->port_type == QLCNIC_GBE) {
+       if (QLCNIC_IS_83XX(adapter)) {
+               qlcnic_83xx_get_pauseparam(adapter, pause);
+               return;
+       }
+       if (ahw->port_type == QLCNIC_GBE) {
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
                        return;
                /* get flow control settings */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
                pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
                switch (port) {
                case 0:
                        pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
@@ -569,11 +796,11 @@ qlcnic_get_pauseparam(struct net_device *netdev,
                        pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
                        break;
                }
-       } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
+       } else if (ahw->port_type == QLCNIC_XGBE) {
                if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
                        return;
                pause->rx_pause = 1;
-               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
                if (port == 0)
                        pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
                else
@@ -589,25 +816,28 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                          struct ethtool_pauseparam *pause)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       int port = adapter->physical_port;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int err, port = adapter->ahw->physical_port;
        __u32 val;
 
+       if (QLCNIC_IS_83XX(adapter))
+               return qlcnic_83xx_set_pauseparam(adapter, pause);
+
        /* read mode */
-       if (adapter->ahw->port_type == QLCNIC_GBE) {
+       if (ahw->port_type == QLCNIC_GBE) {
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
                        return -EIO;
                /* set flow control */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
 
                if (pause->rx_pause)
                        qlcnic_gb_rx_flowctl(val);
                else
                        qlcnic_gb_unset_rx_flowctl(val);
 
-               QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port),
-                               val);
+               QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
                /* set autoneg */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
                switch (port) {
                case 0:
                        if (pause->tx_pause)
@@ -636,14 +866,14 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                        break;
                }
                QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
-       } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
+       } else if (ahw->port_type == QLCNIC_XGBE) {
                if (!pause->rx_pause || pause->autoneg)
                        return -EOPNOTSUPP;
 
                if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
                        return -EIO;
 
-               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
                if (port == 0) {
                        if (pause->tx_pause)
                                qlcnic_xg_unset_xg0_mask(val);
@@ -665,16 +895,30 @@ qlcnic_set_pauseparam(struct net_device *netdev,
 
 static int qlcnic_reg_test(struct net_device *dev)
 {
+       int err;
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 data_read;
 
-       data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
+       if (QLCNIC_IS_83XX(adapter))
+               return qlcnic_83xx_reg_test(adapter);
+
+       data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err);
        if ((data_read & 0xffff) != adapter->pdev->vendor)
                return 1;
 
        return 0;
 }
 
+static int qlcnic_eeprom_test(struct net_device *dev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+       if (QLCNIC_IS_82XX(adapter))
+               return 0;
+
+       return qlcnic_83xx_eeprom_test(adapter);
+}
+
 static int qlcnic_get_sset_count(struct net_device *dev, int sset)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
@@ -682,9 +926,11 @@ static int qlcnic_get_sset_count(struct net_device *dev, int sset)
        case ETH_SS_TEST:
                return QLCNIC_TEST_LEN;
        case ETH_SS_STATS:
-               if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
-                       return QLCNIC_TOTAL_STATS_LEN + QLCNIC_DEVICE_STATS_LEN;
-               return QLCNIC_TOTAL_STATS_LEN;
+               if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+                       QLCNIC_IS_83XX(adapter))
+                       return QLCNIC_STATS_LEN +
+                               QLCNIC_DEVICE_STATS_LEN(adapter);
+               return QLCNIC_82XX_STATS;
        default:
                return -EOPNOTSUPP;
        }
@@ -697,40 +943,38 @@ static int qlcnic_irq_test(struct net_device *netdev)
        int ret;
        struct qlcnic_cmd_args cmd;
 
+       if (QLCNIC_IS_83XX(adapter))
+               return qlcnic_83xx_interrupt_test(netdev);
+
        if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
                return -EIO;
 
        ret = qlcnic_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
        if (ret)
-               goto clear_it;
+               goto clear_diag_irq;
 
-       adapter->diag_cnt = 0;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.req.cmd = QLCNIC_CDRP_CMD_INTRPT_TEST;
-       cmd.req.arg1 = adapter->ahw->pci_func;
-       qlcnic_issue_cmd(adapter, &cmd);
-       ret = cmd.rsp.cmd;
+       adapter->ahw->diag_cnt = 0;
+       adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_INTRPT_TEST);
 
+       cmd.req.arg[1] = cpu_to_le32(adapter->ahw->pci_func);
+       ret = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
        if (ret)
                goto done;
 
        msleep(10);
-
-       ret = !adapter->diag_cnt;
+       ret = !adapter->ahw->diag_cnt;
 
 done:
+       qlcnic_free_mbx_args(&cmd);
        qlcnic_diag_free_res(netdev, max_sds_rings);
 
-clear_it:
+clear_diag_irq:
        adapter->max_sds_rings = max_sds_rings;
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
        return ret;
 }
 
-#define QLCNIC_ILB_PKT_SIZE 64
-#define QLCNIC_NUM_ILB_PKT     16
-#define QLCNIC_ILB_MAX_RCV_LOOP 10
-
 static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
 {
        unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};
@@ -750,7 +994,7 @@ int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
        return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
 }
 
-static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
+int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
 {
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
        struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
@@ -758,31 +1002,34 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
        int i, loop, cnt = 0;
 
        for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
-               skb = netdev_alloc_skb(adapter->netdev, QLCNIC_ILB_PKT_SIZE);
+               skb = dev_alloc_skb(QLCNIC_ILB_PKT_SIZE);
                qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
                skb_put(skb, QLCNIC_ILB_PKT_SIZE);
 
-               adapter->diag_cnt = 0;
+               adapter->ahw->diag_cnt = 0;
                qlcnic_xmit_frame(skb, adapter->netdev);
 
                loop = 0;
                do {
                        msleep(1);
-                       qlcnic_process_rcv_ring_diag(sds_ring);
+                       adapter->ahw->hw_ops->process_lb_rcv_ring_diag(sds_ring);
                        if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
                                break;
-               } while (!adapter->diag_cnt);
+               } while (!adapter->ahw->diag_cnt);
 
                dev_kfree_skb_any(skb);
 
-               if (!adapter->diag_cnt)
-                       QLCDB(adapter, DRV,
-                       "LB Test: packet #%d was not received\n", i + 1);
+               if (!adapter->ahw->diag_cnt)
+                       netdev_warn(adapter->netdev,
+                               "LB Test: packet #%d was not received\n",
+                               i + 1);
                else
                        cnt++;
        }
        if (cnt != i) {
-               dev_warn(&adapter->pdev->dev, "LB Test failed\n");
+               netdev_err(adapter->netdev,
+                       "LB Test: failed, pkts sent[%d], received[%d]\n",
+                       i, cnt);
                if (mode != QLCNIC_ILB_MODE) {
                        dev_warn(&adapter->pdev->dev,
                                "WARNING: Please make sure external"
@@ -793,22 +1040,26 @@ static int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
        return 0;
 }
 
-static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
+int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int max_sds_rings = adapter->max_sds_rings;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        struct qlcnic_host_sds_ring *sds_ring;
        int loop = 0;
        int ret;
 
-       if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
+       if (QLCNIC_IS_83XX(adapter))
+               return qlcnic_83xx_loopback_test(netdev, mode);
+
+       if (!(ahw->capabilities & QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK)) {
                netdev_info(netdev, "Firmware is not loopback test capable\n");
                return -EOPNOTSUPP;
        }
 
        QLCDB(adapter, DRV, "%s loopback test in progress\n",
                   mode == QLCNIC_ILB_MODE ? "internal" : "external");
-       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+       if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
                netdev_warn(netdev, "Loopback test not supported for non "
                                "privilege function\n");
                return 0;
@@ -827,7 +1078,7 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
        if (ret)
                goto free_res;
 
-       adapter->diag_cnt = 0;
+       ahw->diag_cnt = 0;
        do {
                msleep(500);
                qlcnic_process_rcv_ring_diag(sds_ring);
@@ -836,15 +1087,15 @@ static int qlcnic_loopback_test(struct net_device *netdev, u8 mode)
                                " configure request\n");
                        ret = -QLCNIC_FW_NOT_RESPOND;
                        goto free_res;
-               } else if (adapter->diag_cnt) {
-                       ret = adapter->diag_cnt;
+               } else if (ahw->diag_cnt) {
+                       ret = ahw->diag_cnt;
                        goto free_res;
                }
-       } while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));
+       } while (!QLCNIC_IS_LB_CONFIGURED(ahw->loopback_state));
 
        ret = qlcnic_do_lb_test(adapter, mode);
 
-       qlcnic_clear_lb_mode(adapter);
+       qlcnic_clear_lb_mode(adapter, mode);
 
  free_res:
        qlcnic_diag_free_res(netdev, max_sds_rings);
@@ -877,12 +1128,10 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
                data[3] = qlcnic_loopback_test(dev, QLCNIC_ILB_MODE);
                if (data[3])
                        eth_test->flags |= ETH_TEST_FL_FAILED;
-               if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
-                       data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
-                       if (data[4])
-                               eth_test->flags |= ETH_TEST_FL_FAILED;
-                       eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
-               }
+
+               data[4] = qlcnic_eeprom_test(dev);
+               if (data[4])
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
        }
 }
 
@@ -890,7 +1139,7 @@ static void
 qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
-       int index, i, j;
+       int index, i, num_stats;
 
        switch (stringset) {
        case ETH_SS_TEST:
@@ -903,14 +1152,34 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
                               qlcnic_gstrings_stats[index].stat_string,
                               ETH_GSTRING_LEN);
                }
-               for (j = 0; j < QLCNIC_MAC_STATS_LEN; index++, j++) {
-                       memcpy(data + index * ETH_GSTRING_LEN,
-                              qlcnic_mac_stats_strings[j],
-                              ETH_GSTRING_LEN);
+               if (QLCNIC_IS_83XX(adapter)) {
+                       num_stats = ARRAY_SIZE(qlc_83xx_tx_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                       qlc_83xx_tx_stats_strings[i],
+                                       ETH_GSTRING_LEN);
+                       num_stats = ARRAY_SIZE(qlc_83xx_mac_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                       qlc_83xx_mac_stats_strings[i],
+                                       ETH_GSTRING_LEN);
+                       num_stats = ARRAY_SIZE(qlc_83xx_rx_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                       qlc_83xx_rx_stats_strings[i],
+                                       ETH_GSTRING_LEN);
+                       return;
+               } else {
+                       num_stats = ARRAY_SIZE(qlc_83xx_mac_stats_strings);
+                       for (i = 0; i < num_stats; i++, index++)
+                               memcpy(data + index * ETH_GSTRING_LEN,
+                                       qlc_83xx_mac_stats_strings[i],
+                                       ETH_GSTRING_LEN);
                }
                if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
                        return;
-               for (i = 0; i < QLCNIC_DEVICE_STATS_LEN; index++, i++) {
+               num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats);
+               for (i = 0; i < num_stats; index++, i++) {
                        memcpy(data + index * ETH_GSTRING_LEN,
                               qlcnic_device_gstrings_stats[i],
                               ETH_GSTRING_LEN);
@@ -919,65 +1188,55 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
 }
 
 static void
-qlcnic_fill_stats(int *index, u64 *data, void *stats, int type)
+qlcnic_fill_stats(u64 *data, void *stats, int type)
 {
-       int ind = *index;
-
        if (type == QLCNIC_MAC_STATS) {
                struct qlcnic_mac_statistics *mac_stats =
                                        (struct qlcnic_mac_statistics *)stats;
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
-               data[ind++] =
-                       QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_rx_crc_error);
-               data[ind++] = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_frames);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bytes);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_mcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_bcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_pause_cnt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_ctrl_pkt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_64b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_127b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_255b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_511b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1023b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_lt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_tx_gt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_frames);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bytes);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_mcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_bcast_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_pause_cnt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_ctrl_pkt);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_64b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_127b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_255b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_511b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1023b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_lt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_gt_1518b_pkts);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_error);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_small);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_length_large);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_jabber);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_rx_dropped);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_FCS_error);
+               *data++ = QLCNIC_FILL_STATS(mac_stats->mac_align_error);
        } else if (type == QLCNIC_ESW_STATS) {
                struct __qlcnic_esw_statistics *esw_stats =
                                (struct __qlcnic_esw_statistics *)stats;
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->errors);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->local_frames);
-               data[ind++] = QLCNIC_FILL_STATS(esw_stats->numbytes);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->unicast_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->multicast_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->broadcast_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->dropped_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->errors);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
+               *data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
        }
-
-       *index = ind;
 }
 
 static void
@@ -987,21 +1246,28 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        struct qlcnic_esw_statistics port_stats;
        struct qlcnic_mac_statistics mac_stats;
-       int index, ret;
+       int index, ret, length;
 
-       for (index = 0; index < QLCNIC_STATS_LEN; index++) {
+       memset(data, 0, stats->n_stats * sizeof(u64));
+       length = QLCNIC_STATS_LEN;
+       for (index = 0; index < length; index++) {
                char *p =
                    (char *)adapter +
                    qlcnic_gstrings_stats[index].stat_offset;
-               data[index] =
-                   (qlcnic_gstrings_stats[index].sizeof_stat ==
+               *data++ = (qlcnic_gstrings_stats[index].sizeof_stat ==
                     sizeof(u64)) ? *(u64 *)p:(*(u32 *)p);
        }
 
-       /* Retrieve MAC statistics from firmware */
-       memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
-       qlcnic_get_mac_stats(adapter, &mac_stats);
-       qlcnic_fill_stats(&index, data, &mac_stats, QLCNIC_MAC_STATS);
+       if (QLCNIC_IS_83XX(adapter)) {
+               if (adapter->ahw->linkup)
+                       qlcnic_83xx_get_stats(adapter, data);
+               return;
+       } else {
+               /* Retrieve MAC statistics from firmware */
+               memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
+               qlcnic_get_mac_stats(adapter, &mac_stats);
+               qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
+       }
 
        if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
                return;
@@ -1012,14 +1278,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
        if (ret)
                return;
 
-       qlcnic_fill_stats(&index, data, &port_stats.rx, QLCNIC_ESW_STATS);
+       qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
 
        ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
                        QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
        if (ret)
                return;
 
-       qlcnic_fill_stats(&index, data, &port_stats.tx, QLCNIC_ESW_STATS);
+       qlcnic_fill_stats(data, &port_stats.tx, QLCNIC_ESW_STATS);
 }
 
 static int qlcnic_set_led(struct net_device *dev,
@@ -1029,7 +1295,7 @@ static int qlcnic_set_led(struct net_device *dev,
        int max_sds_rings = adapter->max_sds_rings;
        int err = -EIO, active = 1;
 
-       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+       if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
                netdev_warn(dev, "LED test not supported for non "
                                "privilege function\n");
                return -EOPNOTSUPP;
@@ -1037,6 +1303,19 @@ static int qlcnic_set_led(struct net_device *dev,
 
        switch (state) {
        case ETHTOOL_ID_ACTIVE:
+               if (QLCNIC_IS_83XX(adapter) &&
+                       !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+
+                       if (test_and_set_bit(__QLCNIC_LED_ENABLE,
+                                                       &adapter->state))
+                               return -EBUSY;
+
+                       err = qlcnic_83xx_config_led(adapter, active, 0);
+                       if (err)
+                               clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+                       return err;
+               }
+
                if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
                        return -EBUSY;
 
@@ -1049,7 +1328,7 @@ static int qlcnic_set_led(struct net_device *dev,
                        set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
                }
 
-               if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0) {
+               if (adapter->nic_ops->config_led(adapter, active, 0xf) == 0) {
                        err = 0;
                        break;
                }
@@ -1061,6 +1340,15 @@ static int qlcnic_set_led(struct net_device *dev,
        case ETHTOOL_ID_INACTIVE:
                active = 0;
 
+               if (QLCNIC_IS_83XX(adapter) &&
+                       !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+
+                       err = qlcnic_83xx_config_led(adapter, active, 0);
+                       if (!err)
+                               clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+                       return err;
+               }
+
                if (test_bit(__QLCNIC_RESETTING, &adapter->state))
                        break;
 
@@ -1070,7 +1358,7 @@ static int qlcnic_set_led(struct net_device *dev,
                        set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
                }
 
-               if (adapter->nic_ops->config_led(adapter, 0, 0xf))
+               if (adapter->nic_ops->config_led(adapter, active, 0xf))
                        dev_err(&adapter->pdev->dev,
                                "Failed to reset LED blink state.\n");
 
@@ -1092,17 +1380,20 @@ static int qlcnic_set_led(struct net_device *dev,
 static void
 qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
+       int err;
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
 
+       if (QLCNIC_IS_83XX(adapter))
+               return;
        wol->supported = 0;
        wol->wolopts = 0;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
        if (wol_cfg & (1UL << adapter->portnum))
                wol->supported |= WAKE_MAGIC;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
        if (wol_cfg & (1UL << adapter->portnum))
                wol->wolopts |= WAKE_MAGIC;
 }
@@ -1110,17 +1401,20 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static int
 qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
+       int err;
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
 
+       if (QLCNIC_IS_83XX(adapter))
+               return -EOPNOTSUPP;
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EOPNOTSUPP;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
        if (!(wol_cfg & (1 << adapter->portnum)))
                return -EOPNOTSUPP;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
        if (wol->wolopts & WAKE_MAGIC)
                wol_cfg |= 1UL << adapter->portnum;
        else
@@ -1185,7 +1479,7 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,
                        ethcoal->rx_max_coalesced_frames;
        }
 
-       qlcnic_config_intr_coalesce(adapter);
+       adapter->ahw->hw_ops->config_intr_coal(adapter);
 
        return 0;
 }
@@ -1208,14 +1502,14 @@ static u32 qlcnic_get_msglevel(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
-       return adapter->msg_enable;
+       return adapter->ahw->msg_enable;
 }
 
 static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
-       adapter->msg_enable = msglvl;
+       adapter->ahw->msg_enable = msglvl;
 }
 
 static int
@@ -1224,21 +1518,11 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
 
-       if (!fw_dump->tmpl_hdr) {
-               netdev_err(adapter->netdev, "FW Dump not supported\n");
-               return -ENOTSUPP;
-       }
-
        if (fw_dump->clr)
                dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
        else
                dump->len = 0;
-
-       if (!fw_dump->enable)
-               dump->flag = ETH_FW_DUMP_DISABLE;
-       else
-               dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
-
+       dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
        dump->version = adapter->fw_version;
        return 0;
 }
@@ -1252,14 +1536,9 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
 
-       if (!fw_dump->tmpl_hdr) {
-               netdev_err(netdev, "FW Dump not supported\n");
-               return -ENOTSUPP;
-       }
-
        if (!fw_dump->clr) {
                netdev_info(netdev, "Dump not available\n");
-               return -EINVAL;
+               return 0;
        }
        /* Copy template header first */
        copy_sz = fw_dump->tmpl_hdr->size;
@@ -1284,74 +1563,57 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
 static int
 qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 {
-       int i;
+       int ret = 0;
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
-       u32 state;
 
        switch (val->flag) {
        case QLCNIC_FORCE_FW_DUMP_KEY:
-               if (!fw_dump->tmpl_hdr) {
-                       netdev_err(netdev, "FW dump not supported\n");
-                       return -ENOTSUPP;
-               }
                if (!fw_dump->enable) {
                        netdev_info(netdev, "FW dump not enabled\n");
-                       return 0;
+                       return ret;
                }
                if (fw_dump->clr) {
                        netdev_info(netdev,
                        "Previous dump not cleared, not forcing dump\n");
-                       return 0;
+                       return ret;
                }
                netdev_info(netdev, "Forcing a FW dump\n");
-               qlcnic_dev_request_reset(adapter);
+               adapter->nic_ops->request_reset(adapter,
+                                       QLCNIC_FORCE_FW_DUMP_KEY);
                break;
        case QLCNIC_DISABLE_FW_DUMP:
-               if (fw_dump->enable && fw_dump->tmpl_hdr) {
+               if (fw_dump->enable) {
                        netdev_info(netdev, "Disabling FW dump\n");
                        fw_dump->enable = 0;
                }
-               return 0;
+               break;
        case QLCNIC_ENABLE_FW_DUMP:
-               if (!fw_dump->tmpl_hdr) {
-                       netdev_err(netdev, "FW dump not supported\n");
-                       return -ENOTSUPP;
-               }
-               if (!fw_dump->enable) {
+               if (!fw_dump->enable && fw_dump->tmpl_hdr) {
                        netdev_info(netdev, "Enabling FW dump\n");
                        fw_dump->enable = 1;
                }
-               return 0;
+               break;
        case QLCNIC_FORCE_FW_RESET:
                netdev_info(netdev, "Forcing a FW reset\n");
-               qlcnic_dev_request_reset(adapter);
+               adapter->nic_ops->request_reset(adapter,
+                                       QLCNIC_FORCE_FW_RESET);
                adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
-               return 0;
-       case QLCNIC_SET_QUIESCENT:
-       case QLCNIC_RESET_QUIESCENT:
-               state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-               if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-                       netdev_info(netdev, "Device in FAILED state\n");
-               return 0;
+               break;
        default:
-               if (!fw_dump->tmpl_hdr) {
-                       netdev_err(netdev, "FW dump not supported\n");
-                       return -ENOTSUPP;
-               }
-               for (i = 0; i < ARRAY_SIZE(FW_DUMP_LEVELS); i++) {
-                       if (val->flag == FW_DUMP_LEVELS[i]) {
-                               fw_dump->tmpl_hdr->drv_cap_mask =
-                                                       val->flag;
-                               netdev_info(netdev, "Driver mask changed to: 0x%x\n",
-                                       fw_dump->tmpl_hdr->drv_cap_mask);
-                               return 0;
-                       }
+               if (val->flag > QLCNIC_DUMP_MASK_MAX ||
+                       val->flag < QLCNIC_DUMP_MASK_MIN) {
+                               netdev_info(netdev,
+                               "Invalid dump level: 0x%x\n", val->flag);
+                               ret = -EINVAL;
+                               goto out;
                }
-               netdev_info(netdev, "Invalid dump level: 0x%x\n", val->flag);
-               return -EINVAL;
+               fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
+               netdev_info(netdev, "Driver mask changed to: 0x%x\n",
+                       fw_dump->tmpl_hdr->drv_cap_mask);
        }
-       return 0;
+out:
+       return ret;
 }
 
 const struct ethtool_ops qlcnic_ethtool_ops = {
@@ -1384,10 +1646,3 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
        .get_dump_data = qlcnic_get_dump_data,
        .set_dump = qlcnic_set_dump,
 };
-
-const struct ethtool_ops qlcnic_ethtool_failed_ops = {
-       .get_settings = qlcnic_get_settings,
-       .get_drvinfo = qlcnic_get_drvinfo,
-       .set_msglevel = qlcnic_set_msglevel,
-       .get_msglevel = qlcnic_get_msglevel,
-};
index 28a6b28192e302227a9b02552c0acef56e6ea560..f1d1f9fc61dc4a3dfa18a5675e278148fac77a42 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+#include "qlcnic_hw.h"
+
 /*
  * The basic unit of access when reading/writing control registers.
  */
@@ -387,9 +389,6 @@ enum {
 #define QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014)
 #define QLCNIC_ROMUSB_ROM_RDATA                (ROMUSB_ROM + 0x0018)
 
-/* Lock IDs for ROM lock */
-#define ROM_LOCK_DRIVER        0x0d417340
-
 /******************************************************************************
 *
 *    Definitions specific to M25P flash
@@ -449,13 +448,10 @@ enum {
 #define ISR_INT_TARGET_STATUS_F7   (QLCNIC_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
 #define ISR_INT_TARGET_MASK_F7     (QLCNIC_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
 
-#define QLCNIC_PCI_MN_2M       (0)
-#define QLCNIC_PCI_MS_2M       (0x80000)
 #define QLCNIC_PCI_OCM0_2M     (0x000c0000UL)
 #define QLCNIC_PCI_CRBSPACE    (0x06000000UL)
 #define QLCNIC_PCI_CAMQM       (0x04800000UL)
 #define QLCNIC_PCI_CAMQM_END   (0x04800800UL)
-#define QLCNIC_PCI_2MB_SIZE    (0x00200000UL)
 #define QLCNIC_PCI_CAMQM_2M_BASE       (0x000ff800UL)
 
 #define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM)
@@ -491,7 +487,7 @@ enum {
 #define QLCNIC_NIU_GB_MAC_CONFIG_1(I)          \
                (QLCNIC_CRB_NIU + 0x30004 + (I)*0x10000)
 
-
+#define MAX_CTL_CHECK   1000
 #define TEST_AGT_CTRL  (0x00)
 
 #define TA_CTL_START   BIT_0
@@ -499,43 +495,26 @@ enum {
 #define TA_CTL_WRITE   BIT_2
 #define TA_CTL_BUSY    BIT_3
 
-/*
- *   Register offsets for MN
- */
-#define MIU_TEST_AGT_BASE              (0x90)
-
-#define MIU_TEST_AGT_ADDR_LO           (0x04)
-#define MIU_TEST_AGT_ADDR_HI           (0x08)
-#define MIU_TEST_AGT_WRDATA_LO         (0x10)
-#define MIU_TEST_AGT_WRDATA_HI         (0x14)
-#define MIU_TEST_AGT_WRDATA_UPPER_LO   (0x20)
-#define MIU_TEST_AGT_WRDATA_UPPER_HI   (0x24)
-#define MIU_TEST_AGT_WRDATA(i)         (0x10+(0x10*((i)>>1))+(4*((i)&1)))
-#define MIU_TEST_AGT_RDDATA_LO         (0x18)
-#define MIU_TEST_AGT_RDDATA_HI         (0x1c)
-#define MIU_TEST_AGT_RDDATA_UPPER_LO   (0x28)
-#define MIU_TEST_AGT_RDDATA_UPPER_HI   (0x2c)
-#define MIU_TEST_AGT_RDDATA(i)         (0x18+(0x10*((i)>>1))+(4*((i)&1)))
-
-#define MIU_TEST_AGT_ADDR_MASK         0xfffffff8
-#define MIU_TEST_AGT_UPPER_ADDR(off)   (0)
+#define QLCNIC_MS_CTRL     0x41000090
+#define QLCNIC_MS_ADDR_LO  0x41000094
+#define QLCNIC_MS_ADDR_HI  0x41000098
 
-/*
- *   Register offsets for MS
- */
-#define SIU_TEST_AGT_BASE              (0x60)
+#define QLCNIC_MS_WRTDATA_LO       0x410000A0
+#define QLCNIC_MS_WRTDATA_HI       0x410000A4
+#define QLCNIC_MS_WRTDATA_ULO      0x410000B0
+#define QLCNIC_MS_WRTDATA_UHI      0x410000B4
 
-#define SIU_TEST_AGT_ADDR_LO           (0x04)
-#define SIU_TEST_AGT_ADDR_HI           (0x18)
-#define SIU_TEST_AGT_WRDATA_LO         (0x08)
-#define SIU_TEST_AGT_WRDATA_HI         (0x0c)
-#define SIU_TEST_AGT_WRDATA(i)         (0x08+(4*(i)))
-#define SIU_TEST_AGT_RDDATA_LO         (0x10)
-#define SIU_TEST_AGT_RDDATA_HI         (0x14)
-#define SIU_TEST_AGT_RDDATA(i)         (0x10+(4*(i)))
+#define QLCNIC_MS_RDDATA_LO        0x410000A8
+#define QLCNIC_MS_RDDATA_HI        0x410000AC
+#define QLCNIC_MS_RDDATA_ULO       0x410000B8
+#define QLCNIC_MS_RDDATA_UHI       0x410000BC
 
-#define SIU_TEST_AGT_ADDR_MASK         0x3ffff8
-#define SIU_TEST_AGT_UPPER_ADDR(off)   ((off)>>22)
+static const u32 QLCNIC_MS_READ_DATA[] = {
+       0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
+
+#define QLC_TA_WRITE_ENABLE (TA_CTL_ENABLE | TA_CTL_WRITE)
+#define QLC_TA_WRITE_START (TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE)
+#define QLC_TA_START_ENABLE (TA_CTL_START | TA_CTL_ENABLE)
 
 /* XG Link status */
 #define XG_LINK_UP     0x10
@@ -556,9 +535,6 @@ enum {
 
 #define QLCNIC_CAM_RAM_BASE    (QLCNIC_CRB_CAM + 0x02000)
 #define QLCNIC_CAM_RAM(reg)    (QLCNIC_CAM_RAM_BASE + (reg))
-#define QLCNIC_FW_VERSION_MAJOR (QLCNIC_CAM_RAM(0x150))
-#define QLCNIC_FW_VERSION_MINOR (QLCNIC_CAM_RAM(0x154))
-#define QLCNIC_FW_VERSION_SUB  (QLCNIC_CAM_RAM(0x158))
 #define QLCNIC_ROM_LOCK_ID     (QLCNIC_CAM_RAM(0x100))
 #define QLCNIC_PHY_LOCK_ID     (QLCNIC_CAM_RAM(0x120))
 #define QLCNIC_CRB_WIN_LOCK_ID (QLCNIC_CAM_RAM(0x124))
@@ -568,28 +544,16 @@ enum {
 #define QLCNIC_REG(X)          (NIC_CRB_BASE+(X))
 #define QLCNIC_REG_2(X)        (NIC_CRB_BASE_2+(X))
 
+#define QLCNIC_CDRP_MAX_ARGS   4
+#define QLCNIC_CDRP_ARG(i)             (QLCNIC_REG(0x18 + ((i) * 4)))
 #define QLCNIC_CDRP_CRB_OFFSET         (QLCNIC_REG(0x18))
-#define QLCNIC_ARG1_CRB_OFFSET         (QLCNIC_REG(0x1c))
-#define QLCNIC_ARG2_CRB_OFFSET         (QLCNIC_REG(0x20))
-#define QLCNIC_ARG3_CRB_OFFSET         (QLCNIC_REG(0x24))
 #define QLCNIC_SIGN_CRB_OFFSET         (QLCNIC_REG(0x28))
 
-#define CRB_CMDPEG_STATE               (QLCNIC_REG(0x50))
-#define CRB_RCVPEG_STATE               (QLCNIC_REG(0x13c))
-
 #define CRB_XG_STATE_P3P               (QLCNIC_REG(0x98))
 #define CRB_PF_LINK_SPEED_1            (QLCNIC_REG(0xe8))
-#define CRB_PF_LINK_SPEED_2            (QLCNIC_REG(0xec))
 
-#define CRB_TEMP_STATE                 (QLCNIC_REG(0x1b4))
-
-#define CRB_V2P_0                      (QLCNIC_REG(0x290))
-#define CRB_V2P(port)                  (CRB_V2P_0+((port)*4))
 #define CRB_DRIVER_VERSION             (QLCNIC_REG(0x2a0))
-
-#define CRB_FW_CAPABILITIES_1          (QLCNIC_CAM_RAM(0x128))
-#define CRB_FW_CAPABILITIES_2          (QLCNIC_CAM_RAM(0x12c))
-#define CRB_MAC_BLOCK_START            (QLCNIC_CAM_RAM(0x1c0))
+#define CRB_FW_CAPABILITIES_2           (QLCNIC_CAM_RAM(0x12c))
 
 /*
  * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
@@ -616,11 +580,6 @@ enum {
 /* Lock IDs for PHY lock */
 #define PHY_LOCK_DRIVER                0x44524956
 
-/* Used for PS PCI Memory access */
-#define PCIX_PS_OP_ADDR_LO     (0x10000)
-/*   via CRB  (PS side only)     */
-#define PCIX_PS_OP_ADDR_HI     (0x10004)
-
 #define PCIX_INT_VECTOR        (0x10100)
 #define PCIX_INT_MASK          (0x10104)
 
@@ -682,17 +641,6 @@ enum {
 #define QLCNIC_PEG_TUNE_CAPABILITY     (QLCNIC_CAM_RAM(0x02c))
 
 #define QLCNIC_DMA_WATCHDOG_CTRL       (QLCNIC_CAM_RAM(0x14))
-#define QLCNIC_PEG_ALIVE_COUNTER       (QLCNIC_CAM_RAM(0xb0))
-#define QLCNIC_PEG_HALT_STATUS1        (QLCNIC_CAM_RAM(0xa8))
-#define QLCNIC_PEG_HALT_STATUS2        (QLCNIC_CAM_RAM(0xac))
-#define QLCNIC_CRB_DRV_ACTIVE  (QLCNIC_CAM_RAM(0x138))
-#define QLCNIC_CRB_DEV_STATE           (QLCNIC_CAM_RAM(0x140))
-
-#define QLCNIC_CRB_DRV_STATE           (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH         (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO  (QLCNIC_CAM_RAM(0x14c))
-#define QLCNIC_CRB_DRV_IDC_VER         (QLCNIC_CAM_RAM(0x174))
-#define QLCNIC_CRB_DEV_NPAR_STATE      (QLCNIC_CAM_RAM(0x19c))
 #define QLCNIC_ROM_DEV_INIT_TIMEOUT    (0x3e885c)
 #define QLCNIC_ROM_DRV_RESET_TIMEOUT   (0x3e8860)
 
@@ -705,13 +653,10 @@ enum {
 #define QLCNIC_DEV_FAILED              0x6
 #define QLCNIC_DEV_QUISCENT            0x7
 
-#define QLCNIC_DEV_BADBAD              0xbad0bad0
-
 #define QLCNIC_DEV_NPAR_NON_OPER       0 /* NON Operational */
 #define QLCNIC_DEV_NPAR_OPER           1 /* NPAR Operational */
 #define QLCNIC_DEV_NPAR_OPER_TIMEO     30 /* Operational time out */
 
-#define QLC_DEV_CHECK_ACTIVE(VAL, FN)          ((VAL) & (1 << (FN * 4)))
 #define QLC_DEV_SET_REF_CNT(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
 #define QLC_DEV_CLR_REF_CNT(VAL, FN)           ((VAL) &= ~(1 << (FN * 4)))
 #define QLC_DEV_SET_RST_RDY(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
@@ -730,7 +675,7 @@ enum {
 #define QLCNIC_RCODE_FATAL_ERROR               BIT_31
 #define QLCNIC_FWERROR_PEGNUM(code)            ((code) & 0xff)
 #define QLCNIC_FWERROR_CODE(code)              ((code >> 8) & 0x1fffff)
-#define QLCNIC_FWERROR_FAN_FAILURE             0x16
+#define        QLCNIC_FWERROR_FAN_FAILURE              0x16
 
 #define FW_POLL_DELAY          (1 * HZ)
 #define FW_FAIL_THRESH         2
@@ -744,6 +689,9 @@ enum {
 #define QLCNIC_HEARTBEAT_PERIOD_MSECS  200
 #define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT     45
 
+#define QLCNIC_MAX_MC_COUNT            38
+#define QLCNIC_WATCHDOG_TIMEOUTVALUE   5
+
 #define        ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
 #define ISR_LEGACY_INT_TRIGGERED(VAL)  (((VAL) & 0x300) == 0x200)
 
@@ -763,29 +711,16 @@ struct qlcnic_legacy_intr_set {
        u32     int_vec_bit;
        u32     tgt_status_reg;
        u32     tgt_mask_reg;
-       u32     pci_int_reg;
 };
 
-#define QLCNIC_FW_API          0x1b216c
-#define QLCNIC_DRV_OP_MODE     0x1b2170
 #define QLCNIC_MSIX_BASE       0x132110
 #define QLCNIC_MAX_PCI_FUNC    8
 #define QLCNIC_MAX_VLAN_FILTERS        64
 
 /* FW dump defines */
-#define MIU_TEST_CTR           0x41000090
-#define MIU_TEST_ADDR_LO       0x41000094
-#define MIU_TEST_ADDR_HI       0x41000098
 #define FLASH_ROM_WINDOW       0x42110030
 #define FLASH_ROM_DATA         0x42150000
 
-
-static const u32 FW_DUMP_LEVELS[] = {
-       0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff };
-
-static const u32 MIU_TEST_READ_DATA[] = {
-       0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
-
 #define QLCNIC_FW_DUMP_REG1    0x00130060
 #define QLCNIC_FW_DUMP_REG2    0x001e0000
 #define QLCNIC_FLASH_SEM2_LK   0x0013C010
@@ -812,7 +747,8 @@ static const u32 MIU_TEST_READ_DATA[] = {
 enum {
        QLCNIC_MGMT_FUNC        = 0,
        QLCNIC_PRIV_FUNC        = 1,
-       QLCNIC_NON_PRIV_FUNC    = 2
+       QLCNIC_NON_PRIV_FUNC    = 2,
+       QLCNIC_UNKNOWN_FUNC_MODE = 3
 };
 
 enum {
@@ -837,50 +773,42 @@ enum {
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F0,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS,          \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK,            \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(0) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK, },         \
                                                                        \
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F1,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS_F1,       \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F1,         \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(1) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F1, },      \
                                                                        \
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F2,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS_F2,       \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F2,         \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(2) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F2, },      \
                                                                        \
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F3,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS_F3,       \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F3,         \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(3) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F3, },      \
                                                                        \
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F4,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS_F4,       \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F4,         \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(4) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F4, },      \
                                                                        \
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F5,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS_F5,       \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F5,         \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(5) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F5, },      \
                                                                        \
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F6,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS_F6,       \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F6,         \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(6) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F6, },      \
                                                                        \
        {                                                               \
                .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F7,         \
                .tgt_status_reg =       ISR_INT_TARGET_STATUS_F7,       \
-               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F7,         \
-               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(7) },       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F7, },      \
 }
 
 /* NIU REGS */
@@ -1021,6 +949,8 @@ enum {
 #define QLCNIC_NIU_PROMISC_MODE                1
 #define QLCNIC_NIU_ALLMULTI_MODE       2
 
+#define QLCNIC_PCIE_SEM_TIMEOUT        10000
+
 struct crb_128M_2M_sub_block_map {
        unsigned valid;
        unsigned start_128M;
@@ -1031,4 +961,5 @@ struct crb_128M_2M_sub_block_map {
 struct crb_128M_2M_block_map{
        struct crb_128M_2M_sub_block_map sub_block[16];
 };
+
 #endif                         /* __QLCNIC_HDR_H_ */
index 2a0c9dc48eb38a5a3a85a06145ae12ce3db84309..e2ceda5d26109027d964a210b0d9b5a531e05800 100644 (file)
@@ -6,23 +6,14 @@
  */
 
 #include "qlcnic.h"
+#include "qlcnic_hdr.h"
+#include "qlcnic_83xx.h"
+#include "qlcnic_hw.h"
 
 #include <linux/slab.h>
 #include <net/ip.h>
 #include <linux/bitops.h>
 
-#define MASK(n) ((1ULL<<(n))-1)
-#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
-
-#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
-
-#define CRB_BLK(off)   ((off >> 20) & 0x3f)
-#define CRB_SUBBLK(off)        ((off >> 16) & 0xf)
-#define CRB_WINDOW_2M  (0x130060)
-#define CRB_HI(off)    ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000))
-#define CRB_INDIRECT_2M        (0x1e0000UL)
-
-
 #ifndef readq
 static inline u64 readq(void __iomem *addr)
 {
@@ -38,7 +29,7 @@ static inline void writeq(u64 val, void __iomem *addr)
 }
 #endif
 
-static struct crb_128M_2M_block_map
+static const struct crb_128M_2M_block_map
 crb_128M_2M_map[64] __cacheline_aligned_in_smp = {
     {{{0, 0,         0,         0} } },                /* 0: PCI */
     {{{1, 0x0100000, 0x0102000, 0x120000},     /* 1: PCIE */
@@ -266,23 +257,30 @@ static const unsigned crb_hub_agt[64] = {
        0,
 };
 
-/*  PCI Windowing for DDR regions.  */
+static const u32 msi_tgt_status[8] = {
+       ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
+       ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
+       ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
+       ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
+};
 
-#define QLCNIC_PCIE_SEM_TIMEOUT        10000
+/*  PCI Windowing for DDR regions.  */
 
 int
 qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 {
-       int done = 0, timeout = 0;
+       int err, done = 0, timeout = 0;
 
        while (!done) {
-               done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)));
+               done = QLCRD32(adapter,
+                       QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)), &err);
                if (done == 1)
                        break;
                if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
                        dev_err(&adapter->pdev->dev,
-                               "Failed to acquire sem=%d lock; holdby=%d\n",
-                               sem, id_reg ? QLCRD32(adapter, id_reg) : -1);
+                               "Failed to acquire sem=%d lock; held by=%d\n",
+                               sem,
+                               id_reg ? QLCRD32(adapter, id_reg, &err) : -1);
                        return -EIO;
                }
                msleep(1);
@@ -297,7 +295,8 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 void
 qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
 {
-       QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
+       int err;
+       QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err);
 }
 
 static int
@@ -357,9 +356,9 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-static int
+int
 qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
-                               __le16 vlan_id, unsigned op)
+                               __le16 vlan_id, u8 op)
 {
        struct qlcnic_nic_req req;
        struct qlcnic_mac_req *mac_req;
@@ -402,7 +401,7 @@ static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
        }
        memcpy(cur->mac_addr, addr, ETH_ALEN);
 
-       if (qlcnic_sre_macaddr_change(adapter,
+       if (adapter->ahw->hw_ops->change_macvlan(adapter,
                                cur->mac_addr, 0, QLCNIC_MAC_ADD)) {
                kfree(cur);
                return -EIO;
@@ -434,7 +433,7 @@ void qlcnic_set_multi(struct net_device *netdev)
        }
 
        if ((netdev->flags & IFF_ALLMULTI) ||
-           (netdev_mc_count(netdev) > adapter->max_mc_count)) {
+           (netdev_mc_count(netdev) > adapter->ahw->max_mc_count)) {
                mode = VPORT_MISS_MODE_ACCEPT_MULTI;
                goto send_fw_cmd;
        }
@@ -453,7 +452,7 @@ send_fw_cmd:
                adapter->mac_learn = 0;
        }
 
-       qlcnic_nic_set_promisc(adapter, mode);
+       adapter->ahw->hw_ops->config_promisc_mode(adapter, mode);
 }
 
 int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
@@ -482,7 +481,7 @@ void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
 
        while (!list_empty(head)) {
                cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
-               qlcnic_sre_macaddr_change(adapter,
+               adapter->ahw->hw_ops->change_macvlan(adapter,
                                cur->mac_addr, 0, QLCNIC_MAC_DEL);
                list_del(&cur->list);
                kfree(cur);
@@ -496,14 +495,14 @@ void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
        struct hlist_head *head;
        int i;
 
-       for (i = 0; i < adapter->fhash.fmax; i++) {
+       for (i = 0; i < adapter->fhash.fbucket_size; i++) {
                head = &(adapter->fhash.fhead[i]);
 
                hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode)
                {
                        if (jiffies >
                                (QLCNIC_FILTER_AGE * HZ + tmp_fil->ftime)) {
-                               qlcnic_sre_macaddr_change(adapter,
+                               adapter->ahw->hw_ops->change_macvlan(adapter,
                                        tmp_fil->faddr, tmp_fil->vlan_id,
                                        tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
                                        QLCNIC_MAC_DEL);
@@ -524,13 +523,14 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
        struct hlist_head *head;
        int i;
 
-       for (i = 0; i < adapter->fhash.fmax; i++) {
+       for (i = 0; i < adapter->fhash.fbucket_size; i++) {
                head = &(adapter->fhash.fhead[i]);
 
                hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
-                       qlcnic_sre_macaddr_change(adapter, tmp_fil->faddr,
-                               tmp_fil->vlan_id, tmp_fil->vlan_id ?
-                               QLCNIC_MAC_VLAN_DEL :  QLCNIC_MAC_DEL);
+                       adapter->ahw->hw_ops->change_macvlan(adapter,
+                               tmp_fil->faddr, tmp_fil->vlan_id,
+                               tmp_fil->vlan_id ?  QLCNIC_MAC_VLAN_DEL :
+                               QLCNIC_MAC_DEL);
                        spin_lock_bh(&adapter->mac_learn_lock);
                        adapter->fhash.fnum--;
                        hlist_del(&tmp_fil->fnode);
@@ -565,7 +565,8 @@ int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
        if (qlcnic_set_fw_loopback(adapter, mode))
                return -EIO;
 
-       if (qlcnic_nic_set_promisc(adapter, VPORT_MISS_MODE_ACCEPT_ALL)) {
+       if (adapter->ahw->hw_ops->config_promisc_mode(adapter,
+               VPORT_MISS_MODE_ACCEPT_ALL)) {
                qlcnic_set_fw_loopback(adapter, 0);
                return -EIO;
        }
@@ -574,11 +575,11 @@ int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
        return 0;
 }
 
-void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
+int qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
 {
-       int mode = VPORT_MISS_MODE_DROP;
        struct net_device *netdev = adapter->netdev;
 
+       mode = VPORT_MISS_MODE_DROP;
        qlcnic_set_fw_loopback(adapter, 0);
 
        if (netdev->flags & IFF_PROMISC)
@@ -586,14 +587,15 @@ void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
        else if (netdev->flags & IFF_ALLMULTI)
                mode = VPORT_MISS_MODE_ACCEPT_MULTI;
 
-       qlcnic_nic_set_promisc(adapter, mode);
+       adapter->ahw->hw_ops->config_promisc_mode(adapter, mode);
        msleep(1000);
+       return 0;
 }
 
 /*
  * Send the interrupt coalescing parameter set by ethtool to the card.
  */
-int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
+void qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_nic_req req;
        int rv;
@@ -615,7 +617,6 @@ int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
        if (rv != 0)
                dev_err(&adapter->netdev->dev,
                        "Could not send interrupt coalescing parameters\n");
-       return rv;
 }
 
 int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
@@ -673,9 +674,6 @@ int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
        return rv;
 }
 
-
-#define RSS_HASHTYPE_IP_TCP    0x3
-
 int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
 {
        struct qlcnic_nic_req req;
@@ -719,7 +717,7 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable)
        return rv;
 }
 
-int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
+void qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
 {
        struct qlcnic_nic_req req;
        struct qlcnic_ipaddr *ipa;
@@ -739,10 +737,8 @@ int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd)
        rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
        if (rv != 0)
                dev_err(&adapter->netdev->dev,
-                               "could not notify %s IP 0x%x reuqest\n",
+                               "could not notify %s IP 0x%x request\n",
                                (cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
-
-       return rv;
 }
 
 int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable)
@@ -750,14 +746,12 @@ int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable)
        struct qlcnic_nic_req req;
        u64 word;
        int rv;
-
        memset(&req, 0, sizeof(struct qlcnic_nic_req));
        req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
 
        word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
        req.req_hdr = cpu_to_le64(word);
        req.words[0] = cpu_to_le64(enable | (enable << 8));
-
        rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
        if (rv != 0)
                dev_err(&adapter->netdev->dev,
@@ -817,13 +811,13 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
 }
 
 
-netdev_features_t qlcnic_fix_features(struct net_device *netdev,
-       netdev_features_t features)
+u32 qlcnic_fix_features(struct net_device *netdev, u32 features)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
-       if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               netdev_features_t changed = features ^ netdev->features;
+       if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
+           QLCNIC_IS_82XX(adapter)) {
+               u32 changed = features ^ netdev->features;
                features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
        }
 
@@ -834,19 +828,27 @@ netdev_features_t qlcnic_fix_features(struct net_device *netdev,
 }
 
 
-int qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
+int qlcnic_set_features(struct net_device *netdev, u32 features)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       netdev_features_t changed = netdev->features ^ features;
+       u32 changed = netdev->features ^ features;
        int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0;
 
+       if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
+                                       QLCNIC_IS_82XX(adapter))
+               return -EOPNOTSUPP;
        if (!(changed & NETIF_F_LRO))
                return 0;
 
        netdev->features = features ^ NETIF_F_LRO;
 
-       if (qlcnic_config_hw_lro(adapter, hw_lro))
-               return -EIO;
+       if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+               if (adapter->ahw->hw_ops->config_hw_lro(adapter, hw_lro))
+                       return -EIO;
+       }
+
+       if (QLCNIC_IS_83XX(adapter))
+               return 0;
 
        if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
                return -EIO;
@@ -864,7 +866,7 @@ int qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
  * In: 'off' is offset from base in 128M pci map
  */
 static int
-qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
+qlcnic_pci_get_crb_addr_2M(struct qlcnic_hardware_context *ahw,
                ulong off, void __iomem **addr)
 {
        const struct crb_128M_2M_sub_block_map *m;
@@ -880,7 +882,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
        m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)];
 
        if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) {
-               *addr = adapter->ahw->pci_base0 + m->start_2M +
+               *addr = ahw->pci_base0 + m->start_2M +
                        (off - m->start_128M);
                return 0;
        }
@@ -888,7 +890,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
        /*
         * Not in direct map, use crb window
         */
-       *addr = adapter->ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
+       *addr = ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
        return 1;
 }
 
@@ -929,7 +931,7 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
        int rv;
        void __iomem *addr = NULL;
 
-       rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
+       rv = qlcnic_pci_get_crb_addr_2M(adapter->ahw, off, &addr);
 
        if (rv == 0) {
                writel(data, addr);
@@ -955,14 +957,14 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
 }
 
 u32
-qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off, int *err)
 {
        unsigned long flags;
        int rv;
        u32 data = -1;
        void __iomem *addr = NULL;
 
-       rv = qlcnic_pci_get_crb_addr_2M(adapter, off, &addr);
+       rv = qlcnic_pci_get_crb_addr_2M(adapter->ahw, off, &addr);
 
        if (rv == 0)
                return readl(addr);
@@ -981,50 +983,36 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
        dev_err(&adapter->pdev->dev,
                        "%s: invalid offset: 0x%016lx\n", __func__, off);
        dump_stack();
+       if (err)
+               *err = -1;
+
        return -1;
 }
 
 
 void __iomem *
-qlcnic_get_ioaddr(struct qlcnic_adapter *adapter, u32 offset)
+qlcnic_get_ioaddr(struct qlcnic_hardware_context *ahw, u32 offset)
 {
        void __iomem *addr = NULL;
 
-       WARN_ON(qlcnic_pci_get_crb_addr_2M(adapter, offset, &addr));
+       WARN_ON(qlcnic_pci_get_crb_addr_2M(ahw, offset, &addr));
 
        return addr;
 }
 
-
 static int
-qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter,
-               u64 addr, u32 *start)
-{
-       u32 window;
-
-       window = OCM_WIN_P3P(addr);
-
-       writel(window, adapter->ahw->ocm_win_crb);
-       /* read back to flush */
-       readl(adapter->ahw->ocm_win_crb);
-
-       *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr);
-       return 0;
-}
-
-static int
-qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off,
-               u64 *data, int op)
+qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u32 window,
+       u64 off, u64 *data, int op)
 {
        void __iomem *addr;
-       int ret;
        u32 start;
 
        mutex_lock(&adapter->ahw->mem_lock);
 
-       ret = qlcnic_pci_set_window_2M(adapter, off, &start);
-       if (ret != 0)
-               goto unlock;
+       writel(window, adapter->ahw->ocm_win_crb);
+       /* read back to flush */
+       readl(adapter->ahw->ocm_win_crb);
+       start = QLCNIC_PCI_OCM0_2M + off;
 
        addr = adapter->ahw->pci_base0 + start;
 
@@ -1033,10 +1021,12 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off,
        else            /* write */
                writeq(*data, addr);
 
-unlock:
-       mutex_unlock(&adapter->ahw->mem_lock);
+       /* Set window to 0 */
+       writel(0, adapter->ahw->ocm_win_crb);
+       readl(adapter->ahw->ocm_win_crb);
 
-       return ret;
+       mutex_unlock(&adapter->ahw->mem_lock);
+       return 0;
 }
 
 void
@@ -1063,52 +1053,79 @@ qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
 
 #define MAX_CTL_CHECK   1000
 
+/* Set MS memory control data for different chip type*/
+static void
+qlcnic_set_ms_controls(struct qlcnic_adapter *adapter, u64 off,
+       struct qlcnic_ms_reg_ctrl *ms)
+{
+       ms->control = QLCNIC_MS_CTRL;
+       ms->low = QLCNIC_MS_ADDR_LO;
+       ms->hi = QLCNIC_MS_ADDR_HI;
+       if (off & 0xf) {
+               ms->wd[0] = QLCNIC_MS_WRTDATA_LO;
+               ms->rd[0] = QLCNIC_MS_RDDATA_LO;
+               ms->wd[1] = QLCNIC_MS_WRTDATA_HI;
+               ms->rd[1] = QLCNIC_MS_RDDATA_HI;
+               ms->wd[2] = QLCNIC_MS_WRTDATA_ULO;
+               ms->wd[3] = QLCNIC_MS_WRTDATA_UHI;
+               ms->rd[2] = QLCNIC_MS_RDDATA_ULO;
+               ms->rd[3] = QLCNIC_MS_RDDATA_UHI;
+       } else {
+               ms->wd[0] = QLCNIC_MS_WRTDATA_ULO;
+               ms->rd[0] = QLCNIC_MS_RDDATA_ULO;
+               ms->wd[1] = QLCNIC_MS_WRTDATA_UHI;
+               ms->rd[1] = QLCNIC_MS_RDDATA_UHI;
+               ms->wd[2] = QLCNIC_MS_WRTDATA_LO;
+               ms->wd[3] = QLCNIC_MS_WRTDATA_HI;
+               ms->rd[2] = QLCNIC_MS_RDDATA_LO;
+               ms->rd[3] = QLCNIC_MS_RDDATA_HI;
+       }
+       if (QLCNIC_IS_83XX(adapter)) {
+               ms->ocm_window = OCM_WIN_83XX(off);
+               ms->off = GET_83XX_OCM_OFFSET(off);
+       } else {
+               ms->ocm_window = OCM_WIN_P3P(off);
+               ms->off = GET_MEM_OFFS_2M(off);
+       }
+}
+
 int
 qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
                u64 off, u64 data)
 {
-       int i, j, ret;
+       int j, ret = 0;
        u32 temp, off8;
-       void __iomem *mem_crb;
+       struct qlcnic_ms_reg_ctrl ms;
 
        /* Only 64-bit aligned access */
        if (off & 7)
                return -EIO;
 
-       /* P3 onward, test agent base for MIU and SIU is same */
-       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
-                               QLCNIC_ADDR_QDR_NET_MAX)) {
-               mem_crb = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
-               goto correct;
-       }
+       memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl));
+       if (!((ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
+               QLCNIC_ADDR_QDR_NET_MAX)) ||
+                       (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET,
+                               QLCNIC_ADDR_DDR_NET_MAX))))
+               return -EIO;
 
-       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) {
-               mem_crb = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE);
-               goto correct;
-       }
+       qlcnic_set_ms_controls(adapter, off, &ms);
 
        if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
-               return qlcnic_pci_mem_access_direct(adapter, off, &data, 1);
-
-       return -EIO;
+               return qlcnic_pci_mem_access_direct(adapter, ms.ocm_window,
+                       ms.off, &data, 1);
 
-correct:
        off8 = off & ~0xf;
 
        mutex_lock(&adapter->ahw->mem_lock);
 
-       writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
-       writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
+       qlcnic_ind_wr(adapter, ms.low, off8);
+       qlcnic_ind_wr(adapter, ms.hi, 0);
 
-       i = 0;
-       writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
-       writel((TA_CTL_START | TA_CTL_ENABLE),
-                       (mem_crb + TEST_AGT_CTRL));
+       qlcnic_ind_wr(adapter, ms.control, TA_CTL_ENABLE);
+       qlcnic_ind_wr(adapter, ms.control, QLC_TA_START_ENABLE);
 
        for (j = 0; j < MAX_CTL_CHECK; j++) {
-               temp = readl(mem_crb + TEST_AGT_CTRL);
+               temp = qlcnic_ind_rd(adapter, ms.control);
                if ((temp & TA_CTL_BUSY) == 0)
                        break;
        }
@@ -1118,24 +1135,18 @@ correct:
                goto done;
        }
 
-       i = (off & 0xf) ? 0 : 2;
-       writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i)),
-                       mem_crb + MIU_TEST_AGT_WRDATA(i));
-       writel(readl(mem_crb + MIU_TEST_AGT_RDDATA(i+1)),
-                       mem_crb + MIU_TEST_AGT_WRDATA(i+1));
-       i = (off & 0xf) ? 2 : 0;
+       /* This is the modify part of read-modify-write */
+       qlcnic_ind_wr(adapter, ms.wd[0], qlcnic_ind_rd(adapter, ms.rd[0]));
+       qlcnic_ind_wr(adapter, ms.wd[1], qlcnic_ind_rd(adapter, ms.rd[1]));
+       /* This is the write part of read-modify-write */
+       qlcnic_ind_wr(adapter, ms.wd[2], data & 0xffffffff);
+       qlcnic_ind_wr(adapter, ms.wd[3], (data >> 32) & 0xffffffff);
 
-       writel(data & 0xffffffff,
-                       mem_crb + MIU_TEST_AGT_WRDATA(i));
-       writel((data >> 32) & 0xffffffff,
-                       mem_crb + MIU_TEST_AGT_WRDATA(i+1));
-
-       writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
-       writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
-                       (mem_crb + TEST_AGT_CTRL));
+       qlcnic_ind_wr(adapter, ms.control, QLC_TA_WRITE_ENABLE);
+       qlcnic_ind_wr(adapter, ms.control, QLC_TA_WRITE_START);
 
        for (j = 0; j < MAX_CTL_CHECK; j++) {
-               temp = readl(mem_crb + TEST_AGT_CTRL);
+               temp = qlcnic_ind_rd(adapter, ms.control);
                if ((temp & TA_CTL_BUSY) == 0)
                        break;
        }
@@ -1161,45 +1172,36 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter,
        int j, ret;
        u32 temp, off8;
        u64 val;
-       void __iomem *mem_crb;
+       struct qlcnic_ms_reg_ctrl ms;
 
        /* Only 64-bit aligned access */
        if (off & 7)
                return -EIO;
+       if (!((ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
+               QLCNIC_ADDR_QDR_NET_MAX)) ||
+                       (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET,
+                               QLCNIC_ADDR_DDR_NET_MAX))))
+               return -EIO ;
 
-       /* P3 onward, test agent base for MIU and SIU is same */
-       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
-                               QLCNIC_ADDR_QDR_NET_MAX)) {
-               mem_crb = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
-               goto correct;
-       }
-
-       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET, QLCNIC_ADDR_DDR_NET_MAX)) {
-               mem_crb = qlcnic_get_ioaddr(adapter,
-                               QLCNIC_CRB_DDR_NET+MIU_TEST_AGT_BASE);
-               goto correct;
-       }
+       memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl));
+       qlcnic_set_ms_controls(adapter, off, &ms);
 
-       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX)) {
-               return qlcnic_pci_mem_access_direct(adapter,
-                               off, data, 0);
-       }
+       if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
+               return qlcnic_pci_mem_access_direct(adapter, ms.ocm_window,
+                       ms.off, data, 0);
 
-       return -EIO;
+       mutex_lock(&adapter->ahw->mem_lock);
 
-correct:
        off8 = off & ~0xf;
 
-       mutex_lock(&adapter->ahw->mem_lock);
+       qlcnic_ind_wr(adapter, ms.low, off8);
+       qlcnic_ind_wr(adapter, ms.hi, 0);
 
-       writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
-       writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
-       writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
-       writel((TA_CTL_START | TA_CTL_ENABLE), (mem_crb + TEST_AGT_CTRL));
+       qlcnic_ind_wr(adapter, ms.control, TA_CTL_ENABLE);
+       qlcnic_ind_wr(adapter, ms.control, QLC_TA_START_ENABLE);
 
        for (j = 0; j < MAX_CTL_CHECK; j++) {
-               temp = readl(mem_crb + TEST_AGT_CTRL);
+               temp = qlcnic_ind_rd(adapter, ms.control);
                if ((temp & TA_CTL_BUSY) == 0)
                        break;
        }
@@ -1210,13 +1212,10 @@ correct:
                                        "failed to read through agent\n");
                ret = -EIO;
        } else {
-               off8 = MIU_TEST_AGT_RDDATA_LO;
-               if (off & 0xf)
-                       off8 = MIU_TEST_AGT_RDDATA_UPPER_LO;
 
-               temp = readl(mem_crb + off8 + 4);
+               temp = qlcnic_ind_rd(adapter, ms.rd[3]);
                val = (u64)temp << 32;
-               val |= readl(mem_crb + off8);
+               val |= qlcnic_ind_rd(adapter, ms.rd[2]);
                *data = val;
                ret = 0;
        }
@@ -1228,8 +1227,9 @@ correct:
 
 int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
 {
-       int offset, board_type, magic;
+       int offset, board_type, magic, err;
        struct pci_dev *pdev = adapter->pdev;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        offset = QLCNIC_FW_MAGIC_OFFSET;
        if (qlcnic_rom_fast_read(adapter, offset, &magic))
@@ -1245,10 +1245,10 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
        if (qlcnic_rom_fast_read(adapter, offset, &board_type))
                return -EIO;
 
-       adapter->ahw->board_type = board_type;
+       ahw->board_type = board_type;
 
        if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
-               u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
+               u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err);
                if ((gpio & 0x8000) == 0)
                        board_type = QLCNIC_BRDTYPE_P3P_10G_TP;
        }
@@ -1264,20 +1264,20 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
        case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
        case QLCNIC_BRDTYPE_P3P_10G_XFP:
        case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
-               adapter->ahw->port_type = QLCNIC_XGBE;
+               ahw->port_type = QLCNIC_XGBE;
                break;
        case QLCNIC_BRDTYPE_P3P_REF_QG:
        case QLCNIC_BRDTYPE_P3P_4_GB:
        case QLCNIC_BRDTYPE_P3P_4_GB_MM:
-               adapter->ahw->port_type = QLCNIC_GBE;
+               ahw->port_type = QLCNIC_GBE;
                break;
        case QLCNIC_BRDTYPE_P3P_10G_TP:
-               adapter->ahw->port_type = (adapter->portnum < 2) ?
+               ahw->port_type = (adapter->portnum < 2) ?
                        QLCNIC_XGBE : QLCNIC_GBE;
                break;
        default:
                dev_err(&pdev->dev, "unknown board type %x\n", board_type);
-               adapter->ahw->port_type = QLCNIC_XGBE;
+               ahw->port_type = QLCNIC_XGBE;
                break;
        }
 
@@ -1287,11 +1287,12 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
 int
 qlcnic_wol_supported(struct qlcnic_adapter *adapter)
 {
+       int err;
        u32 wol_cfg;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
        if (wol_cfg & (1UL << adapter->portnum)) {
-               wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+               wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
                if (wol_cfg & (1 << adapter->portnum))
                        return 1;
        }
@@ -1321,468 +1322,95 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
        return rv;
 }
 
-/* FW dump related functions */
-static u32
-qlcnic_dump_crb(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
-               u32 *buffer)
+void qlcnic_get_func_no(struct qlcnic_adapter *adapter)
 {
-       int i;
-       u32 addr, data;
-       struct __crb *crb = &entry->region.crb;
-       void __iomem *base = adapter->ahw->pci_base0;
-
-       addr = crb->addr;
-
-       for (i = 0; i < crb->no_ops; i++) {
-               QLCNIC_RD_DUMP_REG(addr, base, &data);
-               *buffer++ = cpu_to_le32(addr);
-               *buffer++ = cpu_to_le32(data);
-               addr += crb->stride;
-       }
-       return crb->no_ops * 2 * sizeof(u32);
+       void __iomem *msix_base_addr;
+       u32 func;
+       u32 msix_base;
+
+       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;
 }
 
-static u32
-qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
-       struct qlcnic_dump_entry *entry, u32 *buffer)
+void qlcnic_get_ocm_win(struct qlcnic_hardware_context *ahw)
 {
-       int i, k, timeout = 0;
-       void __iomem *base = adapter->ahw->pci_base0;
-       u32 addr, data;
-       u8 opcode, no_ops;
-       struct __ctrl *ctr = &entry->region.ctrl;
-       struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
-
-       addr = ctr->addr;
-       no_ops = ctr->no_ops;
-
-       for (i = 0; i < no_ops; i++) {
-               k = 0;
-               opcode = 0;
-               for (k = 0; k < 8; k++) {
-                       if (!(ctr->opcode & (1 << k)))
-                               continue;
-                       switch (1 << k) {
-                       case QLCNIC_DUMP_WCRB:
-                               QLCNIC_WR_DUMP_REG(addr, base, ctr->val1);
-                               break;
-                       case QLCNIC_DUMP_RWCRB:
-                               QLCNIC_RD_DUMP_REG(addr, base, &data);
-                               QLCNIC_WR_DUMP_REG(addr, base, data);
-                               break;
-                       case QLCNIC_DUMP_ANDCRB:
-                               QLCNIC_RD_DUMP_REG(addr, base, &data);
-                               QLCNIC_WR_DUMP_REG(addr, base,
-                                       (data & ctr->val2));
-                               break;
-                       case QLCNIC_DUMP_ORCRB:
-                               QLCNIC_RD_DUMP_REG(addr, base, &data);
-                               QLCNIC_WR_DUMP_REG(addr, base,
-                                       (data | ctr->val3));
-                               break;
-                       case QLCNIC_DUMP_POLLCRB:
-                               while (timeout <= ctr->timeout) {
-                                       QLCNIC_RD_DUMP_REG(addr, base, &data);
-                                       if ((data & ctr->val2) == ctr->val1)
-                                               break;
-                                       msleep(1);
-                                       timeout++;
-                               }
-                               if (timeout > ctr->timeout) {
-                                       dev_info(&adapter->pdev->dev,
-                                       "Timed out, aborting poll CRB\n");
-                                       return -EINVAL;
-                               }
-                               break;
-                       case QLCNIC_DUMP_RD_SAVE:
-                               if (ctr->index_a)
-                                       addr = t_hdr->saved_state[ctr->index_a];
-                               QLCNIC_RD_DUMP_REG(addr, base, &data);
-                               t_hdr->saved_state[ctr->index_v] = data;
-                               break;
-                       case QLCNIC_DUMP_WRT_SAVED:
-                               if (ctr->index_v)
-                                       data = t_hdr->saved_state[ctr->index_v];
-                               else
-                                       data = ctr->val1;
-                               if (ctr->index_a)
-                                       addr = t_hdr->saved_state[ctr->index_a];
-                               QLCNIC_WR_DUMP_REG(addr, base, data);
-                               break;
-                       case QLCNIC_DUMP_MOD_SAVE_ST:
-                               data = t_hdr->saved_state[ctr->index_v];
-                               data <<= ctr->shl_val;
-                               data >>= ctr->shr_val;
-                               if (ctr->val2)
-                                       data &= ctr->val2;
-                               data |= ctr->val3;
-                               data += ctr->val1;
-                               t_hdr->saved_state[ctr->index_v] = data;
-                               break;
-                       default:
-                               dev_info(&adapter->pdev->dev,
-                                       "Unknown opcode\n");
-                               break;
-                       }
-               }
-               addr += ctr->stride;
-       }
-       return 0;
+       ahw->ocm_win_crb = qlcnic_get_ioaddr(ahw, QLCNIC_PCIX_PS_REG(
+                               PCIX_OCM_WINDOW_REG(ahw->pci_func)));
 }
 
-static u32
-qlcnic_dump_mux(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
-       u32 *buffer)
+void qlcnic_read_crb(struct qlcnic_adapter *adapter, char *buf,
+       loff_t offset, size_t size)
 {
-       int loop;
-       u32 val, data = 0;
-       struct __mux *mux = &entry->region.mux;
-       void __iomem *base = adapter->ahw->pci_base0;
-
-       val = mux->val;
-       for (loop = 0; loop < mux->no_ops; loop++) {
-               QLCNIC_WR_DUMP_REG(mux->addr, base, val);
-               QLCNIC_RD_DUMP_REG(mux->read_addr, base, &data);
-               *buffer++ = cpu_to_le32(val);
-               *buffer++ = cpu_to_le32(data);
-               val += mux->val_stride;
-       }
-       return 2 * mux->no_ops * sizeof(u32);
-}
+       int err;
+       u32 data;
+       u64 qmdata;
 
-static u32
-qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
-       u32 *buffer)
-{
-       int i, loop;
-       u32 cnt, addr, data, que_id = 0;
-       void __iomem *base = adapter->ahw->pci_base0;
-       struct __queue *que = &entry->region.que;
-
-       addr = que->read_addr;
-       cnt = que->read_addr_cnt;
-
-       for (loop = 0; loop < que->no_ops; loop++) {
-               QLCNIC_WR_DUMP_REG(que->sel_addr, base, que_id);
-               addr = que->read_addr;
-               for (i = 0; i < cnt; i++) {
-                       QLCNIC_RD_DUMP_REG(addr, base, &data);
-                       *buffer++ = cpu_to_le32(data);
-                       addr += que->read_addr_stride;
-               }
-               que_id += que->stride;
+       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, &err);
+               memcpy(buf, &data, size);
        }
-       return que->no_ops * cnt * sizeof(u32);
 }
 
-static u32
-qlcnic_dump_ocm(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
-       u32 *buffer)
+void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf,
+       loff_t offset, size_t size)
 {
-       int i;
        u32 data;
-       void __iomem *addr;
-       struct __ocm *ocm = &entry->region.ocm;
+       u64 qmdata;
 
-       addr = adapter->ahw->pci_base0 + ocm->read_addr;
-       for (i = 0; i < ocm->no_ops; i++) {
-               data = readl(addr);
-               *buffer++ = cpu_to_le32(data);
-               addr += ocm->read_addr_stride;
+       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 ocm->no_ops * sizeof(u32);
 }
 
-static u32
-qlcnic_read_rom(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
-       u32 *buffer)
+int qlcnic_api_lock(struct qlcnic_adapter *adapter)
 {
-       int i, count = 0;
-       u32 fl_addr, size, val, lck_val, addr;
-       struct __mem *rom = &entry->region.mem;
-       void __iomem *base = adapter->ahw->pci_base0;
-
-       fl_addr = rom->addr;
-       size = rom->size/4;
-lock_try:
-       lck_val = readl(base + QLCNIC_FLASH_SEM2_LK);
-       if (!lck_val && count < MAX_CTL_CHECK) {
-               msleep(10);
-               count++;
-               goto lock_try;
-       }
-       writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID));
-       for (i = 0; i < size; i++) {
-               addr = fl_addr & 0xFFFF0000;
-               QLCNIC_WR_DUMP_REG(FLASH_ROM_WINDOW, base, addr);
-               addr = LSW(fl_addr) + FLASH_ROM_DATA;
-               QLCNIC_RD_DUMP_REG(addr, base, &val);
-               fl_addr += 4;
-               *buffer++ = cpu_to_le32(val);
-       }
-       readl(base + QLCNIC_FLASH_SEM2_ULK);
-       return rom->size;
+       return qlcnic_pcie_sem_lock(adapter, 5, 0);
 }
 
-static u32
-qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
-       struct qlcnic_dump_entry *entry, u32 *buffer)
+void qlcnic_api_unlock(struct qlcnic_adapter *adapter)
 {
-       int i;
-       u32 cnt, val, data, addr;
-       void __iomem *base = adapter->ahw->pci_base0;
-       struct __cache *l1 = &entry->region.cache;
-
-       val = l1->init_tag_val;
-
-       for (i = 0; i < l1->no_ops; i++) {
-               QLCNIC_WR_DUMP_REG(l1->addr, base, val);
-               QLCNIC_WR_DUMP_REG(l1->ctrl_addr, base, LSW(l1->ctrl_val));
-               addr = l1->read_addr;
-               cnt = l1->read_addr_num;
-               while (cnt) {
-                       QLCNIC_RD_DUMP_REG(addr, base, &data);
-                       *buffer++ = cpu_to_le32(data);
-                       addr += l1->read_addr_stride;
-                       cnt--;
-               }
-               val += l1->stride;
-       }
-       return l1->no_ops * l1->read_addr_num * sizeof(u32);
+       qlcnic_pcie_sem_unlock(adapter, 5);
 }
 
-static u32
-qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
-       struct qlcnic_dump_entry *entry, u32 *buffer)
+void qlcnic_add_sysfs(struct qlcnic_adapter *adapter)
 {
-       int i;
-       u32 cnt, val, data, addr;
-       u8 poll_mask, poll_to, time_out = 0;
-       void __iomem *base = adapter->ahw->pci_base0;
-       struct __cache *l2 = &entry->region.cache;
-
-       val = l2->init_tag_val;
-       poll_mask = LSB(MSW(l2->ctrl_val));
-       poll_to = MSB(MSW(l2->ctrl_val));
-
-       for (i = 0; i < l2->no_ops; i++) {
-               QLCNIC_WR_DUMP_REG(l2->addr, base, val);
-               if (LSW(l2->ctrl_val))
-                       QLCNIC_WR_DUMP_REG(l2->ctrl_addr, base,
-                               LSW(l2->ctrl_val));
-               if (!poll_mask)
-                       goto skip_poll;
-               do {
-                       QLCNIC_RD_DUMP_REG(l2->ctrl_addr, base, &data);
-                       if (!(data & poll_mask))
-                               break;
-                       msleep(1);
-                       time_out++;
-               } while (time_out <= poll_to);
-
-               if (time_out > poll_to) {
-                       dev_err(&adapter->pdev->dev,
-                               "Timeout exceeded in %s, aborting dump\n",
-                               __func__);
-                       return -EINVAL;
-               }
-skip_poll:
-               addr = l2->read_addr;
-               cnt = l2->read_addr_num;
-               while (cnt) {
-                       QLCNIC_RD_DUMP_REG(addr, base, &data);
-                       *buffer++ = cpu_to_le32(data);
-                       addr += l2->read_addr_stride;
-                       cnt--;
-               }
-               val += l2->stride;
-       }
-       return l2->no_ops * l2->read_addr_num * sizeof(u32);
+       qlcnic_create_diag_entries(adapter);
 }
 
-static u32
-qlcnic_read_memory(struct qlcnic_adapter *adapter,
-       struct qlcnic_dump_entry *entry, u32 *buffer)
+void qlcnic_remove_sysfs(struct qlcnic_adapter *adapter)
 {
-       u32 addr, data, test, ret = 0;
-       int i, reg_read;
-       struct __mem *mem = &entry->region.mem;
-       void __iomem *base = adapter->ahw->pci_base0;
-
-       reg_read = mem->size;
-       addr = mem->addr;
-       /* check for data size of multiple of 16 and 16 byte alignment */
-       if ((addr & 0xf) || (reg_read%16)) {
-               dev_info(&adapter->pdev->dev,
-                       "Unaligned memory addr:0x%x size:0x%x\n",
-                       addr, reg_read);
-               return -EINVAL;
-       }
-
-       mutex_lock(&adapter->ahw->mem_lock);
-
-       while (reg_read != 0) {
-               QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_LO, base, addr);
-               QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_HI, base, 0);
-               QLCNIC_WR_DUMP_REG(MIU_TEST_CTR, base,
-                       TA_CTL_ENABLE | TA_CTL_START);
-
-               for (i = 0; i < MAX_CTL_CHECK; i++) {
-                       QLCNIC_RD_DUMP_REG(MIU_TEST_CTR, base, &test);
-                       if (!(test & TA_CTL_BUSY))
-                               break;
-               }
-               if (i == MAX_CTL_CHECK) {
-                       if (printk_ratelimit()) {
-                               dev_err(&adapter->pdev->dev,
-                                       "failed to read through agent\n");
-                               ret = -EINVAL;
-                               goto out;
-                       }
-               }
-               for (i = 0; i < 4; i++) {
-                       QLCNIC_RD_DUMP_REG(MIU_TEST_READ_DATA[i], base, &data);
-                       *buffer++ = cpu_to_le32(data);
-               }
-               addr += 16;
-               reg_read -= 16;
-               ret += 16;
-       }
-out:
-       mutex_unlock(&adapter->ahw->mem_lock);
-       return mem->size;
+       qlcnic_remove_diag_entries(adapter);
 }
 
-static u32
-qlcnic_dump_nop(struct qlcnic_adapter *adapter,
-       struct qlcnic_dump_entry *entry, u32 *buffer)
+u32 qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
 {
-       entry->hdr.flags |= QLCNIC_DUMP_SKIP;
-       return 0;
-}
-
-struct qlcnic_dump_operations fw_dump_ops[] = {
-       { QLCNIC_DUMP_NOP, qlcnic_dump_nop },
-       { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
-       { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
-       { QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
-       { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
-       { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
-       { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
-       { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
-       { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
-       { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
-       { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
-       { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
-       { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
-       { QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
-};
+       int err;
+       u32 data;
 
-/* Walk the template and collect dump for each entry in the dump template */
-static int
-qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
-       u32 size)
-{
-       int ret = 1;
-       if (size != entry->hdr.cap_size) {
-               dev_info(dev,
-               "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
-               entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
-               dev_info(dev, "Aborting further dump capture\n");
-               ret = 0;
+       if (QLCNIC_IS_82XX(adapter))
+               QLCNIC_RD_DUMP_REG(addr, adapter->ahw->pci_base0, &data);
+       else {
+               data = qlcnic_83xx_rd_reg_indirect(adapter, addr, &err);
+               if (err == -EIO)
+                       return -EIO;
        }
-       return ret;
+       return data;
 }
 
-int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
+void qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
 {
-       u32 *buffer;
-       char mesg[64];
-       char *msg[] = {mesg, NULL};
-       int i, k, ops_cnt, ops_index, dump_size = 0;
-       u32 entry_offset, dump, no_entries, buf_offset = 0;
-       struct qlcnic_dump_entry *entry;
-       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
-       struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
-
-       if (fw_dump->clr) {
-               dev_info(&adapter->pdev->dev,
-                       "Previous dump not cleared, not capturing dump\n");
-               return -EIO;
-       }
-       /* Calculate the size for dump data area only */
-       for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
-               if (i & tmpl_hdr->drv_cap_mask)
-                       dump_size += tmpl_hdr->cap_sizes[k];
-       if (!dump_size)
-               return -EIO;
-
-       fw_dump->data = vzalloc(dump_size);
-       if (!fw_dump->data) {
-               dev_info(&adapter->pdev->dev,
-                       "Unable to allocate (%d KB) for fw dump\n",
-                       dump_size/1024);
-               return -ENOMEM;
-       }
-       buffer = fw_dump->data;
-       fw_dump->size = dump_size;
-       no_entries = tmpl_hdr->num_entries;
-       ops_cnt = ARRAY_SIZE(fw_dump_ops);
-       entry_offset = tmpl_hdr->offset;
-       tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
-       tmpl_hdr->sys_info[1] = adapter->fw_version;
-
-       for (i = 0; i < no_entries; i++) {
-               entry = (void *)tmpl_hdr + entry_offset;
-               if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
-                       entry->hdr.flags |= QLCNIC_DUMP_SKIP;
-                       entry_offset += entry->hdr.offset;
-                       continue;
-               }
-               /* Find the handler for this entry */
-               ops_index = 0;
-               while (ops_index < ops_cnt) {
-                       if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
-                               break;
-                       ops_index++;
-               }
-               if (ops_index == ops_cnt) {
-                       dev_info(&adapter->pdev->dev,
-                               "Invalid entry type %d, exiting dump\n",
-                               entry->hdr.type);
-                       goto error;
-               }
-               /* Collect dump for this entry */
-               dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
-               if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry,
-                       dump))
-                       entry->hdr.flags |= QLCNIC_DUMP_SKIP;
-               buf_offset += entry->hdr.cap_size;
-               entry_offset += entry->hdr.offset;
-               buffer = fw_dump->data + buf_offset;
-       }
-       if (dump_size != buf_offset) {
-               dev_info(&adapter->pdev->dev,
-                       "Captured(%d) and expected size(%d) do not match\n",
-                       buf_offset, dump_size);
-               goto error;
-       } else {
-               fw_dump->clr = 1;
-               snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
-                       adapter->netdev->name);
-               dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
-                       fw_dump->size);
-               /* Send a udev event to notify availability of FW dump */
-               kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
-               return 0;
-       }
-error:
-       vfree(fw_dump->data);
-       return -EINVAL;
+       if (QLCNIC_IS_82XX(adapter))
+               QLCNIC_WR_DUMP_REG(addr, adapter->ahw->pci_base0, data);
+       else
+               qlcnic_83xx_wrt_reg_indirect(adapter, addr, data);
 }
diff --git a/drivers/net/qlcnic/qlcnic_hw.h b/drivers/net/qlcnic/qlcnic_hw.h
new file mode 100644 (file)
index 0000000..a80cc71
--- /dev/null
@@ -0,0 +1,286 @@
+#ifndef __QLCNIC_HW_H
+#define __QLCNIC_HW_H
+
+#define MASK(n) ((1ULL<<(n))-1)
+#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
+#define OCM_WIN_83XX(addr)     (addr & 0xFFE0000)
+
+#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+#define GET_83XX_OCM_OFFSET(addr)      (addr & MASK(17))
+
+#define CRB_BLK(off)   ((off >> 20) & 0x3f)
+#define CRB_SUBBLK(off)        ((off >> 16) & 0xf)
+#define CRB_WINDOW_2M  (0x130060)
+#define CRB_HI(off)    ((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000))
+#define CRB_INDIRECT_2M        (0x1e0000UL)
+
+
+
+/* List of PCI device IDs */
+#define PCI_DEVICE_ID_QLOGIC_QLE824X   0x8020
+#define PCI_DEVICE_ID_QLOGIC_QLE834X   0x8030
+#define QLCNIC_82XX_BAR0_LENGTH        0x00200000UL
+#define QLCNIC_83XX_BAR0_LENGTH        0x4000
+
+#define QLCNIC_IS_83XX(adapter)        \
+       (((adapter)->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? 1 : 0)
+
+#define QLCNIC_IS_82XX(adapter)        \
+       (((adapter)->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X) ? 1 : 0)
+
+/* Existing registers in Hilda and P3P */
+enum qlcnic_regs {
+       QLCNIC_PEG_HALT_STATUS1 = 0,
+       QLCNIC_PEG_HALT_STATUS2,
+       QLCNIC_PEG_ALIVE_COUNTER,
+       QLCNIC_FLASH_LOCK_OWNER,
+       QLCNIC_FW_CAPABILITIES,
+       QLCNIC_CRB_DRV_ACTIVE,
+       QLCNIC_CRB_DEV_STATE,
+       QLCNIC_CRB_DRV_STATE,
+       QLCNIC_CRB_DRV_SCRATCH,
+       QLCNIC_CRB_DEV_PARTITION_INFO,
+       QLCNIC_CRB_DRV_IDC_VER,
+       QLCNIC_FW_VERSION_MAJOR,
+       QLCNIC_FW_VERSION_MINOR,
+       QLCNIC_FW_VERSION_SUB,
+       QLCNIC_CRB_DEV_NPAR_STATE,
+       QLCNIC_FW_IMG_VALID,
+       QLCNIC_CMDPEG_STATE,
+       QLCNIC_RCVPEG_STATE,
+       QLCNIC_ASIC_TEMP,
+       QLCNIC_FW_API,
+       QLCNIC_DRV_OP_MODE,
+       QLCNIC_FLASH_LOCK,
+       QLCNIC_FLASH_UNLOCK,
+       QLCNIC_FW_CAPABILITIES_2,
+};
+
+/* Additional registers in Hilda */
+enum qlcnic_ext_regs {
+       QLCNIC_GLOBAL_RESET = 0,
+       QLCNIC_WILDCARD,
+       QLCNIC_INFORMANT,
+       QLCNIC_HOST_MBX_CTRL,
+       QLCNIC_FW_MBX_CTRL,
+       QLCNIC_BOOTLOADER_ADDR,
+       QLCNIC_BOOTLOADER_SIZE,
+       QLCNIC_FW_IMAGE_ADDR,
+       QLCNIC_MBX_INTR_ENBL,
+       QLCNIC_DEF_INT_MASK,
+       QLCNIC_DEF_INT_ID,
+       QLC_83XX_IDC_MAJ_VERSION,
+       QLC_83XX_IDC_DEV_STATE,
+       QLC_83XX_IDC_DRV_PRESENCE,
+       QLC_83XX_IDC_DRV_ACK,
+       QLC_83XX_IDC_CTRL,
+       QLC_83XX_IDC_DRV_AUDIT,
+       QLC_83XX_IDC_MIN_VERSION,
+       QLC_83XX_RECOVER_DRV_LOCK,
+       QLC_83XX_IDC_PF_0,
+       QLC_83XX_IDC_PF_1,
+       QLC_83XX_IDC_PF_2,
+       QLC_83XX_IDC_PF_3,
+       QLC_83XX_IDC_PF_4,
+       QLC_83XX_IDC_PF_5,
+       QLC_83XX_IDC_PF_6,
+       QLC_83XX_IDC_PF_7,
+       QLC_83XX_IDC_PF_8,
+       QLC_83XX_IDC_PF_9,
+       QLC_83XX_IDC_PF_10,
+       QLC_83XX_IDC_PF_11,
+       QLC_83XX_IDC_PF_12,
+       QLC_83XX_IDC_PF_13,
+       QLC_83XX_IDC_PF_14,
+       QLC_83XX_IDC_PF_15,
+       QLC_83XX_IDC_DEV_PARTITION_INFO_1,
+       QLC_83XX_IDC_DEV_PARTITION_INFO_2,
+       QLC_83XX_DRV_OP_MODE,
+       QLC_83XX_VNIC_STATE,
+       QLC_83XX_DRV_LOCK,
+       QLC_83XX_DRV_UNLOCK,
+       QLC_83XX_DRV_LOCK_ID,
+       QLC_83XX_ASIC_TEMP,
+};
+
+struct qlcnic_ms_reg_ctrl {
+       u32 ocm_window;
+       u32 control;
+       u32 hi;
+       u32 low;
+       u32 rd[4];
+       u32 wd[4];
+       u64 off;
+};
+
+/* Read from an address offset from BAR0, existing registers */
+#define QLCRD(a, addr)                 \
+       readl(((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+/* Write to an address offset from BAR0, existing registers */
+#define QLCWR(a, addr, value)          \
+       writel(value, ((a)->ahw->pci_base0) + ((a)->ahw->reg_tbl[addr]))
+
+/* Read from a direct address offset from BAR0, additional registers */
+#define QLCRDX(ahw, addr)                      \
+       readl(((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr]))
+/* Write to a direct address offset from BAR0, additional registers */
+#define QLCWRX(ahw, addr, value)               \
+       writel(value, (((ahw)->pci_base0) + ((ahw)->ext_reg_tbl[addr])))
+
+#define QLCNIC_READ_LINK_SPEED(adapter, pcifn, err)\
+       (QLCNIC_IS_83XX(adapter) ?\
+       (((readl(adapter->ahw->pci_base0 + QLC_83XX_LINK_SPEED(pcifn)) >> \
+       ((pcifn % 4) << 4)) & 0xFFFF) * QLC_83XX_LINK_SPEED_FACTOR) :\
+       (P3P_LINK_SPEED_MHZ * P3P_LINK_SPEED_VAL(pcifn, \
+       QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn), err))))
+
+/* Mailbox ownership */
+#define QLCNIC_GET_OWNER(val)  \
+       ((val) & (BIT_0 | BIT_1))
+#define QLCNIC_SET_OWNER       1
+#define QLCNIC_CLR_OWNER       0
+#define QLCNIC_MBX_TIMEOUT     5
+#define QLCNIC_MBX_POLL_CNT    5000
+#define QLCNIC_MBX_POLL_DELAY_MSEC 1
+
+#define QLCNIC_CMD_CONFIGURE_IP_ADDR           0x1
+#define QLCNIC_CMD_CONFIG_INTRPT               0x2
+#define QLCNIC_CMD_CREATE_RX_CTX               0x7
+#define QLCNIC_CMD_DESTROY_RX_CTX              0x8
+#define QLCNIC_CMD_CREATE_TX_CTX               0x9
+#define QLCNIC_CMD_DESTROY_TX_CTX              0xa
+#define QLCNIC_CMD_CONFIGURE_LRO               0xC
+#define QLCNIC_CMD_CONFIGURE_MAC_LEARNING      0xD
+#define QLCNIC_CMD_GET_STATISTICS              0xF
+#define QLCNIC_CMD_INTRPT_TEST                 0x11
+#define QLCNIC_CMD_SET_MTU                     0x12
+#define QLCNIC_CMD_READ_PHY                    0x13
+#define QLCNIC_CMD_WRITE_PHY                   0x14
+#define QLCNIC_CMD_READ_HW_REG                 0x15
+#define QLCNIC_CMD_GET_FLOW_CTL                        0x16
+#define QLCNIC_CMD_SET_FLOW_CTL                        0x17
+#define QLCNIC_CMD_READ_MAX_MTU                        0x18
+#define QLCNIC_CMD_READ_MAX_LRO                        0x19
+#define QLCNIC_CMD_MAC_ADDRESS                 0x1f
+#define QLCNIC_CMD_GET_PCI_INFO                        0x20
+#define QLCNIC_CMD_GET_NIC_INFO                        0x21
+#define QLCNIC_CMD_SET_NIC_INFO                        0x22
+#define QLCNIC_CMD_GET_ESWITCH_CAPABILITY      0x24
+#define QLCNIC_CMD_TOGGLE_ESWITCH              0x25
+#define QLCNIC_CMD_GET_ESWITCH_STATUS          0x26
+#define QLCNIC_CMD_SET_PORTMIRRORING           0x27
+#define QLCNIC_CMD_CONFIGURE_ESWITCH           0x28
+#define QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG     0x29
+#define QLCNIC_CMD_GET_ESWITCH_STATS           0x2a
+#define QLCNIC_CMD_CONFIG_PORT                 0x2e
+#define QLCNIC_CMD_TEMP_SIZE                   0x2f
+#define QLCNIC_CMD_GET_TEMP_HDR                        0x30
+#define QLCNIC_CMD_GET_MAC_STATS               0x37
+#define QLCNIC_CMD_SET_DRV_VER                 0x38
+#define QLCNIC_CMD_CONFIGURE_RSS               0x41
+#define QLCNIC_CMD_CONFIG_INTR_COAL            0x43
+#define QLCNIC_CMD_CONFIGURE_LED               0x44
+#define QLCNIC_CMD_CONFIG_MAC_VLAN             0x45
+#define QLCNIC_CMD_GET_LINK_EVENT              0x48
+#define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE       0x49
+#define QLCNIC_CMD_CONFIGURE_HW_LRO            0x4A
+#define QLCNIC_CMD_INIT_NIC_FUNC               0x60
+#define QLCNIC_CMD_STOP_NIC_FUNC               0x61
+#define QLCNIC_CMD_IDC_ACK                     0x63
+#define QLCNIC_CMD_SET_PORT_CONFIG             0x66
+#define QLCNIC_CMD_GET_PORT_CONFIG             0x67
+#define QLCNIC_CMD_GET_LINK_STATUS             0x68
+#define QLCNIC_CMD_SET_LED_CONFIG              0x69
+#define QLCNIC_CMD_GET_LED_CONFIG              0x6A
+#define QLCNIC_CMD_ADD_RCV_RINGS               0x0B
+
+#define QLC_TCP_HDR_SIZE            20
+#define QLC_TCP_TS_OPTION_SIZE      12
+#define QLC_TCP_TS_HDR_SIZE         (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE)
+
+#define QLCNIC_INTRPT_INTX     1
+#define QLCNIC_INTRPT_MSIX     3
+#define QLCNIC_INTRPT_ADD      1
+#define QLCNIC_INTRPT_DEL      2
+
+#define QLCNIC_GET_CURRENT_MAC 1
+#define QLCNIC_SET_STATION_MAC 2
+#define QLCNIC_GET_DEFAULT_MAC 3
+#define QLCNIC_GET_FAC_DEF_MAC 4
+#define QLCNIC_SET_FAC_DEF_MAC 5
+
+#define QLCNIC_MBX_LINK_EVENT          0x8001
+#define QLCNIC_MBX_COMP_EVENT          0x8100
+#define QLCNIC_MBX_REQUEST_EVENT       0x8101
+#define QLCNIC_MBX_TIME_EXTEND_EVENT   0x8102
+#define QLCNIC_MBX_SFP_INSERT_EVENT    0x8130
+#define QLCNIC_MBX_SFP_REMOVE_EVENT    0x8131
+
+struct qlcnic_mailbox_metadata {
+       u32 cmd;
+       u32 in_args;
+       u32 out_args;
+};
+
+#define QLCNIC_BAR_LENGTH(dev_id, bar)                 \
+do {                                                   \
+       switch (dev_id) {                               \
+       case PCI_DEVICE_ID_QLOGIC_QLE824X:              \
+               *bar = QLCNIC_82XX_BAR0_LENGTH;         \
+               break;                                  \
+       case PCI_DEVICE_ID_QLOGIC_QLE834X:              \
+               *bar = QLCNIC_83XX_BAR0_LENGTH; \
+               break;                                  \
+       default:                                        \
+               *bar = 0;                               \
+       }                                               \
+} while (0)
+
+/* Make a handle with reference handle (0:14) and RDS ring
+ * number (15).
+ */
+#define QLCNIC_MAKE_REF_HANDLE(adapter, handle, ring_id)               \
+       ((adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X) ?      \
+       ((handle) | ((ring_id) << 15)) : handle)
+
+#define QLCNIC_FETCH_RING_ID(handle)                   \
+       ((handle) >> 63)
+
+#define QLCNIC_ENABLE_INTR(adapter, crb) {             \
+       writel(1, crb);                                 \
+       if (!QLCNIC_IS_MSI_FAMILY(adapter))             \
+               writel(0xfbff, adapter->tgt_mask_reg);  \
+}
+
+#define QLCNIC_DISABLE_INTR(crb) {                     \
+       writel(0, crb);                                 \
+}
+
+#define QLCNIC_MBX_RSP_OK      1
+#define QLCNIC_MBX_PORT_RSP_OK 0x1a
+#define QLCNIC_MBX_ASYNC_EVENT BIT_15
+
+#define QLCNIC_MBX_RSP(reg)\
+       LSW(reg)
+#define QLCNIC_MBX_NUM_REGS(reg)\
+       (MSW(reg) & 0x1FF)
+#define QLCNIC_MBX_STATUS(reg) \
+       (((reg) >> 25) & 0x7F)
+
+/* Mailbox registers*/
+#define QLCNIC_MBX_HOST(ahw, i)        \
+       ((ahw)->pci_base0 + ((i) * 4))
+#define QLCNIC_MBX_FW(ahw, i)  \
+       ((ahw)->pci_base0 + 0x800 + ((i) * 4))
+
+#define QLCNIC_IS_TSO_CAPABLE(adapter)\
+       ((QLCNIC_IS_82XX(adapter)) ?\
+       ((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO) :\
+       ((adapter)->ahw->capabilities & QLCNIC_FW_83XX_CAPABILITY_TSO))
+
+#define QLCNIC_IS_VLAN_TX_CAPABLE(adapter) \
+       ((QLCNIC_IS_82XX(adapter)) ?\
+       ((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX) :\
+       1)
+
+#endif                         /* __QLCNIC_HDR_H_ */
index 0bcda9c51e9bcbc42abde3c0130f00371613389e..427d78c376397d1091c8d0f743721cf8b12fcb58 100644 (file)
@@ -5,11 +5,8 @@
  * See LICENSE.qlcnic for copyright and licensing details.
  */
 
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/if_vlan.h>
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
 
 struct crb_addr_pair {
        u32 addr;
@@ -25,10 +22,6 @@ static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM];
 
 #define QLCNIC_ADDR_ERROR (0xffffffff)
 
-static void
-qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_rds_ring *rds_ring);
-
 static int
 qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter);
 
@@ -170,13 +163,12 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_recv_context *recv_ctx;
        struct qlcnic_host_rds_ring *rds_ring;
-       struct qlcnic_host_tx_ring *tx_ring;
        int ring;
 
        recv_ctx = adapter->recv_ctx;
 
        if (recv_ctx->rds_rings == NULL)
-               goto skip_rds;
+               return;
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &recv_ctx->rds_rings[ring];
@@ -184,16 +176,6 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
                rds_ring->rx_buf_arr = NULL;
        }
        kfree(recv_ctx->rds_rings);
-
-skip_rds:
-       if (adapter->tx_ring == NULL)
-               return;
-
-       tx_ring = adapter->tx_ring;
-       vfree(tx_ring->cmd_buf_arr);
-       tx_ring->cmd_buf_arr = NULL;
-       kfree(adapter->tx_ring);
-       adapter->tx_ring = NULL;
 }
 
 int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
@@ -201,30 +183,11 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
        struct qlcnic_recv_context *recv_ctx;
        struct qlcnic_host_rds_ring *rds_ring;
        struct qlcnic_host_sds_ring *sds_ring;
-       struct qlcnic_host_tx_ring *tx_ring;
        struct qlcnic_rx_buffer *rx_buf;
        int ring, i, size;
 
-       struct qlcnic_cmd_buffer *cmd_buf_arr;
        struct net_device *netdev = adapter->netdev;
-
-       size = sizeof(struct qlcnic_host_tx_ring);
-       tx_ring = kzalloc(size, GFP_KERNEL);
-       if (tx_ring == NULL) {
-               dev_err(&netdev->dev, "failed to allocate tx ring struct\n");
-               return -ENOMEM;
-       }
-       adapter->tx_ring = tx_ring;
-
-       tx_ring->num_desc = adapter->num_txd;
-       tx_ring->txq = netdev_get_tx_queue(netdev, 0);
-
-       cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
-       if (cmd_buf_arr == NULL) {
-               dev_err(&netdev->dev, "failed to allocate cmd buffer ring\n");
-               goto err_out;
-       }
-       tx_ring->cmd_buf_arr = cmd_buf_arr;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        recv_ctx = adapter->recv_ctx;
 
@@ -250,7 +213,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
                        rds_ring->dma_size =
                                QLCNIC_P3P_RX_JUMBO_BUF_MAX_LEN;
 
-                       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+                       if (ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
                                rds_ring->dma_size += QLCNIC_LRO_BUFFER_EXTRA;
 
                        rds_ring->skb_size =
@@ -328,11 +291,12 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
 {
        long timeout = 0;
        long done = 0;
+       int err;
 
        cond_resched();
 
        while (done == 0) {
-               done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
+               done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS, &err);
                done &= 2;
                if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) {
                        dev_err(&adapter->pdev->dev,
@@ -347,6 +311,8 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
 static int do_rom_fast_read(struct qlcnic_adapter *adapter,
                            u32 addr, u32 *valp)
 {
+       int err;
+
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3);
@@ -360,7 +326,7 @@ static int do_rom_fast_read(struct qlcnic_adapter *adapter,
        udelay(10);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
 
-       *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA);
+       *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA, &err);
        return 0;
 }
 
@@ -412,15 +378,15 @@ int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp)
 
 int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
 {
-       int addr, val;
+       int addr, val, err;
        int i, n, init_delay;
        struct crb_addr_pair *buf;
        unsigned offset;
        u32 off;
        struct pci_dev *pdev = adapter->pdev;
 
-       QLCWR32(adapter, CRB_CMDPEG_STATE, 0);
-       QLCWR32(adapter, CRB_RCVPEG_STATE, 0);
+       QLCWR(adapter, QLCNIC_CMDPEG_STATE, 0);
+       QLCWR(adapter, QLCNIC_RCVPEG_STATE, 0);
 
        /* Halt all the indiviual PEGs and other blocks */
        /* disable all I2Q */
@@ -445,7 +411,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00);
 
        /* halt sre */
-       val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000);
+       val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000, &err);
        QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1)));
 
        /* halt epg */
@@ -567,8 +533,8 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
        msleep(1);
 
-       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
-       QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
+       QLCWR(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
+       QLCWR(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
 
        return 0;
 }
@@ -579,7 +545,7 @@ static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
        int retries = QLCNIC_CMDPEG_CHECK_RETRY_COUNT;
 
        do {
-               val = QLCRD32(adapter, CRB_CMDPEG_STATE);
+               val = QLCRD(adapter, QLCNIC_CMDPEG_STATE);
 
                switch (val) {
                case PHAN_INITIALIZE_COMPLETE:
@@ -595,7 +561,7 @@ static int qlcnic_cmd_peg_ready(struct qlcnic_adapter *adapter)
 
        } while (--retries);
 
-       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+       QLCWR(adapter, QLCNIC_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
 
 out_err:
        dev_err(&adapter->pdev->dev, "Command Peg initialization not "
@@ -610,7 +576,7 @@ qlcnic_receive_peg_ready(struct qlcnic_adapter *adapter)
        int retries = QLCNIC_RCVPEG_CHECK_RETRY_COUNT;
 
        do {
-               val = QLCRD32(adapter, CRB_RCVPEG_STATE);
+               val = QLCRD(adapter, QLCNIC_RCVPEG_STATE);
 
                if (val == PHAN_PEG_RCV_INITIALIZED)
                        return 0;
@@ -641,7 +607,7 @@ qlcnic_check_fw_status(struct qlcnic_adapter *adapter)
        if (err)
                return err;
 
-       QLCWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
+       QLCWR(adapter, QLCNIC_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
 
        return err;
 }
@@ -652,14 +618,14 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
        int timeo;
        u32 val;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+       val = QLCRD(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
        val = QLC_DEV_GET_DRV(val, adapter->portnum);
        if ((val & 0x3) != QLCNIC_TYPE_NIC) {
                dev_err(&adapter->pdev->dev,
                        "Not an Ethernet NIC func=%u\n", val);
                return -EIO;
        }
-       adapter->physical_port = (val >> 2);
+       adapter->ahw->physical_port = (val >> 2);
        if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
                timeo = QLCNIC_INIT_TIMEOUT_SECS;
 
@@ -734,10 +700,10 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
 
        if (adapter->ahw->revision_id == QLCNIC_P3P_C0)
                ret = qlcnic_get_flt_entry(adapter, QLCNIC_C0_FW_IMAGE_REGION,
-                                                &fw_entry);
+                                               &fw_entry);
        else
                ret = qlcnic_get_flt_entry(adapter, QLCNIC_B0_FW_IMAGE_REGION,
-                                                &fw_entry);
+                                               &fw_entry);
 
        if (!ret)
                /* 0-4:-signature,  4-8:-fw version */
@@ -765,10 +731,11 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
 static int
 qlcnic_has_mn(struct qlcnic_adapter *adapter)
 {
+       int err;
        u32 capability;
        capability = 0;
 
-       capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
+       capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY, &err);
        if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
                return 1;
 
@@ -997,7 +964,7 @@ qlcnic_get_bootld_offs(struct qlcnic_adapter *adapter)
 {
        u32 offs = QLCNIC_BOOTLD_START;
 
-       if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+       if (adapter->ahw->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
                offs = cpu_to_le32((qlcnic_get_data_desc(adapter,
                                        QLCNIC_UNI_DIR_SECT_BOOTLD,
                                        QLCNIC_UNI_BOOTLD_IDX_OFF))->findex);
@@ -1010,7 +977,7 @@ qlcnic_get_fw_offs(struct qlcnic_adapter *adapter)
 {
        u32 offs = QLCNIC_IMAGE_START;
 
-       if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+       if (adapter->ahw->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
                offs = cpu_to_le32((qlcnic_get_data_desc(adapter,
                                        QLCNIC_UNI_DIR_SECT_FW,
                                        QLCNIC_UNI_FIRMWARE_IDX_OFF))->findex);
@@ -1021,7 +988,7 @@ qlcnic_get_fw_offs(struct qlcnic_adapter *adapter)
 static __le32
 qlcnic_get_fw_size(struct qlcnic_adapter *adapter)
 {
-       if (adapter->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
+       if (adapter->ahw->fw_type == QLCNIC_UNIFIED_ROMIMAGE)
                return cpu_to_le32((qlcnic_get_data_desc(adapter,
                                        QLCNIC_UNI_DIR_SECT_FW,
                                        QLCNIC_UNI_FIRMWARE_IDX_OFF))->size);
@@ -1039,7 +1006,7 @@ qlcnic_get_fw_version(struct qlcnic_adapter *adapter)
        const u8 *ver_str;
        int i, ret;
 
-       if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
+       if (adapter->ahw->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
                return cpu_to_le32(*(u32 *)&fw->data[QLCNIC_FW_VERSION_OFFSET]);
 
        fw_data_desc = qlcnic_get_data_desc(adapter, QLCNIC_UNI_DIR_SECT_FW,
@@ -1067,7 +1034,7 @@ qlcnic_get_bios_version(struct qlcnic_adapter *adapter)
        const struct firmware *fw = adapter->fw;
        __le32 bios_ver, prd_off = adapter->file_prd_off;
 
-       if (adapter->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
+       if (adapter->ahw->fw_type != QLCNIC_UNIFIED_ROMIMAGE)
                return cpu_to_le32(
                        *(u32 *)&fw->data[QLCNIC_BIOS_VERSION_OFFSET]);
 
@@ -1091,11 +1058,11 @@ qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter)
        u32 heartbeat, ret = -EIO;
        int retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
 
-       adapter->heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+       adapter->heartbeat = QLCRD(adapter, QLCNIC_PEG_ALIVE_COUNTER);
 
        do {
                msleep(QLCNIC_HEARTBEAT_PERIOD_MSECS);
-               heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+               heartbeat = QLCRD(adapter, QLCNIC_PEG_ALIVE_COUNTER);
                if (heartbeat != adapter->heartbeat) {
                        ret = QLCNIC_RCODE_SUCCESS;
                        break;
@@ -1137,7 +1104,7 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter)
        struct pci_dev *pdev = adapter->pdev;
 
        dev_info(&pdev->dev, "loading firmware from %s\n",
-                       fw_name[adapter->fw_type]);
+                       fw_name[adapter->ahw->fw_type]);
 
        if (fw) {
                __le64 data;
@@ -1229,7 +1196,7 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
        u32 ver, bios, min_size;
        struct pci_dev *pdev = adapter->pdev;
        const struct firmware *fw = adapter->fw;
-       u8 fw_type = adapter->fw_type;
+       u8 fw_type = adapter->ahw->fw_type;
 
        if (fw_type == QLCNIC_UNIFIED_ROMIMAGE) {
                if (qlcnic_validate_unified_romimage(adapter))
@@ -1265,7 +1232,7 @@ qlcnic_validate_firmware(struct qlcnic_adapter *adapter)
                return -EINVAL;
        }
 
-       QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
+       QLCWR(adapter, QLCNIC_FW_IMG_VALID, QLCNIC_BDINFO_MAGIC);
        return 0;
 }
 
@@ -1274,7 +1241,7 @@ qlcnic_get_next_fwtype(struct qlcnic_adapter *adapter)
 {
        u8 fw_type;
 
-       switch (adapter->fw_type) {
+       switch (adapter->ahw->fw_type) {
        case QLCNIC_UNKNOWN_ROMIMAGE:
                fw_type = QLCNIC_UNIFIED_ROMIMAGE;
                break;
@@ -1285,7 +1252,7 @@ qlcnic_get_next_fwtype(struct qlcnic_adapter *adapter)
                break;
        }
 
-       adapter->fw_type = fw_type;
+       adapter->ahw->fw_type = fw_type;
 }
 
 
@@ -1295,16 +1262,16 @@ void qlcnic_request_firmware(struct qlcnic_adapter *adapter)
        struct pci_dev *pdev = adapter->pdev;
        int rc;
 
-       adapter->fw_type = QLCNIC_UNKNOWN_ROMIMAGE;
+       adapter->ahw->fw_type = QLCNIC_UNKNOWN_ROMIMAGE;
 
 next:
        qlcnic_get_next_fwtype(adapter);
 
-       if (adapter->fw_type == QLCNIC_FLASH_ROMIMAGE) {
+       if (adapter->ahw->fw_type == QLCNIC_FLASH_ROMIMAGE) {
                adapter->fw = NULL;
        } else {
                rc = request_firmware(&adapter->fw,
-                               fw_name[adapter->fw_type], &pdev->dev);
+                               fw_name[adapter->ahw->fw_type], &pdev->dev);
                if (rc != 0)
                        goto next;
 
@@ -1321,636 +1288,7 @@ next:
 void
 qlcnic_release_firmware(struct qlcnic_adapter *adapter)
 {
-       release_firmware(adapter->fw);
+       if (adapter->fw)
+               release_firmware(adapter->fw);
        adapter->fw = NULL;
 }
-
-static void
-qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
-                               struct qlcnic_fw_msg *msg)
-{
-       u32 cable_OUI;
-       u16 cable_len;
-       u16 link_speed;
-       u8  link_status, module, duplex, autoneg;
-       u8 lb_status = 0;
-       struct net_device *netdev = adapter->netdev;
-
-       adapter->has_link_events = 1;
-
-       cable_OUI = msg->body[1] & 0xffffffff;
-       cable_len = (msg->body[1] >> 32) & 0xffff;
-       link_speed = (msg->body[1] >> 48) & 0xffff;
-
-       link_status = msg->body[2] & 0xff;
-       duplex = (msg->body[2] >> 16) & 0xff;
-       autoneg = (msg->body[2] >> 24) & 0xff;
-       lb_status = (msg->body[2] >> 32) & 0x3;
-
-       module = (msg->body[2] >> 8) & 0xff;
-       if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
-               dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
-                               "length %d\n", cable_OUI, cable_len);
-       else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
-               dev_info(&netdev->dev, "unsupported cable length %d\n",
-                               cable_len);
-
-       if (!link_status && (lb_status == QLCNIC_ILB_MODE ||
-           lb_status == QLCNIC_ELB_MODE))
-               adapter->ahw->loopback_state |= QLCNIC_LINKEVENT;
-
-       qlcnic_advert_link_change(adapter, link_status);
-
-       if (duplex == LINKEVENT_FULL_DUPLEX)
-               adapter->link_duplex = DUPLEX_FULL;
-       else
-               adapter->link_duplex = DUPLEX_HALF;
-
-       adapter->module_type = module;
-       adapter->link_autoneg = autoneg;
-
-       if (link_status) {
-               adapter->link_speed = link_speed;
-       } else {
-               adapter->link_speed = SPEED_UNKNOWN;
-               adapter->link_duplex = DUPLEX_UNKNOWN;
-       }
-}
-
-static void
-qlcnic_handle_fw_message(int desc_cnt, int index,
-               struct qlcnic_host_sds_ring *sds_ring)
-{
-       struct qlcnic_fw_msg msg;
-       struct status_desc *desc;
-       struct qlcnic_adapter *adapter;
-       struct device *dev;
-       int i = 0, opcode, ret;
-
-       while (desc_cnt > 0 && i < 8) {
-               desc = &sds_ring->desc_head[index];
-               msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
-               msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);
-
-               index = get_next_index(index, sds_ring->num_desc);
-               desc_cnt--;
-       }
-
-       adapter = sds_ring->adapter;
-       dev = &adapter->pdev->dev;
-       opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);
-
-       switch (opcode) {
-       case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
-               qlcnic_handle_linkevent(adapter, &msg);
-               break;
-       case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK:
-               ret = (u32)(msg.body[1]);
-               switch (ret) {
-               case 0:
-                       adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE;
-                       break;
-               case 1:
-                       dev_info(dev, "loopback already in progress\n");
-                       adapter->diag_cnt = -QLCNIC_TEST_IN_PROGRESS;
-                       break;
-               case 2:
-                       dev_info(dev, "loopback cable is not connected\n");
-                       adapter->diag_cnt = -QLCNIC_LB_CABLE_NOT_CONN;
-                       break;
-               default:
-                       dev_info(dev, "loopback configure request failed,"
-                                       " ret %x\n", ret);
-                       adapter->diag_cnt = -QLCNIC_UNDEFINED_ERROR;
-                       break;
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static int
-qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_rds_ring *rds_ring,
-               struct qlcnic_rx_buffer *buffer)
-{
-       struct sk_buff *skb;
-       dma_addr_t dma;
-       struct pci_dev *pdev = adapter->pdev;
-
-       skb = netdev_alloc_skb(adapter->netdev, rds_ring->skb_size);
-       if (!skb) {
-               adapter->stats.skb_alloc_failure++;
-               return -ENOMEM;
-       }
-
-       skb_reserve(skb, NET_IP_ALIGN);
-
-       dma = pci_map_single(pdev, skb->data,
-                       rds_ring->dma_size, PCI_DMA_FROMDEVICE);
-
-       if (pci_dma_mapping_error(pdev, dma)) {
-               adapter->stats.rx_dma_map_error++;
-               dev_kfree_skb_any(skb);
-               return -ENOMEM;
-       }
-
-       buffer->skb = skb;
-       buffer->dma = dma;
-
-       return 0;
-}
-
-static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
-{
-       struct qlcnic_rx_buffer *buffer;
-       struct sk_buff *skb;
-
-       buffer = &rds_ring->rx_buf_arr[index];
-
-       if (unlikely(buffer->skb == NULL)) {
-               WARN_ON(1);
-               return NULL;
-       }
-
-       pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
-                       PCI_DMA_FROMDEVICE);
-
-       skb = buffer->skb;
-
-       if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
-           (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
-               adapter->stats.csummed++;
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-       } else {
-               skb_checksum_none_assert(skb);
-       }
-
-       buffer->skb = NULL;
-
-       return skb;
-}
-
-static inline int
-qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
-                       u16 *vlan_tag)
-{
-       struct ethhdr *eth_hdr;
-
-       if (!__vlan_get_tag(skb, vlan_tag)) {
-               eth_hdr = (struct ethhdr *) skb->data;
-               memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
-               skb_pull(skb, VLAN_HLEN);
-       }
-       if (!adapter->pvid)
-               return 0;
-
-       if (*vlan_tag == adapter->pvid) {
-               /* Outer vlan tag. Packet should follow non-vlan path */
-               *vlan_tag = 0xffff;
-               return 0;
-       }
-       if (adapter->flags & QLCNIC_TAGGING_ENABLED)
-               return 0;
-
-       return -EINVAL;
-}
-
-static struct qlcnic_rx_buffer *
-qlcnic_process_rcv(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_sds_ring *sds_ring,
-               int ring, u64 sts_data0)
-{
-       struct net_device *netdev = adapter->netdev;
-       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-       struct qlcnic_rx_buffer *buffer;
-       struct sk_buff *skb;
-       struct qlcnic_host_rds_ring *rds_ring;
-       int index, length, cksum, pkt_offset;
-       u16 vid = 0xffff;
-
-       if (unlikely(ring >= adapter->max_rds_rings))
-               return NULL;
-
-       rds_ring = &recv_ctx->rds_rings[ring];
-
-       index = qlcnic_get_sts_refhandle(sts_data0);
-       if (unlikely(index >= rds_ring->num_desc))
-               return NULL;
-
-       buffer = &rds_ring->rx_buf_arr[index];
-
-       length = qlcnic_get_sts_totallength(sts_data0);
-       cksum  = qlcnic_get_sts_status(sts_data0);
-       pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
-
-       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
-       if (!skb)
-               return buffer;
-
-       if (length > rds_ring->skb_size)
-               skb_put(skb, rds_ring->skb_size);
-       else
-               skb_put(skb, length);
-
-       if (pkt_offset)
-               skb_pull(skb, pkt_offset);
-
-       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
-               adapter->stats.rxdropped++;
-               dev_kfree_skb(skb);
-               return buffer;
-       }
-
-       skb->protocol = eth_type_trans(skb, netdev);
-
-       if (vid != 0xffff)
-               __vlan_hwaccel_put_tag(skb, vid);
-
-       napi_gro_receive(&sds_ring->napi, skb);
-
-       adapter->stats.rx_pkts++;
-       adapter->stats.rxbytes += length;
-
-       return buffer;
-}
-
-#define QLC_TCP_HDR_SIZE            20
-#define QLC_TCP_TS_OPTION_SIZE      12
-#define QLC_TCP_TS_HDR_SIZE         (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE)
-
-static struct qlcnic_rx_buffer *
-qlcnic_process_lro(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_sds_ring *sds_ring,
-               int ring, u64 sts_data0, u64 sts_data1)
-{
-       struct net_device *netdev = adapter->netdev;
-       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-       struct qlcnic_rx_buffer *buffer;
-       struct sk_buff *skb;
-       struct qlcnic_host_rds_ring *rds_ring;
-       struct iphdr *iph;
-       struct tcphdr *th;
-       bool push, timestamp;
-       int l2_hdr_offset, l4_hdr_offset;
-       int index;
-       u16 lro_length, length, data_offset;
-       u32 seq_number;
-       u16 vid = 0xffff;
-
-       if (unlikely(ring > adapter->max_rds_rings))
-               return NULL;
-
-       rds_ring = &recv_ctx->rds_rings[ring];
-
-       index = qlcnic_get_lro_sts_refhandle(sts_data0);
-       if (unlikely(index > rds_ring->num_desc))
-               return NULL;
-
-       buffer = &rds_ring->rx_buf_arr[index];
-
-       timestamp = qlcnic_get_lro_sts_timestamp(sts_data0);
-       lro_length = qlcnic_get_lro_sts_length(sts_data0);
-       l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0);
-       l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0);
-       push = qlcnic_get_lro_sts_push_flag(sts_data0);
-       seq_number = qlcnic_get_lro_sts_seq_number(sts_data1);
-
-       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
-       if (!skb)
-               return buffer;
-
-       if (timestamp)
-               data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
-       else
-               data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
-
-       skb_put(skb, lro_length + data_offset);
-
-       skb_pull(skb, l2_hdr_offset);
-
-       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
-               adapter->stats.rxdropped++;
-               dev_kfree_skb(skb);
-               return buffer;
-       }
-
-       skb->protocol = eth_type_trans(skb, netdev);
-
-       iph = (struct iphdr *)skb->data;
-       th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
-
-       length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
-       iph->tot_len = htons(length);
-       iph->check = 0;
-       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-       th->psh = push;
-       th->seq = htonl(seq_number);
-
-       length = skb->len;
-
-       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
-               skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
-
-       if (vid != 0xffff)
-               __vlan_hwaccel_put_tag(skb, vid);
-       netif_receive_skb(skb);
-
-       adapter->stats.lro_pkts++;
-       adapter->stats.lrobytes += length;
-
-       return buffer;
-}
-
-int
-qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
-{
-       struct qlcnic_adapter *adapter = sds_ring->adapter;
-       struct list_head *cur;
-       struct status_desc *desc;
-       struct qlcnic_rx_buffer *rxbuf;
-       u64 sts_data0, sts_data1;
-
-       int count = 0;
-       int opcode, ring, desc_cnt;
-       u32 consumer = sds_ring->consumer;
-
-       while (count < max) {
-               desc = &sds_ring->desc_head[consumer];
-               sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
-
-               if (!(sts_data0 & STATUS_OWNER_HOST))
-                       break;
-
-               desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
-               opcode = qlcnic_get_sts_opcode(sts_data0);
-
-               switch (opcode) {
-               case QLCNIC_RXPKT_DESC:
-               case QLCNIC_OLD_RXPKT_DESC:
-               case QLCNIC_SYN_OFFLOAD:
-                       ring = qlcnic_get_sts_type(sts_data0);
-                       rxbuf = qlcnic_process_rcv(adapter, sds_ring,
-                                       ring, sts_data0);
-                       break;
-               case QLCNIC_LRO_DESC:
-                       ring = qlcnic_get_lro_sts_type(sts_data0);
-                       sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
-                       rxbuf = qlcnic_process_lro(adapter, sds_ring,
-                                       ring, sts_data0, sts_data1);
-                       break;
-               case QLCNIC_RESPONSE_DESC:
-                       qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
-               default:
-                       goto skip;
-               }
-
-               WARN_ON(desc_cnt > 1);
-
-               if (likely(rxbuf))
-                       list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
-               else
-                       adapter->stats.null_rxbuf++;
-
-skip:
-               for (; desc_cnt > 0; desc_cnt--) {
-                       desc = &sds_ring->desc_head[consumer];
-                       desc->status_desc_data[0] =
-                               cpu_to_le64(STATUS_OWNER_PHANTOM);
-                       consumer = get_next_index(consumer, sds_ring->num_desc);
-               }
-               count++;
-       }
-
-       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-               struct qlcnic_host_rds_ring *rds_ring =
-                       &adapter->recv_ctx->rds_rings[ring];
-
-               if (!list_empty(&sds_ring->free_list[ring])) {
-                       list_for_each(cur, &sds_ring->free_list[ring]) {
-                               rxbuf = list_entry(cur,
-                                               struct qlcnic_rx_buffer, list);
-                               qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
-                       }
-                       spin_lock(&rds_ring->lock);
-                       list_splice_tail_init(&sds_ring->free_list[ring],
-                                               &rds_ring->free_list);
-                       spin_unlock(&rds_ring->lock);
-               }
-
-               qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
-       }
-
-       if (count) {
-               sds_ring->consumer = consumer;
-               writel(consumer, sds_ring->crb_sts_consumer);
-       }
-
-       return count;
-}
-
-void
-qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
-       struct qlcnic_host_rds_ring *rds_ring)
-{
-       struct rcv_desc *pdesc;
-       struct qlcnic_rx_buffer *buffer;
-       int count = 0;
-       u32 producer;
-       struct list_head *head;
-
-       producer = rds_ring->producer;
-
-       head = &rds_ring->free_list;
-       while (!list_empty(head)) {
-
-               buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
-
-               if (!buffer->skb) {
-                       if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
-                               break;
-               }
-
-               count++;
-               list_del(&buffer->list);
-
-               /* make a rcv descriptor  */
-               pdesc = &rds_ring->desc_head[producer];
-               pdesc->addr_buffer = cpu_to_le64(buffer->dma);
-               pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
-               pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
-
-               producer = get_next_index(producer, rds_ring->num_desc);
-       }
-
-       if (count) {
-               rds_ring->producer = producer;
-               writel((producer-1) & (rds_ring->num_desc-1),
-                               rds_ring->crb_rcv_producer);
-       }
-}
-
-static void
-qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_rds_ring *rds_ring)
-{
-       struct rcv_desc *pdesc;
-       struct qlcnic_rx_buffer *buffer;
-       int  count = 0;
-       uint32_t producer;
-       struct list_head *head;
-
-       if (!spin_trylock(&rds_ring->lock))
-               return;
-
-       producer = rds_ring->producer;
-
-       head = &rds_ring->free_list;
-       while (!list_empty(head)) {
-
-               buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
-
-               if (!buffer->skb) {
-                       if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
-                               break;
-               }
-
-               count++;
-               list_del(&buffer->list);
-
-               /* make a rcv descriptor  */
-               pdesc = &rds_ring->desc_head[producer];
-               pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
-               pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
-               pdesc->addr_buffer = cpu_to_le64(buffer->dma);
-
-               producer = get_next_index(producer, rds_ring->num_desc);
-       }
-
-       if (count) {
-               rds_ring->producer = producer;
-               writel((producer - 1) & (rds_ring->num_desc - 1),
-                               rds_ring->crb_rcv_producer);
-       }
-       spin_unlock(&rds_ring->lock);
-}
-
-static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
-{
-       int i;
-       unsigned char *data = skb->data;
-
-       printk(KERN_INFO "\n");
-       for (i = 0; i < skb->len; i++) {
-               QLCDB(adapter, DRV, "%02x ", data[i]);
-               if ((i & 0x0f) == 8)
-                       printk(KERN_INFO "\n");
-       }
-}
-
-void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_sds_ring *sds_ring,
-               int ring, u64 sts_data0)
-{
-       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-       struct sk_buff *skb;
-       struct qlcnic_host_rds_ring *rds_ring;
-       int index, length, cksum, pkt_offset;
-
-       if (unlikely(ring >= adapter->max_rds_rings))
-               return;
-
-       rds_ring = &recv_ctx->rds_rings[ring];
-
-       index = qlcnic_get_sts_refhandle(sts_data0);
-       length = qlcnic_get_sts_totallength(sts_data0);
-       if (unlikely(index >= rds_ring->num_desc))
-               return;
-
-       cksum  = qlcnic_get_sts_status(sts_data0);
-       pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
-
-       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
-       if (!skb)
-               return;
-
-       if (length > rds_ring->skb_size)
-               skb_put(skb, rds_ring->skb_size);
-       else
-               skb_put(skb, length);
-
-       if (pkt_offset)
-               skb_pull(skb, pkt_offset);
-
-       if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
-               adapter->diag_cnt++;
-       else
-               dump_skb(skb, adapter);
-
-       dev_kfree_skb_any(skb);
-       adapter->stats.rx_pkts++;
-       adapter->stats.rxbytes += length;
-
-       return;
-}
-
-void
-qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
-{
-       struct qlcnic_adapter *adapter = sds_ring->adapter;
-       struct status_desc *desc;
-       u64 sts_data0;
-       int ring, opcode, desc_cnt;
-
-       u32 consumer = sds_ring->consumer;
-
-       desc = &sds_ring->desc_head[consumer];
-       sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
-
-       if (!(sts_data0 & STATUS_OWNER_HOST))
-               return;
-
-       desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
-       opcode = qlcnic_get_sts_opcode(sts_data0);
-       switch (opcode) {
-       case QLCNIC_RESPONSE_DESC:
-               qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
-               break;
-       default:
-               ring = qlcnic_get_sts_type(sts_data0);
-               qlcnic_process_rcv_diag(adapter, sds_ring, ring, sts_data0);
-               break;
-       }
-
-       for (; desc_cnt > 0; desc_cnt--) {
-               desc = &sds_ring->desc_head[consumer];
-               desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
-               consumer = get_next_index(consumer, sds_ring->num_desc);
-       }
-
-       sds_ring->consumer = consumer;
-       writel(consumer, sds_ring->crb_sts_consumer);
-}
-
-void
-qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
-                       u8 alt_mac, u8 *mac)
-{
-       u32 mac_low, mac_high;
-       int i;
-
-       mac_low = off1;
-       mac_high = off2;
-
-       if (alt_mac) {
-               mac_low |= (mac_low >> 16) | (mac_high << 16);
-               mac_high >>= 16;
-       }
-
-       for (i = 0; i < 2; i++)
-               mac[i] = (u8)(mac_high >> ((1 - i) * 8));
-       for (i = 2; i < 6; i++)
-               mac[i] = (u8)(mac_low >> ((5 - i) * 8));
-}
diff --git a/drivers/net/qlcnic/qlcnic_io.c b/drivers/net/qlcnic/qlcnic_io.c
new file mode 100644 (file)
index 0000000..2ea75e6
--- /dev/null
@@ -0,0 +1,1196 @@
+#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+
+#include "qlcnic.h"
+#include "qlcnic_hw.h"
+
+void qlcnic_change_filter(struct qlcnic_adapter *adapter,
+               u64 *uaddr, __le16 vlan_id)
+{
+       struct cmd_desc_type0 *hwdesc;
+       struct qlcnic_nic_req *req;
+       struct qlcnic_mac_req *mac_req;
+       struct qlcnic_vlan_req *vlan_req;
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+       u32 producer;
+       u64 word;
+
+       producer = tx_ring->producer;
+       hwdesc = &tx_ring->desc_head[tx_ring->producer];
+
+       req = (struct qlcnic_nic_req *)hwdesc;
+       memset(req, 0, sizeof(struct qlcnic_nic_req));
+       req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
+
+       word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
+       req->req_hdr = cpu_to_le64(word);
+
+       mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
+       mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+       memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
+
+       vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
+       vlan_req->vlan_id = vlan_id;
+
+       tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
+       smp_mb();
+}
+
+static inline u8 qlcnic_mac_hash(u64 mac)
+{
+       return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff));
+}
+
+static void
+qlcnic_send_filter(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_tx_ring *tx_ring,
+               struct cmd_desc_type0 *first_desc,
+               struct sk_buff *skb)
+{
+       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+       struct qlcnic_filter *fil, *tmp_fil;
+       struct hlist_node *tmp_hnode, *n;
+       struct hlist_head *head;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       u64 src_addr = 0;
+       __le16 vlan_id = 0;
+       u8 hindex;
+
+       if (!compare_ether_addr(phdr->h_source, adapter->mac_addr))
+               return;
+
+       if (adapter->fhash.fnum >= adapter->fhash.fmax) {
+               adapter->stats.mac_filter_limit_overrun++;
+               QLCDB(adapter, DRV, "Can not add more than %d mac addresses\n",
+                     adapter->fhash.fmax);
+               return;
+       }
+
+       /* Only NPAR capable devices support vlan based learning*/
+       if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+               vlan_id = first_desc->vlan_TCI;
+       memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+       hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
+       head = &(adapter->fhash.fhead[hindex]);
+
+       hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+               if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+                           tmp_fil->vlan_id == vlan_id) {
+
+                       if (jiffies >
+                           (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
+                               ahw->hw_ops->change_l2_filter(adapter, &src_addr,
+                                       vlan_id);
+                       tmp_fil->ftime = jiffies;
+                       return;
+               }
+       }
+
+       fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
+       if (!fil)
+               return;
+
+       ahw->hw_ops->change_l2_filter(adapter, &src_addr, vlan_id);
+
+       fil->ftime = jiffies;
+       fil->vlan_id = vlan_id;
+       memcpy(fil->faddr, &src_addr, ETH_ALEN);
+       spin_lock(&adapter->mac_learn_lock);
+       hlist_add_head(&(fil->fnode), head);
+       adapter->fhash.fnum++;
+       spin_unlock(&adapter->mac_learn_lock);
+}
+
+static int
+qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
+               struct cmd_desc_type0 *first_desc,
+               struct sk_buff *skb)
+{
+       u8 opcode = 0, hdr_len = 0;
+       u16 flags = 0, vlan_tci = 0;
+       int copied, offset, copy_len;
+       struct cmd_desc_type0 *hwdesc;
+       struct vlan_ethhdr *vh;
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+       u16 protocol = ntohs(skb->protocol);
+       u32 producer = tx_ring->producer;
+
+       if (protocol == ETH_P_8021Q) {
+               vh = (struct vlan_ethhdr *)skb->data;
+               flags = FLAGS_VLAN_TAGGED;
+               vlan_tci = vh->h_vlan_TCI;
+       } else if (vlan_tx_tag_present(skb)) {
+               flags = FLAGS_VLAN_OOB;
+               vlan_tci = vlan_tx_tag_get(skb);
+       }
+       if (unlikely(adapter->pvid)) {
+               if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
+                       return -EIO;
+               if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
+                       goto set_flags;
+
+               flags = FLAGS_VLAN_OOB;
+               vlan_tci = adapter->pvid;
+       }
+set_flags:
+       qlcnic_set_tx_vlan_tci(first_desc, vlan_tci);
+       qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+       if (*(skb->data) & BIT_0) {
+               flags |= BIT_0;
+               memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
+       }
+       opcode = TX_ETHER_PKT;
+       if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
+                       skb_shinfo(skb)->gso_size > 0) {
+
+               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+               first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+               first_desc->total_hdr_length = hdr_len;
+
+               opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
+
+               /* For LSO, we need to copy the MAC/IP/TCP headers into
+               * the descriptor ring */
+               copied = 0;
+               offset = 2;
+
+               if (flags & FLAGS_VLAN_OOB) {
+                       first_desc->total_hdr_length += VLAN_HLEN;
+                       first_desc->tcp_hdr_offset = VLAN_HLEN;
+                       first_desc->ip_hdr_offset = VLAN_HLEN;
+                       /* Only in case of TSO on vlan device */
+                       flags |= FLAGS_VLAN_TAGGED;
+
+                       /* Create a TSO vlan header template for firmware */
+
+                       hwdesc = &tx_ring->desc_head[producer];
+                       tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+                       copy_len = min((int)sizeof(struct cmd_desc_type0) -
+                               offset, hdr_len + VLAN_HLEN);
+
+                       vh = (struct vlan_ethhdr *)((char *) hwdesc + 2);
+                       skb_copy_from_linear_data(skb, vh, 12);
+                       vh->h_vlan_proto = htons(ETH_P_8021Q);
+                       vh->h_vlan_TCI = htons(vlan_tci);
+
+                       skb_copy_from_linear_data_offset(skb, 12,
+                               (char *)vh + 16, copy_len - 16);
+
+                       copied = copy_len - VLAN_HLEN;
+                       offset = 0;
+
+                       producer = get_next_index(producer, tx_ring->num_desc);
+               }
+
+               while (copied < hdr_len) {
+
+                       copy_len = min((int)sizeof(struct cmd_desc_type0) -
+                               offset, (hdr_len - copied));
+
+                       hwdesc = &tx_ring->desc_head[producer];
+                       tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+                       skb_copy_from_linear_data_offset(skb, copied,
+                                (char *) hwdesc + offset, copy_len);
+
+                       copied += copy_len;
+                       offset = 0;
+
+                       producer = get_next_index(producer, tx_ring->num_desc);
+               }
+
+               tx_ring->producer = producer;
+               smp_mb();
+               adapter->stats.lso_frames++;
+
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               u8 l4proto;
+
+               if (protocol == ETH_P_IP) {
+                       l4proto = ip_hdr(skb)->protocol;
+
+                       if (l4proto == IPPROTO_TCP)
+                               opcode = TX_TCP_PKT;
+                       else if (l4proto == IPPROTO_UDP)
+                               opcode = TX_UDP_PKT;
+               } else if (protocol == ETH_P_IPV6) {
+                       l4proto = ipv6_hdr(skb)->nexthdr;
+
+                       if (l4proto == IPPROTO_TCP)
+                               opcode = TX_TCPV6_PKT;
+                       else if (l4proto == IPPROTO_UDP)
+                               opcode = TX_UDPV6_PKT;
+               }
+       }
+       first_desc->tcp_hdr_offset += skb_transport_offset(skb);
+       first_desc->ip_hdr_offset += skb_network_offset(skb);
+       qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+       return 0;
+}
+
+static int
+qlcnic_map_tx_skb(struct pci_dev *pdev,
+               struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
+{
+       struct qlcnic_skb_frag *nf;
+       struct skb_frag_struct *frag;
+       int i, nr_frags;
+       dma_addr_t map;
+
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       nf = &pbuf->frag_array[0];
+
+       map = pci_map_single(pdev, skb->data,
+                       skb_headlen(skb), PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(pdev, map))
+               goto out_err;
+
+       nf->dma = map;
+       nf->length = skb_headlen(skb);
+
+       for (i = 0; i < nr_frags; i++) {
+               frag = &skb_shinfo(skb)->frags[i];
+               nf = &pbuf->frag_array[i+1];
+
+               map = pci_map_page(pdev, frag->page, frag->page_offset,
+                       frag->size, PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(pdev, map))
+                       goto unwind;
+
+               nf->dma = map;
+               nf->length = frag->size;
+       }
+
+       return 0;
+
+unwind:
+       while (--i >= 0) {
+               nf = &pbuf->frag_array[i+1];
+               pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
+       }
+
+       nf = &pbuf->frag_array[0];
+       pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+
+out_err:
+       return -ENOMEM;
+}
+
+static void
+qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
+                       struct qlcnic_cmd_buffer *pbuf)
+{
+       struct qlcnic_skb_frag *nf = &pbuf->frag_array[0];
+       int nr_frags = skb_shinfo(skb)->nr_frags;
+       int i;
+
+       for (i = 0; i < nr_frags; i++) {
+               nf = &pbuf->frag_array[i+1];
+               pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
+       }
+
+       nf = &pbuf->frag_array[0];
+       pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+       pbuf->skb = NULL;
+}
+
+static inline void
+qlcnic_clear_cmddesc(u64 *desc)
+{
+       desc[0] = 0ULL;
+       desc[2] = 0ULL;
+       desc[7] = 0ULL;
+}
+
+netdev_tx_t
+qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+       struct qlcnic_cmd_buffer *pbuf;
+       struct qlcnic_skb_frag *buffrag;
+       struct cmd_desc_type0 *hwdesc, *first_desc;
+       struct pci_dev *pdev;
+       struct ethhdr *phdr;
+       int delta = 0;
+       int i, k;
+
+       u32 producer;
+       int frag_count;
+       u32 num_txd = tx_ring->num_desc;
+
+       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+               netif_stop_queue(netdev);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (adapter->flags & QLCNIC_MACSPOOF) {
+               phdr = (struct ethhdr *)skb->data;
+               if (compare_ether_addr(phdr->h_source,
+                                       adapter->mac_addr))
+                       goto drop_packet;
+       }
+
+       frag_count = skb_shinfo(skb)->nr_frags + 1;
+       /* 14 frags supported for normal packet and
+        * 32 frags supported for TSO packet
+        */
+       if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
+
+               for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
+                       delta += skb_shinfo(skb)->frags[i].size;
+
+               if (!__pskb_pull_tail(skb, delta))
+                       goto drop_packet;
+
+               frag_count = 1 + skb_shinfo(skb)->nr_frags;
+       }
+
+       if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
+               netif_stop_queue(netdev);
+               if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
+                       netif_start_queue(netdev);
+               else {
+                       adapter->stats.xmit_off++;
+                       return NETDEV_TX_BUSY;
+               }
+       }
+
+       producer = tx_ring->producer;
+       pbuf = &tx_ring->cmd_buf_arr[producer];
+
+       pdev = adapter->pdev;
+
+       first_desc = hwdesc = &tx_ring->desc_head[producer];
+       qlcnic_clear_cmddesc((u64 *)hwdesc);
+
+       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;
+
+       qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
+       qlcnic_set_tx_port(first_desc, adapter->portnum);
+
+       for (i = 0; i < frag_count; i++) {
+
+               k = i % 4;
+
+               if ((k == 0) && (i > 0)) {
+                       /* move to next desc.*/
+                       producer = get_next_index(producer, num_txd);
+                       hwdesc = &tx_ring->desc_head[producer];
+                       qlcnic_clear_cmddesc((u64 *)hwdesc);
+                       tx_ring->cmd_buf_arr[producer].skb = NULL;
+               }
+
+               buffrag = &pbuf->frag_array[i];
+
+               hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
+               switch (k) {
+               case 0:
+                       hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
+                       break;
+               case 1:
+                       hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
+                       break;
+               case 2:
+                       hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
+                       break;
+               case 3:
+                       hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
+                       break;
+               }
+       }
+
+       tx_ring->producer = get_next_index(producer, num_txd);
+       smp_mb();
+
+       if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
+               goto unwind_buff;
+
+       if (adapter->mac_learn)
+               qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
+
+       adapter->stats.txbytes += skb->len;
+       adapter->stats.xmitcalled++;
+
+       qlcnic_update_cmd_producer(adapter, tx_ring);
+
+       return NETDEV_TX_OK;
+
+unwind_buff:
+       qlcnic_unmap_buffers(pdev, skb, pbuf);
+drop_packet:
+       adapter->stats.txdropped++;
+       dev_kfree_skb_any(skb);
+       return NETDEV_TX_OK;
+}
+
+void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       if (adapter->ahw->linkup && !linkup) {
+               netdev_info(netdev, "NIC Link is down\n");
+               adapter->ahw->linkup = 0;
+               if (netif_running(netdev)) {
+                       netif_carrier_off(netdev);
+                       netif_stop_queue(netdev);
+               }
+       } else if (!adapter->ahw->linkup && linkup) {
+               netdev_info(netdev, "NIC Link is up\n");
+               adapter->ahw->linkup = 1;
+               if (netif_running(netdev)) {
+                       netif_carrier_on(netdev);
+                       netif_wake_queue(netdev);
+               }
+       }
+}
+
+int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_tx_ring *tx_ring, int budget)
+{
+       u32 sw_consumer, hw_consumer;
+       int count = 0, i;
+       struct qlcnic_cmd_buffer *buffer;
+       struct pci_dev *pdev = adapter->pdev;
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_skb_frag *frag;
+       int done;
+
+       if (!spin_trylock(&adapter->tx_clean_lock))
+               return 1;
+
+       sw_consumer = tx_ring->sw_consumer;
+       hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+
+       while (sw_consumer != hw_consumer) {
+               buffer = &tx_ring->cmd_buf_arr[sw_consumer];
+               if (buffer->skb) {
+                       frag = &buffer->frag_array[0];
+                       pci_unmap_single(pdev, frag->dma, frag->length,
+                                        PCI_DMA_TODEVICE);
+                       frag->dma = 0ULL;
+                       for (i = 1; i < buffer->frag_count; i++) {
+                               frag++;
+                               pci_unmap_page(pdev, frag->dma, frag->length,
+                                              PCI_DMA_TODEVICE);
+                               frag->dma = 0ULL;
+                       }
+
+                       adapter->stats.xmitfinished++;
+                       dev_kfree_skb_any(buffer->skb);
+                       buffer->skb = NULL;
+               }
+
+               sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
+               if (++count >= budget)
+                       break;
+       }
+
+       if (count && netif_running(netdev)) {
+               tx_ring->sw_consumer = sw_consumer;
+
+               smp_mb();
+
+               if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
+                       if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
+                               netif_wake_queue(netdev);
+                               adapter->stats.xmit_on++;
+                       }
+               }
+               adapter->tx_timeo_cnt = 0;
+       }
+       /*
+        * If everything is freed up to consumer then check if the ring is full
+        * If the ring is full then check if more needs to be freed and
+        * schedule the call back again.
+        *
+        * This happens when there are 2 CPUs. One could be freeing and the
+        * other filling it. If the ring is full when we get out of here and
+        * the card has already interrupted the host then the host can miss the
+        * interrupt.
+        *
+        * There is still a possible race condition and the host could miss an
+        * interrupt. The card has to take care of this.
+        */
+       hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+       done = (sw_consumer == hw_consumer);
+       spin_unlock(&adapter->tx_clean_lock);
+
+       return done;
+}
+
+int qlcnic_poll(struct napi_struct *napi, int budget)
+{
+       struct qlcnic_host_sds_ring *sds_ring =
+               container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+       int tx_complete;
+       int work_done;
+
+       tx_complete = qlcnic_process_cmd_ring(adapter, adapter->tx_ring,
+                                               budget);
+
+       work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+       if ((work_done < budget) && tx_complete) {
+               napi_complete(&sds_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+                       QLCNIC_ENABLE_INTR(adapter, sds_ring->crb_intr_mask);
+       }
+
+       return work_done;
+}
+
+int qlcnic_rx_poll(struct napi_struct *napi, int budget)
+{
+       struct qlcnic_host_sds_ring *sds_ring =
+               container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       int work_done;
+
+       work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+       if (work_done < budget) {
+               napi_complete(&sds_ring->napi);
+               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+                       QLCNIC_ENABLE_INTR(adapter, sds_ring->crb_intr_mask);
+       }
+
+       return work_done;
+}
+
+void
+qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
+                               struct qlcnic_fw_msg *msg)
+{
+       u32 cable_OUI;
+       u16 cable_len;
+       u16 link_speed;
+       u8  link_status, module, duplex, autoneg;
+       u8 lb_status = 0;
+       struct net_device *netdev = adapter->netdev;
+
+       adapter->ahw->has_link_events = 1;
+       cable_OUI = msg->body[1] & 0xffffffff;
+       cable_len = (msg->body[1] >> 32) & 0xffff;
+       link_speed = (msg->body[1] >> 48) & 0xffff;
+
+       link_status = msg->body[2] & 0xff;
+       duplex = (msg->body[2] >> 16) & 0xff;
+       autoneg = (msg->body[2] >> 24) & 0xff;
+       lb_status = (msg->body[2] >> 32) & 0x3;
+
+       module = (msg->body[2] >> 8) & 0xff;
+       if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
+               dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
+                               "length %d\n", cable_OUI, cable_len);
+       else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
+               dev_info(&netdev->dev, "unsupported cable length %d\n",
+                               cable_len);
+
+       if (!link_status && (lb_status == QLCNIC_ILB_MODE ||
+           lb_status == QLCNIC_ELB_MODE))
+               adapter->ahw->loopback_state |= QLCNIC_LINKEVENT;
+
+       qlcnic_advert_link_change(adapter, link_status);
+
+       if (duplex == LINKEVENT_FULL_DUPLEX)
+               adapter->ahw->link_duplex = DUPLEX_FULL;
+       else
+               adapter->ahw->link_duplex = DUPLEX_HALF;
+
+       adapter->ahw->module_type = module;
+       adapter->ahw->link_autoneg = autoneg;
+       adapter->ahw->link_speed = link_speed;
+}
+
+void
+qlcnic_handle_fw_message(int desc_cnt, int index,
+               struct qlcnic_host_sds_ring *sds_ring)
+{
+       struct qlcnic_fw_msg msg;
+       struct status_desc *desc;
+       struct qlcnic_adapter *adapter;
+       struct device *dev;
+       int i = 0, opcode, ret;
+
+       while (desc_cnt > 0 && i < 8) {
+               desc = &sds_ring->desc_head[index];
+               msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
+               msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);
+
+               index = get_next_index(index, sds_ring->num_desc);
+               desc_cnt--;
+       }
+
+       adapter = sds_ring->adapter;
+       dev = &adapter->pdev->dev;
+       opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);
+       switch (opcode) {
+       case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
+               qlcnic_handle_linkevent(adapter, &msg);
+               break;
+       case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK:
+               ret = (u32)(msg.body[1]);
+               switch (ret) {
+               case 0:
+                       adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE;
+                       break;
+               case 1:
+                       dev_info(dev, "loopback already in progress\n");
+                       adapter->ahw->diag_cnt = -QLCNIC_TEST_IN_PROGRESS;
+                       break;
+               case 2:
+                       dev_info(dev, "loopback cable is not connected\n");
+                       adapter->ahw->diag_cnt = -QLCNIC_LB_CABLE_NOT_CONN;
+                       break;
+               default:
+                       dev_info(dev, "loopback configure request failed,"
+                                       " ret %x\n", ret);
+                       adapter->ahw->diag_cnt = -QLCNIC_UNDEFINED_ERROR;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+int
+qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_rds_ring *rds_ring,
+               struct qlcnic_rx_buffer *buffer)
+{
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       struct pci_dev *pdev = adapter->pdev;
+
+       skb = dev_alloc_skb(rds_ring->skb_size);
+       if (!skb) {
+               adapter->stats.skb_alloc_failure++;
+               return -ENOMEM;
+       }
+
+       skb_reserve(skb, NET_IP_ALIGN);
+
+       dma = pci_map_single(pdev, skb->data,
+                       rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+
+       if (pci_dma_mapping_error(pdev, dma)) {
+               adapter->stats.rx_dma_map_error++;
+               dev_kfree_skb_any(skb);
+               return -ENOMEM;
+       }
+
+       buffer->skb = skb;
+       buffer->dma = dma;
+
+       return 0;
+}
+
+struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
+{
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       if (unlikely(buffer->skb == NULL)) {
+               WARN_ON(1);
+               return NULL;
+       }
+
+       pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
+                       PCI_DMA_FROMDEVICE);
+
+       skb = buffer->skb;
+
+       if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
+           (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
+               adapter->stats.csummed++;
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       } else {
+               skb_checksum_none_assert(skb);
+       }
+
+       skb->dev = adapter->netdev;
+
+       buffer->skb = NULL;
+
+       return skb;
+}
+
+inline int
+qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
+                       u16 *vlan_tag)
+{
+       struct ethhdr *eth_hdr;
+
+       if (!__vlan_get_tag(skb, vlan_tag)) {
+               eth_hdr = (struct ethhdr *) skb->data;
+               memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
+               skb_pull(skb, VLAN_HLEN);
+       }
+       if (!adapter->pvid)
+               return 0;
+
+       if (*vlan_tag == adapter->pvid) {
+               /* Outer vlan tag. Packet should follow non-vlan path */
+               *vlan_tag = 0xffff;
+               return 0;
+       }
+       if (adapter->flags & QLCNIC_TAGGING_ENABLED)
+               return 0;
+
+       return -EINVAL;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               int ring, u64 sts_data0)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length, cksum, pkt_offset;
+       u16 vid = 0xffff;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_get_sts_refhandle(sts_data0);
+       if (unlikely(index >= rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       length = qlcnic_get_sts_totallength(sts_data0);
+       cksum  = qlcnic_get_sts_status(sts_data0);
+       pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+       if (!skb)
+               return buffer;
+
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
+
+       if (pkt_offset)
+               skb_pull(skb, pkt_offset);
+
+       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+               adapter->stats.rxdropped++;
+               dev_kfree_skb(skb);
+               return buffer;
+       }
+
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       if (vid != 0xffff)
+               __vlan_hwaccel_put_tag(skb, vid);
+
+       napi_gro_receive(&sds_ring->napi, skb);
+
+       adapter->stats.rx_pkts++;
+       adapter->stats.rxbytes += length;
+
+       return buffer;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_lro(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               int ring, u64 sts_data0, u64 sts_data1)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct qlcnic_rx_buffer *buffer;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct iphdr *iph;
+       struct tcphdr *th;
+       bool push, timestamp;
+       int l2_hdr_offset, l4_hdr_offset;
+       int index;
+       u16 lro_length, length, data_offset;
+       u32 seq_number;
+       u16 vid = 0xffff;
+
+       if (unlikely(ring > adapter->max_rds_rings))
+               return NULL;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_get_lro_sts_refhandle(sts_data0);
+       if (unlikely(index > rds_ring->num_desc))
+               return NULL;
+
+       buffer = &rds_ring->rx_buf_arr[index];
+
+       timestamp = qlcnic_get_lro_sts_timestamp(sts_data0);
+       lro_length = qlcnic_get_lro_sts_length(sts_data0);
+       l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0);
+       l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0);
+       push = qlcnic_get_lro_sts_push_flag(sts_data0);
+       seq_number = qlcnic_get_lro_sts_seq_number(sts_data1);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+       if (!skb)
+               return buffer;
+
+       if (timestamp)
+               data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
+       else
+               data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
+
+       skb_put(skb, lro_length + data_offset);
+
+       skb_pull(skb, l2_hdr_offset);
+
+       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+               adapter->stats.rxdropped++;
+               dev_kfree_skb(skb);
+               return buffer;
+       }
+
+       skb->protocol = eth_type_trans(skb, netdev);
+
+       iph = (struct iphdr *)skb->data;
+       th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+
+       length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+       iph->tot_len = htons(length);
+       iph->check = 0;
+       iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+       th->psh = push;
+       th->seq = htonl(seq_number);
+
+       length = skb->len;
+
+       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+               skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+
+       if (vid != 0xffff)
+               __vlan_hwaccel_put_tag(skb, vid);
+       netif_receive_skb(skb);
+
+       adapter->stats.lro_pkts++;
+       adapter->stats.lrobytes += length;
+
+       return buffer;
+}
+
+int
+qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct list_head *cur;
+       struct status_desc *desc;
+       struct qlcnic_rx_buffer *rxbuf;
+       u64 sts_data0, sts_data1;
+
+       int count = 0;
+       int opcode, desc_cnt;
+       u8 ring;
+       u32 consumer = sds_ring->consumer;
+
+       while (count < max) {
+               desc = &sds_ring->desc_head[consumer];
+               sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+               if (!(sts_data0 & STATUS_OWNER_HOST))
+                       break;
+
+               desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+               opcode = qlcnic_get_sts_opcode(sts_data0);
+
+               switch (opcode) {
+               case QLCNIC_RXPKT_DESC:
+               case QLCNIC_OLD_RXPKT_DESC:
+               case QLCNIC_SYN_OFFLOAD:
+                       ring = qlcnic_get_sts_type(sts_data0);
+                       rxbuf = qlcnic_process_rcv(adapter, sds_ring,
+                                       ring, sts_data0);
+                       break;
+               case QLCNIC_LRO_DESC:
+                       ring = qlcnic_get_lro_sts_type(sts_data0);
+                       sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
+                       rxbuf = qlcnic_process_lro(adapter, sds_ring,
+                                       ring, sts_data0, sts_data1);
+                       break;
+               case QLCNIC_RESPONSE_DESC:
+                       qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+               default:
+                       goto skip;
+               }
+
+               WARN_ON(desc_cnt > 1);
+
+               if (likely(rxbuf))
+                       list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+               else
+                       adapter->stats.null_rxbuf++;
+
+skip:
+               for (; desc_cnt > 0; desc_cnt--) {
+                       desc = &sds_ring->desc_head[consumer];
+                       desc->status_desc_data[0] =
+                               cpu_to_le64(STATUS_OWNER_PHANTOM);
+                       consumer = get_next_index(consumer, sds_ring->num_desc);
+               }
+               count++;
+       }
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               struct qlcnic_host_rds_ring *rds_ring =
+                       &adapter->recv_ctx->rds_rings[ring];
+
+               if (!list_empty(&sds_ring->free_list[ring])) {
+                       list_for_each(cur, &sds_ring->free_list[ring]) {
+                               rxbuf = list_entry(cur,
+                                               struct qlcnic_rx_buffer, list);
+                               qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+                       }
+                       spin_lock(&rds_ring->lock);
+                       list_splice_tail_init(&sds_ring->free_list[ring],
+                                               &rds_ring->free_list);
+                       spin_unlock(&rds_ring->lock);
+               }
+
+               qlcnic_post_rx_buffers_nodb(adapter, rds_ring, ring);
+       }
+
+       if (count) {
+               sds_ring->consumer = consumer;
+               writel(consumer, sds_ring->crb_sts_consumer);
+       }
+
+       return count;
+}
+
+void
+qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
+       struct qlcnic_host_rds_ring *rds_ring, u8 ring_id)
+{
+       struct rcv_desc *pdesc;
+       struct qlcnic_rx_buffer *buffer;
+       int count = 0;
+       u32 producer;
+       struct list_head *head;
+
+       producer = rds_ring->producer;
+
+       head = &rds_ring->free_list;
+       while (!list_empty(head)) {
+
+               buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+               if (!buffer->skb) {
+                       if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+                               break;
+               }
+
+               count++;
+               list_del(&buffer->list);
+
+               /* make a rcv descriptor  */
+               pdesc = &rds_ring->desc_head[producer];
+               pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+               pdesc->reference_handle = cpu_to_le16(QLCNIC_MAKE_REF_HANDLE(
+                       adapter, buffer->ref_handle, ring_id));
+               pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+               producer = get_next_index(producer, rds_ring->num_desc);
+       }
+
+       if (count) {
+               rds_ring->producer = producer;
+               writel((producer-1) & (rds_ring->num_desc-1),
+                               rds_ring->crb_rcv_producer);
+       }
+}
+
+void
+qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_rds_ring *rds_ring, u8 ring_id)
+{
+       struct rcv_desc *pdesc;
+       struct qlcnic_rx_buffer *buffer;
+       int  count = 0;
+       uint32_t producer;
+       struct list_head *head;
+
+       if (!spin_trylock(&rds_ring->lock))
+               return;
+
+       producer = rds_ring->producer;
+
+       head = &rds_ring->free_list;
+       while (!list_empty(head)) {
+
+               buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+               if (!buffer->skb) {
+                       if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+                               break;
+               }
+
+               count++;
+               list_del(&buffer->list);
+
+               /* make a rcv descriptor  */
+               pdesc = &rds_ring->desc_head[producer];
+               pdesc->reference_handle = cpu_to_le16(QLCNIC_MAKE_REF_HANDLE(
+                       adapter, buffer->ref_handle, ring_id));
+               pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+               pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+               producer = get_next_index(producer, rds_ring->num_desc);
+       }
+
+       if (count) {
+               rds_ring->producer = producer;
+               writel((producer - 1) & (rds_ring->num_desc - 1),
+                               rds_ring->crb_rcv_producer);
+       }
+       spin_unlock(&rds_ring->lock);
+}
+
+void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
+{
+       int i;
+       unsigned char *data = skb->data;
+
+       printk(KERN_INFO "\n");
+       for (i = 0; i < skb->len; i++) {
+               QLCDB(adapter, DRV, "%02x ", data[i]);
+               if ((i & 0x0f) == 8)
+                       printk(KERN_INFO "\n");
+       }
+}
+
+void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter,
+               struct qlcnic_host_sds_ring *sds_ring,
+               int ring, u64 sts_data0)
+{
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+       struct sk_buff *skb;
+       struct qlcnic_host_rds_ring *rds_ring;
+       int index, length, cksum, pkt_offset;
+
+       if (unlikely(ring >= adapter->max_rds_rings))
+               return;
+
+       rds_ring = &recv_ctx->rds_rings[ring];
+
+       index = qlcnic_get_sts_refhandle(sts_data0);
+       length = qlcnic_get_sts_totallength(sts_data0);
+       if (unlikely(index >= rds_ring->num_desc))
+               return;
+
+       cksum  = qlcnic_get_sts_status(sts_data0);
+       pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+       skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+       if (!skb)
+               return;
+
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
+
+       if (pkt_offset)
+               skb_pull(skb, pkt_offset);
+
+       if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
+               adapter->ahw->diag_cnt++;
+       else
+               dump_skb(skb, adapter);
+
+       dev_kfree_skb_any(skb);
+       adapter->stats.rx_pkts++;
+       adapter->stats.rxbytes += length;
+
+       return;
+}
+
+void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+       struct qlcnic_adapter *adapter = sds_ring->adapter;
+       struct status_desc *desc;
+       u64 sts_data0;
+       int ring, opcode, desc_cnt;
+
+       u32 consumer = sds_ring->consumer;
+
+       desc = &sds_ring->desc_head[consumer];
+       sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+       if (!(sts_data0 & STATUS_OWNER_HOST))
+               return;
+
+       desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+       opcode = qlcnic_get_sts_opcode(sts_data0);
+       switch (opcode) {
+       case QLCNIC_RESPONSE_DESC:
+               qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+               break;
+       default:
+               ring = qlcnic_get_sts_type(sts_data0);
+               qlcnic_process_rcv_diag(adapter, sds_ring, ring, sts_data0);
+               break;
+       }
+
+       for (; desc_cnt > 0; desc_cnt--) {
+               desc = &sds_ring->desc_head[consumer];
+               desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+               consumer = get_next_index(consumer, sds_ring->num_desc);
+       }
+
+       sds_ring->consumer = consumer;
+       writel(consumer, sds_ring->crb_sts_consumer);
+}
+
+void
+qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
+                       u8 alt_mac, u8 *mac)
+{
+       u32 mac_low, mac_high;
+       int i;
+
+       mac_low = off1;
+       mac_high = off2;
+
+       if (alt_mac) {
+               mac_low |= (mac_low >> 16) | (mac_high << 16);
+               mac_high >>= 16;
+       }
+
+       for (i = 0; i < 2; i++)
+               mac[i] = (u8)(mac_high >> ((1 - i) * 8));
+       for (i = 2; i < 6; i++)
+               mac[i] = (u8)(mac_low >> ((5 - i) * 8));
+}
index 88ec1cfe5d38cf7c51086c52832b55b6cca92f72..ec2cef9abe5a23276447aff830cde39bb6e02349 100644 (file)
 #include <linux/interrupt.h>
 
 #include "qlcnic.h"
+#include "qlcnic_hw.h"
+#include "qlcnic_83xx.h"
 
 #include <linux/swab.h>
 #include <linux/dma-mapping.h>
 #include <net/ip.h>
 #include <linux/ipv6.h>
 #include <linux/inetdevice.h>
-#include <linux/sysfs.h>
 #include <linux/aer.h>
 #include <linux/log2.h>
 
@@ -29,28 +30,27 @@ char qlcnic_driver_name[] = "qlcnic";
 static const char qlcnic_driver_string[] = "QLogic 1/10 GbE "
        "Converged/Intelligent Ethernet Driver v" QLCNIC_LINUX_VERSIONID;
 
-static struct workqueue_struct *qlcnic_wq;
 static int qlcnic_mac_learn;
 module_param(qlcnic_mac_learn, int, 0444);
 MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
 
-static int use_msi = 1;
+int use_msi = 1;
 module_param(use_msi, int, 0444);
 MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
 
-static int use_msi_x = 1;
+int use_msi_x = 1;
 module_param(use_msi_x, int, 0444);
 MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
 
-static int auto_fw_reset = 1;
+int auto_fw_reset = 1;
 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;
+int load_fw_file;
 module_param(load_fw_file, int, 0444);
 MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
 
-static int qlcnic_config_npars;
+int qlcnic_config_npars;
 module_param(qlcnic_config_npars, int, 0444);
 MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
 
@@ -63,20 +63,13 @@ static void qlcnic_tx_timeout(struct net_device *netdev);
 static void qlcnic_attach_work(struct work_struct *work);
 static void qlcnic_fwinit_work(struct work_struct *work);
 static void qlcnic_fw_poll_work(struct work_struct *work);
-static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
+void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
                work_func_t func, int delay);
-static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
-static int qlcnic_poll(struct napi_struct *napi, int budget);
-static int qlcnic_rx_poll(struct napi_struct *napi, int budget);
+void qlcnic_cancel_idc_work(struct qlcnic_adapter *adapter);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void qlcnic_poll_controller(struct net_device *netdev);
 #endif
 
-static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
-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, u8);
 static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
@@ -85,9 +78,10 @@ static irqreturn_t qlcnic_tmp_intr(int irq, void *data);
 static irqreturn_t qlcnic_intr(int irq, void *data);
 static irqreturn_t qlcnic_msi_intr(int irq, void *data);
 static irqreturn_t qlcnic_msix_intr(int irq, void *data);
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data);
+static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *);
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
-static void qlcnic_restore_indev_addr(struct net_device *dev, unsigned long);
 static int qlcnic_start_firmware(struct qlcnic_adapter *);
 
 static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
@@ -97,18 +91,17 @@ static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
 static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
 static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
                                struct qlcnic_esw_func_cfg *);
-static int qlcnic_vlan_rx_add(struct net_device *, u16);
-static int qlcnic_vlan_rx_del(struct net_device *, u16);
+static void qlcnic_vlan_rx_add(struct net_device *, u16);
+static void qlcnic_vlan_rx_del(struct net_device *, u16);
 
 /*  PCI Device ID Table  */
 #define ENTRY(device) \
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
        .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
 
-#define PCI_DEVICE_ID_QLOGIC_QLE824X  0x8020
-
 static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
+       ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
        {0,}
 };
 
@@ -129,25 +122,61 @@ static const u32 msi_tgt_status[8] = {
        ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
 };
 
-static const
-struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
-
-static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
-{
-       writel(0, sds_ring->crb_intr_mask);
-}
+static const u32 qlcnic_reg_tbl[] = {
+       0x1B20A8, /* PEG_HALT_STAT1 */
+       0x1B20AC, /* PEG_HALT_STAT2 */
+       0x1B20B0, /* FW_HEARTBEAT */
+       0x1B2100, /* LOCK ID */
+       0x1B2128, /* FW_CAPABILITIES */
+       0x1B2138, /* drv active */
+       0x1B2140, /* dev state */
+       0x1B2144, /* drv state */
+       0x1B2148, /* drv scratch */
+       0x1B214C, /* dev partition info */
+       0x1B2174, /* drv idc ver */
+       0x1B2150, /* fw version major */
+       0x1B2154, /* fw version minor */
+       0x1B2158, /* fw version sub */
+       0x1B219C, /* npar state */
+       0x1B21FC, /* FW_IMG_VALID */
+       0x1B2250, /* CMD_PEG_STATE */
+       0x1B233C, /* RCV_PEG_STATE */
+       0x1B23B4, /* ASIC TEMP */
+       0x1B216C, /* FW api */
+       0x1B2170, /* drv op mode */
+       0x13C010, /* flash lock */
+       0x13C014, /* flash unlock */
+       0x1B212C, /* FW_CAPABILITIES_2 */
+};
 
-static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
-{
-       struct qlcnic_adapter *adapter = sds_ring->adapter;
+static const struct qlcnic_brdinfo qlcnic_boards[] = {
+       {0x1077, 0x8020, 0x1077, 0x203,
+               "8200 Series Single Port 10GbE Converged Network Adapter "
+               "(TCP/IP Networking)"},
+       {0x1077, 0x8020, 0x1077, 0x207,
+               "8200 Series Dual Port 10GbE Converged Network Adapter "
+               "(TCP/IP Networking)"},
+       {0x1077, 0x8020, 0x1077, 0x20b,
+               "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"},
+       {0x1077, 0x8020, 0x1077, 0x20c,
+               "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"},
+       {0x1077, 0x8020, 0x1077, 0x20f,
+               "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
+       {0x1077, 0x8020, 0x103c, 0x3733,
+               "NC523SFP 10Gb 2-port Server Adapter"},
+       {0x1077, 0x8020, 0x103c, 0x3346,
+               "CN1000Q Dual Port Converged Network Adapter"},
+       {0x1077, 0x8020, 0x1077, 0x210,
+               "QME8242-k 10GbE Dual Port Mezzanine Card"},
+       {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
+};
 
-       writel(0x1, sds_ring->crb_intr_mask);
+#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
 
-       if (!QLCNIC_IS_MSI_FAMILY(adapter))
-               writel(0xfbff, adapter->tgt_mask_reg);
-}
+static const
+struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
 
-static int
+int
 qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
 {
        int size = sizeof(struct qlcnic_host_sds_ring) * count;
@@ -157,7 +186,7 @@ qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
        return recv_ctx->sds_rings == NULL;
 }
 
-static void
+void
 qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
 {
        if (recv_ctx->sds_rings != NULL)
@@ -166,7 +195,66 @@ qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
        recv_ctx->sds_rings = NULL;
 }
 
-static int
+void
+qlcnic_free_tx_rings(struct qlcnic_adapter *adapter)
+{
+       int ring;
+       struct qlcnic_host_tx_ring *tx_ring;
+
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               if (tx_ring && tx_ring->cmd_buf_arr != NULL) {
+                       vfree(tx_ring->cmd_buf_arr);
+                       tx_ring->cmd_buf_arr = NULL;
+               }
+       }
+       if (adapter->tx_ring != NULL)
+               kfree(adapter->tx_ring);
+}
+
+int
+qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       int ring, size;
+       struct qlcnic_host_tx_ring *tx_ring;
+       struct qlcnic_cmd_buffer *cmd_buf_arr;
+
+       size = adapter->max_drv_tx_rings * sizeof(struct qlcnic_host_tx_ring);
+       tx_ring = kzalloc(size, GFP_KERNEL);
+       if (tx_ring == NULL) {
+               netdev_err(netdev, "failed to allocate tx rings\n");
+               return -ENOMEM;
+       }
+       adapter->tx_ring = tx_ring;
+
+       for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+               tx_ring = &adapter->tx_ring[ring];
+               tx_ring->num_desc = adapter->num_txd;
+               tx_ring->txq = netdev_get_tx_queue(netdev, ring);
+               cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
+               if (cmd_buf_arr == NULL) {
+                       netdev_err(netdev,
+                                "failed to allocate cmd buffer ring\n");
+                       qlcnic_free_tx_rings(adapter);
+                       return -ENOMEM;
+               }
+               memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
+               tx_ring->cmd_buf_arr = cmd_buf_arr;
+       }
+
+       if (QLCNIC_IS_83XX(adapter)) {
+               for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
+                       tx_ring = &adapter->tx_ring[ring];
+                       tx_ring->adapter = adapter;
+                       if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                               tx_ring->irq = adapter->msix_entries[adapter->
+                                       max_sds_rings + ring].vector;
+               }
+       }
+       return 0;
+}
+
+int
 qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        int ring;
@@ -178,13 +266,17 @@ qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
-
                if (ring == adapter->max_sds_rings - 1)
                        netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
-                               QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
+                                QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
                else
-                       netif_napi_add(netdev, &sds_ring->napi,
-                               qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
+                       netif_napi_add(netdev, &sds_ring->napi, qlcnic_rx_poll,
+                               QLCNIC_NETDEV_WEIGHT*2);
+       }
+
+       if (qlcnic_alloc_tx_rings(adapter, netdev)) {
+               qlcnic_free_sds_rings(recv_ctx);
+               return -ENOMEM;
        }
 
        return 0;
@@ -203,6 +295,8 @@ qlcnic_napi_del(struct qlcnic_adapter *adapter)
        }
 
        qlcnic_free_sds_rings(adapter->recv_ctx);
+
+       qlcnic_free_tx_rings(adapter);
 }
 
 static void
@@ -218,7 +312,7 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter)
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
                napi_enable(&sds_ring->napi);
-               qlcnic_enable_int(sds_ring);
+               QLCNIC_ENABLE_INTR(adapter, sds_ring->crb_intr_mask);
        }
 }
 
@@ -234,41 +328,12 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter)
 
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
-               qlcnic_disable_int(sds_ring);
+               QLCNIC_DISABLE_INTR(sds_ring->crb_intr_mask);
                napi_synchronize(&sds_ring->napi);
                napi_disable(&sds_ring->napi);
        }
 }
 
-static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
-{
-       memset(&adapter->stats, 0, sizeof(adapter->stats));
-}
-
-static void qlcnic_set_msix_bit(struct pci_dev *pdev, int enable)
-{
-       u32 control;
-       int pos;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               pci_read_config_dword(pdev, pos, &control);
-               if (enable)
-                       control |= PCI_MSIX_FLAGS_ENABLE;
-               else
-                       control = 0;
-               pci_write_config_dword(pdev, pos, control);
-       }
-}
-
-static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
-{
-       int i;
-
-       for (i = 0; i < count; i++)
-               adapter->msix_entries[i].entry = i;
-}
-
 static int
 qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
 {
@@ -276,7 +341,7 @@ qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
 
-       if (qlcnic_get_mac_address(adapter, mac_addr) != 0)
+       if (adapter->ahw->hw_ops->get_mac_address(adapter, mac_addr) != 0)
                return -EIO;
 
        memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
@@ -301,11 +366,11 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
                return -EOPNOTSUPP;
 
        if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
+               return -EINVAL;
 
        if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
                netif_device_detach(netdev);
-               qlcnic_napi_disable(adapter);
+               adapter->ahw->hw_ops->napi_disable(adapter);
        }
 
        memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len);
@@ -314,7 +379,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
 
        if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
                netif_device_attach(netdev);
-               qlcnic_napi_enable(adapter);
+               adapter->ahw->hw_ops->napi_enable(adapter);
        }
        return 0;
 }
@@ -338,14 +403,16 @@ static const struct net_device_ops qlcnic_netdev_ops = {
 #endif
 };
 
-static const struct net_device_ops qlcnic_netdev_failed_ops = {
-       .ndo_open          = qlcnic_open,
-};
-
 static struct qlcnic_nic_template qlcnic_ops = {
        .config_bridged_mode = qlcnic_config_bridged_mode,
        .config_led = qlcnic_config_led,
-       .start_firmware = qlcnic_start_firmware
+       .start_firmware = qlcnic_start_firmware,
+       .request_reset = qlcnic_dev_request_reset,
+       .cancel_idc_work = qlcnic_cancel_idc_work,
+       .napi_add = qlcnic_napi_add,
+       .napi_del = qlcnic_napi_del,
+       .config_ipaddr = qlcnic_config_ipaddr,
+       .clear_legacy_intr = qlcnic_clear_legacy_intr,
 };
 
 static struct qlcnic_nic_template qlcnic_vf_ops = {
@@ -354,38 +421,115 @@ static struct qlcnic_nic_template qlcnic_vf_ops = {
        .start_firmware = qlcnicvf_start_firmware
 };
 
-static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
+static struct qlcnic_hardware_ops qlcnic_hw_ops = {
+       .read_crb = qlcnic_read_crb,
+       .write_crb = qlcnic_write_crb,
+       .rdreg = qlcnic_hw_read_wx_2M,
+       .wrtreg = qlcnic_hw_write_wx_2M,
+       .get_mac_address = qlcnic_get_mac_address,
+       .setup_intr = qlcnic_setup_intr,
+       .alloc_mbx_args = qlcnic_alloc_mbx_args,
+       .mbx_cmd = qlcnic_issue_cmd,
+       .get_func_no = qlcnic_get_func_no,
+       .api_lock = qlcnic_api_lock,
+       .api_unlock = qlcnic_api_unlock,
+       .add_sysfs = qlcnic_add_sysfs,
+       .remove_sysfs = qlcnic_remove_sysfs,
+       .process_lb_rcv_ring_diag = qlcnic_process_rcv_ring_diag,
+       .create_rx_ctx = qlcnic_fw_cmd_create_rx_ctx,
+       .create_tx_ctx = qlcnic_fw_cmd_create_tx_ctx,
+       .setup_link_event = qlcnic_linkevent_request,
+       .get_nic_info = qlcnic_get_nic_info,
+       .get_pci_info = qlcnic_get_pci_info,
+       .set_nic_info = qlcnic_set_nic_info,
+       .change_macvlan = qlcnic_sre_macaddr_change,
+       .napi_enable = qlcnic_napi_enable,
+       .napi_disable = qlcnic_napi_disable,
+       .config_intr_coal = qlcnic_config_intr_coalesce,
+       .config_rss = qlcnic_config_rss,
+       .config_hw_lro = qlcnic_config_hw_lro,
+       .config_loopback = qlcnic_set_lb_mode,
+       .clear_loopback = qlcnic_clear_lb_mode,
+       .config_promisc_mode = qlcnic_nic_set_promisc,
+       .change_l2_filter = qlcnic_change_filter,
+       .get_board_info = qlcnic_get_board_info,
+};
+
+static struct qlcnic_nic_template qlcnic_83xx_ops = {
+       .config_bridged_mode = qlcnic_config_bridged_mode,
+       .config_led = qlcnic_config_led,
+       .request_reset = qlcnic_83xx_dev_request_reset,
+       .cancel_idc_work = qlcnic_83xx_cancel_idc_work,
+       .napi_add = qlcnic_83xx_napi_add,
+       .napi_del = qlcnic_83xx_napi_del,
+       .config_ipaddr = qlcnic_83xx_config_ipaddr,
+       .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr,
+};
+
+int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
 {
        struct pci_dev *pdev = adapter->pdev;
-       int err = -1;
+       int err = -1, i;
+       int max_tx_rings;
+
+       if (!adapter->msix_entries) {
+               adapter->msix_entries = kcalloc(num_msix,
+                                       sizeof(struct msix_entry), GFP_KERNEL);
+               if (!adapter->msix_entries) {
+                       dev_err(&pdev->dev, "failed allocating msix_entries\n");
+                       return -ENOMEM;
+               }
+       }
 
        adapter->max_sds_rings = 1;
        adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
-       qlcnic_set_msix_bit(pdev, 0);
 
-       if (adapter->msix_supported) {
+       if (adapter->ahw->msix_supported) {
  enable_msix:
-               qlcnic_init_msix_entries(adapter, num_msix);
+               for (i = 0; i < num_msix; i++)
+                       adapter->msix_entries[i].entry = i;
+
                err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
                if (err == 0) {
                        adapter->flags |= QLCNIC_MSIX_ENABLED;
-                       qlcnic_set_msix_bit(pdev, 1);
-
-                       adapter->max_sds_rings = num_msix;
-
+                       if (QLCNIC_IS_83XX(adapter)) {
+                               adapter->ahw->num_msix = num_msix;
+                               /* subtract the vectors which are required for
+                                mail box and tx ring */
+                               max_tx_rings = adapter->max_drv_tx_rings;
+                               adapter->max_sds_rings = num_msix -
+                                                        max_tx_rings - 1;
+                       } else
+                               adapter->max_sds_rings = num_msix;
                        dev_info(&pdev->dev, "using msi-x interrupts\n");
                        return err;
-               }
-               if (err > 0) {
-                       num_msix = rounddown_pow_of_two(err);
-                       if (num_msix)
+               } else if (err > 0) {
+                       netdev_info(adapter->netdev, "Unable to allocate %d "
+                                   "MSI-X interrupt vectors\n", num_msix);
+                       if (QLCNIC_IS_83XX(adapter)) {
+                               if (err < QLC_83XX_MINIMUM_VECTOR)
+                                       return err;
+                               err -= (adapter->max_drv_tx_rings + 1);
+                               num_msix = rounddown_pow_of_two(err);
+                               num_msix += (adapter->max_drv_tx_rings + 1);
+                       } else {
+                               num_msix = rounddown_pow_of_two(err);
+                       }
+
+                       if (num_msix) {
+                               netdev_info(adapter->netdev,
+                                           "Trying to allocate %d MSI-X interrupt vectors\n",
+                                           num_msix);
                                goto enable_msix;
-               }
+                       }
+               } else
+                       netdev_info(adapter->netdev,
+                                   "Unable to allocate %d MSI-X interrupt vectors\n",
+                                   num_msix);
        }
        return err;
 }
 
-
 static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
 {
        const struct qlcnic_legacy_intr_set *legacy_intrp;
@@ -393,7 +537,7 @@ static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
 
        if (use_msi && !pci_enable_msi(pdev)) {
                adapter->flags |= QLCNIC_MSI_ENABLED;
-               adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
+               adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter->ahw,
                                msi_tgt_status[adapter->ahw->pci_func]);
                dev_info(&pdev->dev, "using msi interrupts\n");
                adapter->msix_entries[0].vector = pdev->irq;
@@ -402,34 +546,40 @@ static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
 
        legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
 
-       adapter->int_vec_bit = legacy_intrp->int_vec_bit;
-       adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
+       adapter->ahw->int_vec_bit = legacy_intrp->int_vec_bit;
+       adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter->ahw,
                        legacy_intrp->tgt_status_reg);
-       adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
+       adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter->ahw,
                        legacy_intrp->tgt_mask_reg);
-       adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
+       adapter->isr_int_vec = qlcnic_get_ioaddr(adapter->ahw, ISR_INT_VECTOR);
 
-       adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
+       adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter->ahw,
                        ISR_INT_STATE_REG);
        dev_info(&pdev->dev, "using legacy interrupts\n");
        adapter->msix_entries[0].vector = pdev->irq;
 }
 
-static void
-qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+int
+qlcnic_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
 {
-       int num_msix;
+       int num_msix, err;
 
-       if (adapter->msix_supported) {
+       if (!num_intr)
+               num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS;
+
+       if (adapter->ahw->msix_supported) {
                num_msix = rounddown_pow_of_two(min_t(int, num_online_cpus(),
-                               QLCNIC_DEF_NUM_STS_DESC_RINGS));
-       } else
+                               num_intr));
+       }
+       else
                num_msix = 1;
 
-       if (!qlcnic_enable_msix(adapter, num_msix))
-               return;
+       err = qlcnic_enable_msix(adapter, num_msix);
+       if (err == -ENOMEM || !err)
+               return err;
 
        qlcnic_enable_msi_legacy(adapter);
+       return 0;
 }
 
 static void
@@ -439,28 +589,73 @@ qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
                pci_disable_msix(adapter->pdev);
        if (adapter->flags & QLCNIC_MSI_ENABLED)
                pci_disable_msi(adapter->pdev);
+       kfree(adapter->msix_entries);
+       adapter->msix_entries = NULL;
+
+       if (adapter->ahw->intr_tbl) {
+               vfree(adapter->ahw->intr_tbl);
+               adapter->ahw->intr_tbl = NULL;
+       }
 }
 
 static void
-qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
+qlcnic_cleanup_pci_map(struct qlcnic_hardware_context *ahw)
 {
-       if (adapter->ahw->pci_base0 != NULL)
-               iounmap(adapter->ahw->pci_base0);
+       if (ahw->pci_base0 != NULL)
+               iounmap(ahw->pci_base0);
 }
 
-static int
+int
+qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_pci_info *pci_info;
+       int ret;
+
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+               switch (adapter->ahw->port_type) {
+               case QLCNIC_GBE:
+                       adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_GBE_PORTS;
+                       break;
+               case QLCNIC_XGBE:
+                       adapter->ahw->act_pci_func = QLCNIC_NIU_MAX_XG_PORTS;
+                       break;
+               }
+               return 0;
+       }
+
+       if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+               return 0;
+
+       pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+       if (!pci_info)
+               return -ENOMEM;
+
+       ret = adapter->ahw->hw_ops->get_pci_info(adapter, pci_info);
+       kfree(pci_info);
+       return ret;
+}
+
+int
 qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_pci_info *pci_info;
-       int i, ret = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int i, ret = 0, j = 0;
+       u16 act_pci_func;
        u8 pfn;
 
        pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
        if (!pci_info)
                return -ENOMEM;
 
+       ret = ahw->hw_ops->get_pci_info(adapter, pci_info);
+       if (ret)
+               goto err_pci_info;
+
+       act_pci_func = adapter->ahw->act_pci_func;
+
        adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
-                               QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
+                               act_pci_func, GFP_KERNEL);
        if (!adapter->npars) {
                ret = -ENOMEM;
                goto err_pci_info;
@@ -473,25 +668,32 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
                goto err_npars;
        }
 
-       ret = qlcnic_get_pci_info(adapter, pci_info);
-       if (ret)
-               goto err_eswitch;
-
        for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
                pfn = pci_info[i].id;
-               if (pfn >= QLCNIC_MAX_PCI_FUNC) {
+
+               if (pfn > QLCNIC_MAX_PCI_FUNC) {
                        ret = QL_STATUS_INVALID_PARAM;
                        goto err_eswitch;
                }
-               adapter->npars[pfn].active = (u8)pci_info[i].active;
-               adapter->npars[pfn].type = (u8)pci_info[i].type;
-               adapter->npars[pfn].phy_port = (u8)pci_info[i].default_port;
-               adapter->npars[pfn].min_bw = pci_info[i].tx_min_bw;
-               adapter->npars[pfn].max_bw = pci_info[i].tx_max_bw;
+
+               if (!pci_info[i].active ||
+                               (pci_info[i].type != QLCNIC_TYPE_NIC))
+                       continue;
+
+               adapter->npars[j].pci_func = pfn;
+               adapter->npars[j].active = (u8)pci_info[i].active;
+               adapter->npars[j].type = (u8)pci_info[i].type;
+               adapter->npars[j].phy_port = (u8)pci_info[i].default_port;
+               adapter->npars[j].min_bw = pci_info[i].tx_min_bw;
+               adapter->npars[j].max_bw = pci_info[i].tx_max_bw;
+               j++;
        }
 
-       for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+       for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) {
                adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+               if (QLCNIC_IS_83XX(adapter))
+                       qlcnic_enable_eswitch(adapter, i, 1);
+       }
 
        kfree(pci_info);
        return 0;
@@ -515,87 +717,109 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
        u32 ref_count;
        int i, ret = 1;
        u32 data = QLCNIC_MGMT_FUNC;
-       void __iomem *priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        /* If other drivers are not in use set their privilege level */
-       ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
-       ret = qlcnic_api_lock(adapter);
+       ref_count = QLCRD(adapter, QLCNIC_CRB_DRV_ACTIVE);
+       ret = ahw->hw_ops->api_lock(adapter);
        if (ret)
                goto err_lock;
 
        if (qlcnic_config_npars) {
-               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-                       id = i;
-                       if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
-                               id == adapter->ahw->pci_func)
+               for (i = 0; i < ahw->act_pci_func; i++) {
+                       id = adapter->npars[i].pci_func;
+                       if (id == 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)) |
+               data = QLCRD(adapter, QLCNIC_DRV_OP_MODE);
+               data = (data & ~QLC_DEV_SET_DRV(0xf, ahw->pci_func)) |
                        (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
-                       adapter->ahw->pci_func));
+                       ahw->pci_func));
        }
-       writel(data, priv_op);
-       qlcnic_api_unlock(adapter);
+       QLCWR(adapter, QLCNIC_DRV_OP_MODE, data);
+       ahw->hw_ops->api_unlock(adapter);
 err_lock:
        return ret;
 }
 
-static void
-qlcnic_check_vf(struct qlcnic_adapter *adapter)
+void
+qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter, const struct pci_device_id *ent)
 {
-       void __iomem *msix_base_addr;
-       void __iomem *priv_op;
-       u32 func;
-       u32 msix_base;
        u32 op_mode, priv_level;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        /* Determine FW API version */
-       adapter->fw_hal_version = readl(adapter->ahw->pci_base0 +
-                                       QLCNIC_FW_API);
+       /* hilda workaround */
+       ahw->fw_hal_version = 2;
+       /* Find PCI function number */
+       ahw->hw_ops->get_func_no(adapter);
+
+       /* Determine function privilege level */
+       op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+       if (op_mode == QLC_83XX_DEFAULT_OPMODE)
+               priv_level = QLCNIC_MGMT_FUNC;
+       else
+               priv_level = QLC_83XX_GET_FUNC_PRIVILEGE_LEVEL(op_mode, ahw->pci_func);
+
+       if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+               ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
+               dev_info(&adapter->pdev->dev,
+                       "HAL Version: %d Non Privileged function\n",
+                       ahw->fw_hal_version);
+               adapter->nic_ops = &qlcnic_vf_ops;
+       } else {
+               adapter->nic_ops = &qlcnic_83xx_ops;
+       }
+}
 
+void
+qlcnic_check_vf(struct qlcnic_adapter *adapter, const struct pci_device_id *ent)
+{
+       void __iomem *priv_op;
+       u32 op_mode, priv_level;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Determine FW API version */
+       ahw->fw_hal_version = QLCRD(adapter, QLCNIC_FW_API);
        /* 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;
+       ahw->hw_ops->get_func_no(adapter);
 
        /* Determine function privilege level */
-       priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
-       op_mode = readl(priv_op);
+       priv_op = ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
+       op_mode = QLCRD(adapter, QLCNIC_DRV_OP_MODE);
        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);
+               priv_level = QLC_DEV_GET_DRV(op_mode, ahw->pci_func);
 
        if (priv_level == QLCNIC_NON_PRIV_FUNC) {
-               adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
+               ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
                dev_info(&adapter->pdev->dev,
                        "HAL Version: %d Non Privileged function\n",
-                       adapter->fw_hal_version);
+                       ahw->fw_hal_version);
                adapter->nic_ops = &qlcnic_vf_ops;
-       } else
+       } else {
                adapter->nic_ops = &qlcnic_ops;
+       }
 }
 
 static int
-qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
+qlcnic_setup_pci_map(struct pci_dev *pdev,
+               struct qlcnic_hardware_context *ahw)
 {
        void __iomem *mem_ptr0 = NULL;
        resource_size_t mem_base;
-       unsigned long mem_len, pci_len0 = 0;
-
-       struct pci_dev *pdev = adapter->pdev;
+       unsigned long mem_len, pci_len0 = 0, bar0_len;
 
        /* remap phys address */
        mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
        mem_len = pci_resource_len(pdev, 0);
 
-       if (mem_len == QLCNIC_PCI_2MB_SIZE) {
+       QLCNIC_BAR_LENGTH(pdev->device, &bar0_len);
+       if (mem_len >= bar0_len) {
 
                mem_ptr0 = pci_ioremap_bar(pdev, 0);
                if (mem_ptr0 == NULL) {
@@ -606,22 +830,18 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        } else {
                return -EIO;
        }
-
        dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
 
-       adapter->ahw->pci_base0 = mem_ptr0;
-       adapter->ahw->pci_len0 = pci_len0;
+       ahw->pci_base0 = mem_ptr0;
+       ahw->pci_len0 = pci_len0;
 
-       qlcnic_check_vf(adapter);
-
-       adapter->ahw->ocm_win_crb = qlcnic_get_ioaddr(adapter,
-               QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(
-                       adapter->ahw->pci_func)));
+       qlcnic_get_ioaddr(ahw,
+               QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(ahw->pci_func)));
 
        return 0;
 }
 
-static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
+static void qlcnic_get_brd_name(struct qlcnic_adapter *adapter, char *name)
 {
        struct pci_dev *pdev = adapter->pdev;
        int i, found = 0;
@@ -631,8 +851,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) {
-                               sprintf(name, "%pM: %s" ,
-                                       adapter->mac_addr,
+                               snprintf(name,
+                                       QLCNIC_MAX_BOARD_NAME_LEN,
+                                       "%pM: %s", adapter->mac_addr,
                                        qlcnic_boards[i].short_name);
                                found = 1;
                                break;
@@ -641,25 +862,33 @@ static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
        }
 
        if (!found)
-               sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
+               snprintf(name, ETH_ALEN, "%pM Gigabit Ethernet",
+                               adapter->mac_addr);
 }
 
-static void
+void
 qlcnic_check_options(struct qlcnic_adapter *adapter)
 {
+       int err;
        u32 fw_major, fw_minor, fw_build, prev_fw_version;
        struct pci_dev *pdev = adapter->pdev;
-       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump;
 
        prev_fw_version = adapter->fw_version;
 
-       fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
-       fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
-       fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
+       fw_major = QLCRD(adapter, QLCNIC_FW_VERSION_MAJOR);
+       fw_minor = QLCRD(adapter, QLCNIC_FW_VERSION_MINOR);
+       fw_build = QLCRD(adapter, QLCNIC_FW_VERSION_SUB);
 
        adapter->fw_version = QLCNIC_VERSION_CODE(fw_major, fw_minor, fw_build);
 
-       if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC) {
+       err = adapter->ahw->hw_ops->get_board_info(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "Error getting board config info.\n");
+               return;
+       }
+       if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
                if (fw_dump->tmpl_hdr == NULL ||
                                adapter->fw_version > prev_fw_version) {
                        if (fw_dump->tmpl_hdr)
@@ -672,7 +901,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 
        dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
                        fw_major, fw_minor, fw_build);
-       if (adapter->ahw->port_type == QLCNIC_XGBE) {
+       if (ahw->port_type == QLCNIC_XGBE) {
                if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
                        adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
                        adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
@@ -684,14 +913,14 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
                adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
                adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
 
-       } else if (adapter->ahw->port_type == QLCNIC_GBE) {
+       } else if (ahw->port_type == QLCNIC_GBE) {
                adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
                adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
                adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
                adapter->max_rxd = MAX_RCV_DESCRIPTORS_1G;
        }
 
-       adapter->msix_supported = !!use_msi_x;
+       adapter->ahw->msix_supported = !!use_msi_x;
 
        adapter->num_txd = MAX_CMD_DESCRIPTORS;
 
@@ -703,20 +932,26 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
 {
        int err;
        struct qlcnic_info nic_info;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func);
+       memset(&nic_info, 0, sizeof(struct qlcnic_info));
+       err = ahw->hw_ops->get_nic_info(adapter, &nic_info, ahw->pci_func);
        if (err)
                return err;
 
-       adapter->physical_port = (u8)nic_info.phys_port;
-       adapter->switch_mode = nic_info.switch_mode;
-       adapter->max_tx_ques = nic_info.max_tx_ques;
-       adapter->max_rx_ques = nic_info.max_rx_ques;
-       adapter->capabilities = nic_info.capabilities;
-       adapter->max_mac_filters = nic_info.max_mac_filters;
-       adapter->max_mtu = nic_info.max_mtu;
+       ahw->physical_port = (u8) nic_info.phys_port;
+       ahw->switch_mode = nic_info.switch_mode;
+       ahw->max_tx_ques = nic_info.max_tx_ques;
+       ahw->max_rx_ques = nic_info.max_rx_ques;
+       ahw->capabilities = nic_info.capabilities;
+       ahw->max_mac_filters = nic_info.max_mac_filters;
+       ahw->max_mtu = nic_info.max_mtu;
 
-       if (adapter->capabilities & BIT_6)
+       /* Disable NPAR for 83XX */
+       if (QLCNIC_IS_83XX(adapter))
+               return err;
+
+       if (ahw->capabilities & BIT_6)
                adapter->flags |= QLCNIC_ESWITCH_ENABLED;
        else
                adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
@@ -724,7 +959,7 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
        return err;
 }
 
-static void
+void
 qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
                struct qlcnic_esw_func_cfg *esw_cfg)
 {
@@ -739,26 +974,23 @@ qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
                adapter->pvid = 0;
 }
 
-static int
+static void
 qlcnic_vlan_rx_add(struct net_device *netdev, u16 vid)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        set_bit(vid, adapter->vlans);
-       return 0;
 }
 
-static int
+static void
 qlcnic_vlan_rx_del(struct net_device *netdev, u16 vid)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
        qlcnic_restore_indev_addr(netdev, NETDEV_DOWN);
        clear_bit(vid, adapter->vlans);
-       return 0;
 }
 
-static void
-qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
+void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
                struct qlcnic_esw_func_cfg *esw_cfg)
 {
        adapter->flags &= ~(QLCNIC_MACSPOOF | QLCNIC_MAC_OVERRIDE_DISABLED |
@@ -776,8 +1008,7 @@ qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
        qlcnic_set_netdev_features(adapter, esw_cfg);
 }
 
-static int
-qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_esw_func_cfg esw_cfg;
 
@@ -798,14 +1029,17 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
                struct qlcnic_esw_func_cfg *esw_cfg)
 {
        struct net_device *netdev = adapter->netdev;
-       netdev_features_t features, vlan_features;
+       unsigned long features, vlan_features;
+
+       if (QLCNIC_IS_83XX(adapter))
+               return;
 
        features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
                        NETIF_F_IPV6_CSUM | NETIF_F_GRO);
        vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
                        NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER);
 
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
+       if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
                features |= (NETIF_F_TSO | NETIF_F_TSO6);
                vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
        }
@@ -826,12 +1060,13 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
        netdev->vlan_features = (features & vlan_features);
 }
 
-static int
+int
 qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
 {
        void __iomem *priv_op;
        u32 op_mode, priv_level;
        int err = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        err = qlcnic_initialize_nic(adapter);
        if (err)
@@ -840,18 +1075,18 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
        if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
                return 0;
 
-       priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
-       op_mode = readl(priv_op);
-       priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
+       priv_op = ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
+       op_mode = QLCRD(adapter, QLCNIC_DRV_OP_MODE);
+       priv_level = QLC_DEV_GET_DRV(op_mode, ahw->pci_func);
 
        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);
+               priv_level = QLC_DEV_GET_DRV(op_mode, ahw->pci_func);
 
        if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
                if (priv_level == QLCNIC_MGMT_FUNC) {
-                       adapter->op_mode = QLCNIC_MGMT_FUNC;
+                       adapter->ahw->op_mode = QLCNIC_MGMT_FUNC;
                        err = qlcnic_init_pci_info(adapter);
                        if (err)
                                return err;
@@ -859,12 +1094,12 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
                        qlcnic_set_function_modes(adapter);
                        dev_info(&adapter->pdev->dev,
                                "HAL Version: %d, Management function\n",
-                               adapter->fw_hal_version);
+                               adapter->ahw->fw_hal_version);
                } else if (priv_level == QLCNIC_PRIV_FUNC) {
-                       adapter->op_mode = QLCNIC_PRIV_FUNC;
+                       adapter->ahw->op_mode = QLCNIC_PRIV_FUNC;
                        dev_info(&adapter->pdev->dev,
                                "HAL Version: %d, Privileged function\n",
-                               adapter->fw_hal_version);
+                               adapter->ahw->fw_hal_version);
                }
        }
 
@@ -873,7 +1108,7 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
        return err;
 }
 
-static int
+int
 qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_esw_func_cfg esw_cfg;
@@ -883,16 +1118,16 @@ qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
        if (adapter->need_fw_reset)
                return 0;
 
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-                       continue;
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
                memset(&esw_cfg, 0, sizeof(struct qlcnic_esw_func_cfg));
-               esw_cfg.pci_func = i;
-               esw_cfg.offload_flags = BIT_0;
+               esw_cfg.pci_func = adapter->npars[i].pci_func;
                esw_cfg.mac_override = BIT_0;
                esw_cfg.promisc_mode = BIT_0;
-               if (adapter->capabilities  & QLCNIC_FW_CAPABILITY_TSO)
-                       esw_cfg.offload_flags |= (BIT_1 | BIT_2);
+               if (QLCNIC_IS_82XX(adapter)) {
+                       esw_cfg.offload_flags = BIT_0;
+                       if (QLCNIC_IS_TSO_CAPABLE(adapter))
+                               esw_cfg.offload_flags |= (BIT_1 | BIT_2);
+               }
                if (qlcnic_config_switch_port(adapter, &esw_cfg))
                        return -EIO;
                npar = &adapter->npars[i];
@@ -907,6 +1142,7 @@ qlcnic_set_default_offload_settings(struct qlcnic_adapter *adapter)
        return 0;
 }
 
+
 static int
 qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
                        struct qlcnic_npar_info *npar, int pci_func)
@@ -930,37 +1166,39 @@ qlcnic_reset_eswitch_config(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-static int
+int
 qlcnic_reset_npar_config(struct qlcnic_adapter *adapter)
 {
        int i, err;
        struct qlcnic_npar_info *npar;
        struct qlcnic_info nic_info;
+       u8 pci_func;
 
-       if (!adapter->need_fw_reset)
-               return 0;
+       if (QLCNIC_IS_82XX(adapter))
+               if (!adapter->need_fw_reset)
+                       return 0;
 
        /* Set the NPAR config data after FW reset */
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
                npar = &adapter->npars[i];
-               if (npar->type != QLCNIC_TYPE_NIC)
-                       continue;
-               err = qlcnic_get_nic_info(adapter, &nic_info, i);
+               pci_func = npar->pci_func;
+               memset(&nic_info, 0, sizeof(struct qlcnic_info));
+               err = adapter->ahw->hw_ops->get_nic_info(adapter, &nic_info, pci_func);
                if (err)
                        return err;
                nic_info.min_tx_bw = npar->min_bw;
                nic_info.max_tx_bw = npar->max_bw;
-               err = qlcnic_set_nic_info(adapter, &nic_info);
+               err = adapter->ahw->hw_ops->set_nic_info(adapter, &nic_info);
                if (err)
                        return err;
 
                if (npar->enable_pm) {
                        err = qlcnic_config_port_mirroring(adapter,
-                                                       npar->dest_npar, 1, i);
+                                                       npar->dest_npar, 1, pci_func);
                        if (err)
                                return err;
                }
-               err = qlcnic_reset_eswitch_config(adapter, npar, i);
+               err = qlcnic_reset_eswitch_config(adapter, npar, pci_func);
                if (err)
                        return err;
        }
@@ -972,13 +1210,13 @@ static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
        u8 npar_opt_timeo = QLCNIC_DEV_NPAR_OPER_TIMEO;
        u32 npar_state;
 
-       if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+       if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
                return 0;
 
-       npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+       npar_state = QLCRD(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
        while (npar_state != QLCNIC_DEV_NPAR_OPER && --npar_opt_timeo) {
                msleep(1000);
-               npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+               npar_state = QLCRD(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
        }
        if (!npar_opt_timeo) {
                dev_err(&adapter->pdev->dev,
@@ -988,13 +1226,13 @@ static int qlcnic_check_npar_opertional(struct qlcnic_adapter *adapter)
        return 0;
 }
 
-static int
+int
 qlcnic_set_mgmt_operations(struct qlcnic_adapter *adapter)
 {
        int err;
 
        if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
-                   adapter->op_mode != QLCNIC_MGMT_FUNC)
+                   adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
                return 0;
 
        err = qlcnic_set_default_offload_settings(adapter);
@@ -1028,7 +1266,7 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
                if (err)
                        goto err_out;
 
-               adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
+               adapter->ahw->fw_type = QLCNIC_FLASH_ROMIMAGE;
        }
 
        err = qlcnic_need_fw_reset(adapter);
@@ -1051,9 +1289,8 @@ check_fw_status:
        if (err)
                goto err_out;
 
-       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
+       QLCWR(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
        qlcnic_idc_debug_info(adapter, 1);
-
        err = qlcnic_check_eswitch_mode(adapter);
        if (err) {
                dev_err(&adapter->pdev->dev,
@@ -1071,7 +1308,7 @@ check_fw_status:
        return 0;
 
 err_out:
-       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+       QLCWR(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
        dev_err(&adapter->pdev->dev, "Device state set to failed\n");
 
        qlcnic_release_firmware(adapter);
@@ -1083,14 +1320,18 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
 {
        irq_handler_t handler;
        struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
        int err, ring;
 
        unsigned long flags = 0;
        struct net_device *netdev = adapter->netdev;
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-       if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
-               handler = qlcnic_tmp_intr;
+       if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
+               if (QLCNIC_IS_82XX(adapter))
+                       handler = qlcnic_tmp_intr;
+               else
+                       handler = qlcnic_83xx_tmp_intr;
                if (!QLCNIC_IS_MSI_FAMILY(adapter))
                        flags |= IRQF_SHARED;
 
@@ -1106,15 +1347,33 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
        }
        adapter->irq = netdev->irq;
 
-       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-               sds_ring = &recv_ctx->sds_rings[ring];
-               sprintf(sds_ring->name, "%s[%d]", netdev->name, ring);
-               err = request_irq(sds_ring->irq, handler,
-                                 flags, sds_ring->name, sds_ring);
-               if (err)
-                       return err;
+       if(adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+               for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                       sds_ring = &recv_ctx->sds_rings[ring];
+                       snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
+                                       "%s[%d]",
+                                       netdev->name, ring);
+                       err = request_irq(sds_ring->irq, handler, flags,
+                                       sds_ring->name, sds_ring);
+                       if (err)
+                               return err;
+               }
+               if (QLCNIC_IS_83XX(adapter) &&
+                                adapter->flags & QLCNIC_MSIX_ENABLED) {
+                       handler = qlcnic_msix_tx_intr;
+                       for (ring = 0; ring < adapter->max_drv_tx_rings;
+                                                               ring++) {
+                               tx_ring = &adapter->tx_ring[ring];
+                               snprintf(tx_ring->name, IFNAMSIZ + sizeof(int),
+                                       "%s[%d]", netdev->name,
+                                       adapter->max_sds_rings + ring);
+                               err = request_irq(tx_ring->irq, handler, flags,
+                                       tx_ring->name, tx_ring);
+                               if (err)
+                                       return err;
+                       }
+               }
        }
-
        return 0;
 }
 
@@ -1123,70 +1382,95 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
 {
        int ring;
        struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_host_tx_ring *tx_ring;
 
        struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
-       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
-               sds_ring = &recv_ctx->sds_rings[ring];
-               free_irq(sds_ring->irq, sds_ring);
+               if(adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST) {
+                       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+                               sds_ring = &recv_ctx->sds_rings[ring];
+                               free_irq(sds_ring->irq, sds_ring);
+                       }
+               if (QLCNIC_IS_83XX(adapter)) {
+                       for (ring = 0; ring < adapter->max_drv_tx_rings;
+                               ring++) {
+                               tx_ring = &adapter->tx_ring[ring];
+                               if (tx_ring->irq)
+                                       free_irq(tx_ring->irq, tx_ring);
+                       }
+               }
        }
 }
 
-static int
-__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void
+qlcnic_get_lro_mss_cap(struct qlcnic_adapter *adapter)
 {
-       int ring;
-       u32 capab2;
+       u32 capab2 = 0;
 
-       struct qlcnic_host_rds_ring *rds_ring;
+       if (QLCNIC_IS_82XX(adapter)) {
+               if (adapter->ahw->capabilities &
+                       QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+                       capab2 = QLCRD(adapter, QLCNIC_FW_CAPABILITIES_2);
+                               if (capab2 &
+                                       QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+                                       adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+               }
+       } else {
+               if (QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(
+                               adapter->ahw->capabilities))
+                       adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+       }
+}
 
+int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+       u8 ring;
+       struct qlcnic_host_rds_ring *rds_ring;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
                return -EIO;
 
        if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
                return 0;
+
        if (qlcnic_set_eswitch_port_config(adapter))
                return -EIO;
 
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
-               capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
-               if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
-                       adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
-       }
+       qlcnic_get_lro_mss_cap(adapter);
 
        if (qlcnic_fw_create_ctx(adapter))
                return -EIO;
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &adapter->recv_ctx->rds_rings[ring];
-               qlcnic_post_rx_buffers(adapter, rds_ring);
+               qlcnic_post_rx_buffers(adapter, rds_ring, ring);
        }
 
        qlcnic_set_multi(netdev);
        qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
 
-       adapter->ahw->linkup = 0;
+       ahw->linkup = 0;
 
        if (adapter->max_sds_rings > 1)
-               qlcnic_config_rss(adapter, 1);
+               ahw->hw_ops->config_rss(adapter, 1);
 
-       qlcnic_config_intr_coalesce(adapter);
+       ahw->hw_ops->config_intr_coal(adapter);
 
        if (netdev->features & NETIF_F_LRO)
-               qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
-
-       qlcnic_napi_enable(adapter);
+               ahw->hw_ops->config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
 
-       qlcnic_linkevent_request(adapter, 1);
+       ahw->hw_ops->napi_enable(adapter);
 
-       adapter->reset_context = 0;
+       ahw->reset_context = 0;
        set_bit(__QLCNIC_DEV_UP, &adapter->state);
+
+       ahw->hw_ops->setup_link_event(adapter, 1);
        return 0;
 }
 
 /* Usage: During resume and firmware recovery module.*/
 
-static int
+int
 qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        int err = 0;
@@ -1199,8 +1483,7 @@ qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        return err;
 }
 
-static void
-__qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
+void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
                return;
@@ -1211,6 +1494,7 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
        smp_mb();
        spin_lock(&adapter->tx_clean_lock);
        netif_carrier_off(netdev);
+       adapter->ahw->linkup = 0;
        netif_tx_disable(netdev);
 
        qlcnic_free_mac_list(adapter);
@@ -1218,13 +1502,14 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
        if (adapter->fhash.fnum)
                qlcnic_delete_lb_filters(adapter);
 
-       qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
+       adapter->ahw->hw_ops->config_promisc_mode(adapter,
+               QLCNIC_NIU_NON_PROMISC_MODE);
 
-       qlcnic_napi_disable(adapter);
+       adapter->ahw->hw_ops->napi_disable(adapter);
 
        qlcnic_fw_destroy_ctx(adapter);
-       adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP;
 
+       adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP;
        qlcnic_reset_rx_buffers_list(adapter);
        qlcnic_release_tx_buffers(adapter);
        spin_unlock(&adapter->tx_clean_lock);
@@ -1232,27 +1517,26 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 
 /* Usage: During suspend and firmware recovery module */
 
-static void
+void
 qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        rtnl_lock();
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
        rtnl_unlock();
-
 }
 
-static int
+int
 qlcnic_attach(struct qlcnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
-       int err;
+       int err = -1;
 
        if (adapter->is_up == QLCNIC_ADAPTER_UP_MAGIC)
                return 0;
 
-       err = qlcnic_napi_add(adapter, netdev);
+       err = adapter->nic_ops->napi_add(adapter, netdev);
        if (err)
                return err;
 
@@ -1284,11 +1568,11 @@ err_out_free_hw:
 err_out_free_sw:
        qlcnic_free_sw_resources(adapter);
 err_out_napi_del:
-       qlcnic_napi_del(adapter);
+       adapter->nic_ops->napi_del(adapter);
        return err;
 }
 
-static void
+void
 qlcnic_detach(struct qlcnic_adapter *adapter)
 {
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1299,7 +1583,7 @@ qlcnic_detach(struct qlcnic_adapter *adapter)
        qlcnic_free_hw_resources(adapter);
        qlcnic_release_rx_buffers(adapter);
        qlcnic_free_irq(adapter);
-       qlcnic_napi_del(adapter);
+       adapter->nic_ops->napi_del(adapter);
        qlcnic_free_sw_resources(adapter);
 
        adapter->is_up = 0;
@@ -1312,18 +1596,17 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
        int ring;
 
        clear_bit(__QLCNIC_DEV_UP, &adapter->state);
-       if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+       if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx->sds_rings[ring];
-                       qlcnic_disable_int(sds_ring);
+                       QLCNIC_DISABLE_INTR(sds_ring->crb_intr_mask);
                }
        }
 
        qlcnic_fw_destroy_ctx(adapter);
-
        qlcnic_detach(adapter);
 
-       adapter->diag_test = 0;
+       adapter->ahw->diag_test = 0;
        adapter->max_sds_rings = max_sds_rings;
 
        if (qlcnic_attach(adapter))
@@ -1338,21 +1621,11 @@ out:
 static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
 {
        int err = 0;
-       adapter->ahw = kzalloc(sizeof(struct qlcnic_hardware_context),
-                               GFP_KERNEL);
-       if (!adapter->ahw) {
-               dev_err(&adapter->pdev->dev,
-                       "Failed to allocate recv ctx resources for adapter\n");
-               err = -ENOMEM;
-               goto err_out;
-       }
        adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
                                GFP_KERNEL);
        if (!adapter->recv_ctx) {
                dev_err(&adapter->pdev->dev,
                        "Failed to allocate recv ctx resources for adapter\n");
-               kfree(adapter->ahw);
-               adapter->ahw = NULL;
                err = -ENOMEM;
                goto err_out;
        }
@@ -1360,6 +1633,8 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
        adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
        adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
        adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+       /* clear stats */
+       memset(&adapter->stats, 0, sizeof(adapter->stats));
 err_out:
        return err;
 }
@@ -1373,8 +1648,9 @@ static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter)
                vfree(adapter->ahw->fw_dump.tmpl_hdr);
                adapter->ahw->fw_dump.tmpl_hdr = NULL;
        }
-       kfree(adapter->ahw);
-       adapter->ahw = NULL;
+
+       kfree(adapter->ahw->reset.buff);
+       adapter->ahw->fw_dump.tmpl_hdr = NULL;
 }
 
 int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
@@ -1382,7 +1658,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_host_sds_ring *sds_ring;
        struct qlcnic_host_rds_ring *rds_ring;
-       int ring;
+       u8 ring;
        int ret;
 
        netif_device_detach(netdev);
@@ -1393,7 +1669,8 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
        qlcnic_detach(adapter);
 
        adapter->max_sds_rings = 1;
-       adapter->diag_test = test;
+       adapter->ahw->diag_test = test;
+       adapter->ahw->linkup = 0;
 
        ret = qlcnic_attach(adapter);
        if (ret) {
@@ -1410,19 +1687,19 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &adapter->recv_ctx->rds_rings[ring];
-               qlcnic_post_rx_buffers(adapter, rds_ring);
+               qlcnic_post_rx_buffers(adapter, rds_ring, ring);
        }
 
-       if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
+       if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx->sds_rings[ring];
-                       qlcnic_enable_int(sds_ring);
+                       QLCNIC_ENABLE_INTR(adapter, sds_ring->crb_intr_mask);
                }
        }
 
-       if (adapter->diag_test == QLCNIC_LOOPBACK_TEST) {
+       if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
                adapter->ahw->loopback_state = 0;
-               qlcnic_linkevent_request(adapter, 1);
+               adapter->ahw->hw_ops->setup_link_event(adapter, 1);
        }
 
        set_bit(__QLCNIC_DEV_UP, &adapter->state);
@@ -1431,7 +1708,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
 }
 
 /* Reset context in hardware only */
-static int
+int
 qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
@@ -1448,6 +1725,7 @@ qlcnic_reset_hw_context(struct qlcnic_adapter *adapter)
        netif_device_attach(netdev);
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       dev_err(&adapter->pdev->dev, "%s:\n", __func__);
        return 0;
 }
 
@@ -1491,11 +1769,11 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        int err;
        struct pci_dev *pdev = adapter->pdev;
 
-       adapter->mc_enabled = 0;
-       adapter->max_mc_count = 38;
+       adapter->ahw->mc_enabled = 0;
+       adapter->ahw->max_mc_count = QLCNIC_MAX_MC_COUNT;
 
        netdev->netdev_ops         = &qlcnic_netdev_ops;
-       netdev->watchdog_timeo     = 5*HZ;
+       netdev->watchdog_timeo     = QLCNIC_WATCHDOG_TIMEOUTVALUE*HZ;
 
        qlcnic_change_mtu(netdev, netdev->mtu);
 
@@ -1504,16 +1782,16 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
                NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
 
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+       if (QLCNIC_IS_TSO_CAPABLE(adapter))
                netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
        if (pci_using_dac)
                netdev->hw_features |= NETIF_F_HIGHDMA;
 
        netdev->vlan_features = netdev->hw_features;
 
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
+       if (QLCNIC_IS_VLAN_TX_CAPABLE(adapter))
                netdev->hw_features |= NETIF_F_HW_VLAN_TX;
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
                netdev->hw_features |= NETIF_F_LRO;
 
        netdev->features |= netdev->hw_features |
@@ -1546,27 +1824,26 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
        return 0;
 }
 
-static int
-qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count)
+int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
 {
-       adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry),
-                                       GFP_KERNEL);
-
-       if (adapter->msix_entries)
-               return 0;
+       int i;
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+               if (adapter->npars[i].pci_func == pci_func)
+                       return i;
+       }
 
-       dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n");
-       return -ENOMEM;
+       return -1;
 }
 
 static int __devinit
 qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       u32 capab2;
        struct net_device *netdev = NULL;
        struct qlcnic_adapter *adapter = NULL;
+       struct qlcnic_hardware_context *ahw;
        int err;
-       uint8_t revision_id;
-       uint8_t pci_using_dac;
+       uint8_t pci_using_dac = 0;
        char brd_name[QLCNIC_MAX_BOARD_NAME_LEN];
 
        err = pci_enable_device(pdev);
@@ -1589,10 +1866,27 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_set_master(pdev);
        pci_enable_pcie_error_reporting(pdev);
 
+       ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL);
+       if (!ahw)
+               goto err_out_free_res;
+
+       if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE824X) {
+               ahw->hw_ops = &qlcnic_hw_ops;
+               ahw->reg_tbl = (u32 *) qlcnic_reg_tbl;
+       } else if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
+               qlcnic_83xx_register_map(ahw);
+       }
+       else
+               goto err_out_free_hw_res;
+
+       err = qlcnic_setup_pci_map(pdev, ahw);
+       if (err)
+               goto err_out_free_hw_res;
+
        netdev = alloc_etherdev(sizeof(struct qlcnic_adapter));
        if (!netdev) {
                err = -ENOMEM;
-               goto err_out_free_res;
+               goto err_out_iounmap;
        }
 
        SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -1600,15 +1894,21 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter = netdev_priv(netdev);
        adapter->netdev  = netdev;
        adapter->pdev    = pdev;
+       adapter->ahw = ahw;
 
-       err = qlcnic_alloc_adapter_resources(adapter);
-       if (err)
+       adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic");
+       if (adapter->qlcnic_wq == NULL) {
+               netdev_err(netdev, "Failed to create workqueue\n");
+               goto err_out_free_netdev;
+       }
+
+       if (qlcnic_alloc_adapter_resources(adapter))
                goto err_out_free_netdev;
 
        adapter->dev_rst_time = jiffies;
-       revision_id = pdev->revision;
-       adapter->ahw->revision_id = revision_id;
+       adapter->ahw->revision_id = pdev->revision;
        adapter->mac_learn = qlcnic_mac_learn;
+       adapter->max_drv_tx_rings = 1;
 
        rwlock_init(&adapter->ahw->crb_lock);
        mutex_init(&adapter->ahw->mem_lock);
@@ -1616,58 +1916,78 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        spin_lock_init(&adapter->tx_clean_lock);
        INIT_LIST_HEAD(&adapter->mac_list);
 
-       err = qlcnic_setup_pci_map(adapter);
-       if (err)
-               goto err_out_free_hw;
-
-       /* This will be reset for mezz cards  */
-       adapter->portnum = adapter->ahw->pci_func;
-
-       err = qlcnic_get_board_info(adapter);
-       if (err) {
-               dev_err(&pdev->dev, "Error getting board config info.\n");
-               goto err_out_iounmap;
-       }
-
-       err = qlcnic_setup_idc_param(adapter);
-       if (err)
-               goto err_out_iounmap;
+       /* hilda workaorund */
+       if (QLCNIC_IS_82XX(adapter)) {
+               qlcnic_check_vf(adapter, ent);
+               adapter->portnum = adapter->ahw->pci_func;
+               err = adapter->nic_ops->start_firmware(adapter);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Loading fw failed.Please Reboot\n");
+                       goto err_out_free_hw;
+               }
 
-       adapter->flags |= QLCNIC_NEED_FLR;
+               err = qlcnic_setup_idc_param(adapter);
+               if (err)
+                       goto err_out_free_hw;
 
-       err = adapter->nic_ops->start_firmware(adapter);
-       if (err) {
-               dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
-                       "\t\tIf reboot doesn't help, try flashing the card\n");
-               goto err_out_maintenance_mode;
+               adapter->flags |= QLCNIC_NEED_FLR;
+       } else if (QLCNIC_IS_83XX(adapter)) {
+               qlcnic_83xx_check_vf(adapter, ent);
+               adapter->portnum = adapter->ahw->pci_func;
+               err = qlcnic_83xx_init(adapter);
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "%s: failed. Please Reboot\n", __func__);
+                       goto err_out_free_hw;
+               }
+       } else {
+               dev_err(&pdev->dev,
+                       "%s: failed. Please Reboot\n", __func__);
+               goto err_out_free_hw;
        }
 
        if (qlcnic_read_mac_addr(adapter))
                dev_warn(&pdev->dev, "failed to read mac addr\n");
 
        if (adapter->portnum == 0) {
-               get_brd_name(adapter, brd_name);
+               qlcnic_get_brd_name(adapter, brd_name);
 
                pr_info("%s: %s Board Chip rev 0x%x\n",
                                module_name(THIS_MODULE),
                                brd_name, adapter->ahw->revision_id);
        }
 
-       qlcnic_clear_stats(adapter);
+       if ((QLCNIC_IS_82XX(adapter)) && (adapter->ahw->capabilities &
+                        QLCNIC_FW_CAPABILITY_MORE_CAPS)) {
+               capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err);
+               if (capab2 & QLCNIC_FW_CAPABILITY_2_OCBB)
+                       qlcnic_fw_cmd_set_drv_version(adapter);
+       }
+
+       if (QLCNIC_IS_83XX(adapter) && !use_msi_x && !!use_msi)
+               dev_warn(&pdev->dev, "doesn't support MSI interrupt\n");
 
-       err = qlcnic_alloc_msix_entries(adapter, adapter->max_rx_ques);
+       err = ahw->hw_ops->setup_intr(adapter, 0);
        if (err)
-               goto err_out_decr_ref;
+               goto err_out_disable_msi;
 
-       qlcnic_setup_intr(adapter);
+       if (QLCNIC_IS_83XX(adapter)) {
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err)
+                       goto err_out_disable_msi;
+       }
 
        err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
        if (err)
-               goto err_out_disable_msi;
+               goto err_out_disable_mbx_intr;
 
        pci_set_drvdata(pdev, adapter);
 
-       qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
+       if (QLCNIC_IS_82XX(adapter)) {
+               qlcnic_schedule_work(adapter,
+                       qlcnic_fw_poll_work, FW_POLL_DELAY);
+       }
 
        switch (adapter->ahw->port_type) {
        case QLCNIC_GBE:
@@ -1680,29 +2000,40 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        }
 
+       if (qlcnic_get_act_pci_func(adapter))
+               goto err_out_disable_mbx_intr;
+
        if (adapter->mac_learn)
                qlcnic_alloc_lb_filters_mem(adapter);
 
-       qlcnic_create_diag_entries(adapter);
+       adapter->ahw->hw_ops->add_sysfs(adapter);
 
        return 0;
 
+err_out_disable_mbx_intr:
+       if (QLCNIC_IS_83XX(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+       }
+
 err_out_disable_msi:
        qlcnic_teardown_intr(adapter);
-       kfree(adapter->msix_entries);
-
-err_out_decr_ref:
+       adapter->nic_ops->cancel_idc_work(adapter);
        qlcnic_clr_all_drv_state(adapter, 0);
 
-err_out_iounmap:
-       qlcnic_cleanup_pci_map(adapter);
-
 err_out_free_hw:
        qlcnic_free_adapter_resources(adapter);
 
 err_out_free_netdev:
        free_netdev(netdev);
 
+err_out_iounmap:
+       qlcnic_cleanup_pci_map(ahw);
+
+err_out_free_hw_res:
+       kfree(ahw);
+
 err_out_free_res:
        pci_release_regions(pdev);
 
@@ -1710,54 +2041,51 @@ err_out_disable_pdev:
        pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
        return err;
-
-err_out_maintenance_mode:
-       netdev->netdev_ops = &qlcnic_netdev_failed_ops;
-       SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
-       err = register_netdev(netdev);
-       if (err) {
-               dev_err(&pdev->dev, "failed to register net device\n");
-               goto err_out_decr_ref;
-       }
-       pci_set_drvdata(pdev, adapter);
-       qlcnic_create_diag_entries(adapter);
-       return 0;
 }
 
 static void __devexit qlcnic_remove(struct pci_dev *pdev)
 {
        struct qlcnic_adapter *adapter;
        struct net_device *netdev;
+       struct qlcnic_hardware_context *ahw;
 
        adapter = pci_get_drvdata(pdev);
        if (adapter == NULL)
                return;
 
        netdev = adapter->netdev;
-
-       qlcnic_cancel_fw_work(adapter);
+       ahw = adapter->ahw;
+       adapter->nic_ops->cancel_idc_work(adapter);
 
        unregister_netdev(netdev);
 
-       qlcnic_detach(adapter);
 
+       if (QLCNIC_IS_83XX(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+               qlcnic_83xx_register_nic_idc_func(adapter, 0);
+               cancel_delayed_work_sync(&adapter->idc_aen_work);
+       }
+
+       qlcnic_detach(adapter);
        if (adapter->npars != NULL)
                kfree(adapter->npars);
        if (adapter->eswitch != NULL)
                kfree(adapter->eswitch);
 
-       qlcnic_clr_all_drv_state(adapter, 0);
+       if (QLCNIC_IS_82XX(adapter))
+               qlcnic_clr_all_drv_state(adapter, 0);
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 
        qlcnic_free_lb_filters_mem(adapter);
 
        qlcnic_teardown_intr(adapter);
-       kfree(adapter->msix_entries);
 
-       qlcnic_remove_diag_entries(adapter);
+       adapter->ahw->hw_ops->remove_sysfs(adapter);
 
-       qlcnic_cleanup_pci_map(adapter);
+       qlcnic_cleanup_pci_map(ahw);
 
        qlcnic_release_firmware(adapter);
 
@@ -1766,7 +2094,12 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
+       if (adapter->qlcnic_wq) {
+               destroy_workqueue(adapter->qlcnic_wq);
+               adapter->qlcnic_wq = NULL;
+       }
        qlcnic_free_adapter_resources(adapter);
+       kfree(ahw);
        free_netdev(netdev);
 }
 static int __qlcnic_shutdown(struct pci_dev *pdev)
@@ -1776,13 +2109,13 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
        int retval;
 
        netif_device_detach(netdev);
-
-       qlcnic_cancel_fw_work(adapter);
+       adapter->nic_ops->cancel_idc_work(adapter);
 
        if (netif_running(netdev))
                qlcnic_down(adapter, netdev);
 
-       qlcnic_clr_all_drv_state(adapter, 0);
+       if (QLCNIC_IS_82XX(adapter))
+               qlcnic_clr_all_drv_state(adapter, 0);
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 
@@ -1790,9 +2123,11 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
        if (retval)
                return retval;
 
-       if (qlcnic_wol_supported(adapter)) {
-               pci_enable_wake(pdev, PCI_D3cold, 1);
-               pci_enable_wake(pdev, PCI_D3hot, 1);
+       if (QLCNIC_IS_82XX(adapter)) {
+               if (qlcnic_wol_supported(adapter)) {
+                       pci_enable_wake(pdev, PCI_D3cold, 1);
+                       pci_enable_wake(pdev, PCI_D3hot, 1);
+               }
        }
 
        return 0;
@@ -1858,16 +2193,9 @@ done:
 static int qlcnic_open(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
        int err;
 
-       if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
-               netdev_err(netdev, "Device in FAILED state\n");
-               return -EIO;
-       }
-
        netif_carrier_off(netdev);
-
        err = qlcnic_attach(adapter);
        if (err)
                return err;
@@ -1893,6 +2221,7 @@ static int qlcnic_close(struct net_device *netdev)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
        __qlcnic_down(adapter, netdev);
+
        return 0;
 }
 
@@ -1900,21 +2229,36 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
 {
        void *head;
        int i;
+       u32 filter_size = 0;
+       u16 act_pci_func = 0;
 
        if (adapter->fhash.fmax && adapter->fhash.fhead)
                return;
 
+       act_pci_func = adapter->ahw->act_pci_func;
        spin_lock_init(&adapter->mac_learn_lock);
 
-       head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
-                                                               GFP_KERNEL);
+       if (QLCNIC_IS_82XX(adapter)) {
+               filter_size = QLCNIC_LB_MAX_FILTERS;
+               adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE;
+       } else {
+               filter_size = QLC_83XX_LB_MAX_FILTERS;
+               adapter->fhash.fbucket_size = QLC_83XX_LB_BUCKET_SIZE;
+       }
+
+       head = kcalloc(adapter->fhash.fbucket_size,
+                      sizeof(struct hlist_head), GFP_KERNEL);
+
        if (!head)
                return;
 
-       adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
+       adapter->fhash.fmax = (filter_size / act_pci_func);
        adapter->fhash.fhead = head;
 
-       for (i = 0; i < adapter->fhash.fmax; i++)
+       QLCDB(adapter, DRV, "active nic func = %d, mac filter size=%d\n",
+             act_pci_func, adapter->fhash.fmax);
+
+       for (i = 0; i < adapter->fhash.fbucket_size; i++)
                INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
 }
 
@@ -1927,435 +2271,18 @@ static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
        adapter->fhash.fmax = 0;
 }
 
-static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
-               u64 uaddr, __le16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
-{
-       struct cmd_desc_type0 *hwdesc;
-       struct qlcnic_nic_req *req;
-       struct qlcnic_mac_req *mac_req;
-       struct qlcnic_vlan_req *vlan_req;
-       u32 producer;
-       u64 word;
-
-       producer = tx_ring->producer;
-       hwdesc = &tx_ring->desc_head[tx_ring->producer];
-
-       req = (struct qlcnic_nic_req *)hwdesc;
-       memset(req, 0, sizeof(struct qlcnic_nic_req));
-       req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
-
-       word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
-       req->req_hdr = cpu_to_le64(word);
-
-       mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
-       mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
-       memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
-
-       vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
-       vlan_req->vlan_id = vlan_id;
-
-       tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
-       smp_mb();
-}
-
-#define QLCNIC_MAC_HASH(MAC)\
-       ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
-
-static void
-qlcnic_send_filter(struct qlcnic_adapter *adapter,
-               struct qlcnic_host_tx_ring *tx_ring,
-               struct cmd_desc_type0 *first_desc,
-               struct sk_buff *skb)
-{
-       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
-       struct qlcnic_filter *fil, *tmp_fil;
-       struct hlist_node *tmp_hnode, *n;
-       struct hlist_head *head;
-       u64 src_addr = 0;
-       __le16 vlan_id = 0;
-       u8 hindex;
-
-       if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
-               return;
-
-       if (adapter->fhash.fnum >= adapter->fhash.fmax)
-               return;
-
-       /* Only NPAR capable devices support vlan based learning*/
-       if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
-               vlan_id = first_desc->vlan_TCI;
-       memcpy(&src_addr, phdr->h_source, ETH_ALEN);
-       hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
-       head = &(adapter->fhash.fhead[hindex]);
-
-       hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
-               if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
-                           tmp_fil->vlan_id == vlan_id) {
-
-                       if (jiffies >
-                           (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
-                               qlcnic_change_filter(adapter, src_addr, vlan_id,
-                                                               tx_ring);
-                       tmp_fil->ftime = jiffies;
-                       return;
-               }
-       }
-
-       fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
-       if (!fil)
-               return;
-
-       qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
-
-       fil->ftime = jiffies;
-       fil->vlan_id = vlan_id;
-       memcpy(fil->faddr, &src_addr, ETH_ALEN);
-       spin_lock(&adapter->mac_learn_lock);
-       hlist_add_head(&(fil->fnode), head);
-       adapter->fhash.fnum++;
-       spin_unlock(&adapter->mac_learn_lock);
-}
-
-static int
-qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
-               struct cmd_desc_type0 *first_desc,
-               struct sk_buff *skb)
-{
-       u8 opcode = 0, hdr_len = 0;
-       u16 flags = 0, vlan_tci = 0;
-       int copied, offset, copy_len;
-       struct cmd_desc_type0 *hwdesc;
-       struct vlan_ethhdr *vh;
-       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
-       u16 protocol = ntohs(skb->protocol);
-       u32 producer = tx_ring->producer;
-
-       if (protocol == ETH_P_8021Q) {
-               vh = (struct vlan_ethhdr *)skb->data;
-               flags = FLAGS_VLAN_TAGGED;
-               vlan_tci = vh->h_vlan_TCI;
-               protocol = ntohs(vh->h_vlan_encapsulated_proto);
-       } else if (vlan_tx_tag_present(skb)) {
-               flags = FLAGS_VLAN_OOB;
-               vlan_tci = vlan_tx_tag_get(skb);
-       }
-       if (unlikely(adapter->pvid)) {
-               if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
-                       return -EIO;
-               if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
-                       goto set_flags;
-
-               flags = FLAGS_VLAN_OOB;
-               vlan_tci = adapter->pvid;
-       }
-set_flags:
-       qlcnic_set_tx_vlan_tci(first_desc, vlan_tci);
-       qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
-
-       if (*(skb->data) & BIT_0) {
-               flags |= BIT_0;
-               memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
-       }
-       opcode = TX_ETHER_PKT;
-       if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
-                       skb_shinfo(skb)->gso_size > 0) {
-
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
-
-               first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
-               first_desc->total_hdr_length = hdr_len;
-
-               opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
-
-               /* For LSO, we need to copy the MAC/IP/TCP headers into
-               * the descriptor ring */
-               copied = 0;
-               offset = 2;
-
-               if (flags & FLAGS_VLAN_OOB) {
-                       first_desc->total_hdr_length += VLAN_HLEN;
-                       first_desc->tcp_hdr_offset = VLAN_HLEN;
-                       first_desc->ip_hdr_offset = VLAN_HLEN;
-                       /* Only in case of TSO on vlan device */
-                       flags |= FLAGS_VLAN_TAGGED;
-
-                       /* Create a TSO vlan header template for firmware */
-
-                       hwdesc = &tx_ring->desc_head[producer];
-                       tx_ring->cmd_buf_arr[producer].skb = NULL;
-
-                       copy_len = min((int)sizeof(struct cmd_desc_type0) -
-                               offset, hdr_len + VLAN_HLEN);
-
-                       vh = (struct vlan_ethhdr *)((char *) hwdesc + 2);
-                       skb_copy_from_linear_data(skb, vh, 12);
-                       vh->h_vlan_proto = htons(ETH_P_8021Q);
-                       vh->h_vlan_TCI = htons(vlan_tci);
-
-                       skb_copy_from_linear_data_offset(skb, 12,
-                               (char *)vh + 16, copy_len - 16);
-
-                       copied = copy_len - VLAN_HLEN;
-                       offset = 0;
-
-                       producer = get_next_index(producer, tx_ring->num_desc);
-               }
-
-               while (copied < hdr_len) {
-
-                       copy_len = min((int)sizeof(struct cmd_desc_type0) -
-                               offset, (hdr_len - copied));
-
-                       hwdesc = &tx_ring->desc_head[producer];
-                       tx_ring->cmd_buf_arr[producer].skb = NULL;
-
-                       skb_copy_from_linear_data_offset(skb, copied,
-                                (char *) hwdesc + offset, copy_len);
-
-                       copied += copy_len;
-                       offset = 0;
-
-                       producer = get_next_index(producer, tx_ring->num_desc);
-               }
-
-               tx_ring->producer = producer;
-               smp_mb();
-               adapter->stats.lso_frames++;
-
-       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               u8 l4proto;
-
-               if (protocol == ETH_P_IP) {
-                       l4proto = ip_hdr(skb)->protocol;
-
-                       if (l4proto == IPPROTO_TCP)
-                               opcode = TX_TCP_PKT;
-                       else if (l4proto == IPPROTO_UDP)
-                               opcode = TX_UDP_PKT;
-               } else if (protocol == ETH_P_IPV6) {
-                       l4proto = ipv6_hdr(skb)->nexthdr;
-
-                       if (l4proto == IPPROTO_TCP)
-                               opcode = TX_TCPV6_PKT;
-                       else if (l4proto == IPPROTO_UDP)
-                               opcode = TX_UDPV6_PKT;
-               }
-       }
-       first_desc->tcp_hdr_offset += skb_transport_offset(skb);
-       first_desc->ip_hdr_offset += skb_network_offset(skb);
-       qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
-
-       return 0;
-}
-
-static int
-qlcnic_map_tx_skb(struct pci_dev *pdev,
-               struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
-{
-       struct qlcnic_skb_frag *nf;
-       struct skb_frag_struct *frag;
-       int i, nr_frags;
-       dma_addr_t map;
-
-       nr_frags = skb_shinfo(skb)->nr_frags;
-       nf = &pbuf->frag_array[0];
-
-       map = pci_map_single(pdev, skb->data,
-                       skb_headlen(skb), PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(pdev, map))
-               goto out_err;
-
-       nf->dma = map;
-       nf->length = skb_headlen(skb);
-
-       for (i = 0; i < nr_frags; i++) {
-               frag = &skb_shinfo(skb)->frags[i];
-               nf = &pbuf->frag_array[i+1];
-
-               map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
-                                      DMA_TO_DEVICE);
-               if (dma_mapping_error(&pdev->dev, map))
-                       goto unwind;
-
-               nf->dma = map;
-               nf->length = skb_frag_size(frag);
-       }
-
-       return 0;
-
-unwind:
-       while (--i >= 0) {
-               nf = &pbuf->frag_array[i+1];
-               pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
-       }
-
-       nf = &pbuf->frag_array[0];
-       pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
-
-out_err:
-       return -ENOMEM;
-}
-
-static void
-qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
-                       struct qlcnic_cmd_buffer *pbuf)
-{
-       struct qlcnic_skb_frag *nf = &pbuf->frag_array[0];
-       int nr_frags = skb_shinfo(skb)->nr_frags;
-       int i;
-
-       for (i = 0; i < nr_frags; i++) {
-               nf = &pbuf->frag_array[i+1];
-               pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
-       }
-
-       nf = &pbuf->frag_array[0];
-       pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
-       pbuf->skb = NULL;
-}
-
-static inline void
-qlcnic_clear_cmddesc(u64 *desc)
-{
-       desc[0] = 0ULL;
-       desc[2] = 0ULL;
-       desc[7] = 0ULL;
-}
-
-netdev_tx_t
-qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
-{
-       struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
-       struct qlcnic_cmd_buffer *pbuf;
-       struct qlcnic_skb_frag *buffrag;
-       struct cmd_desc_type0 *hwdesc, *first_desc;
-       struct pci_dev *pdev;
-       struct ethhdr *phdr;
-       int delta = 0;
-       int i, k;
-
-       u32 producer;
-       int frag_count;
-       u32 num_txd = tx_ring->num_desc;
-
-       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
-               netif_stop_queue(netdev);
-               return NETDEV_TX_BUSY;
-       }
-
-       if (adapter->flags & QLCNIC_MACSPOOF) {
-               phdr = (struct ethhdr *)skb->data;
-               if (!ether_addr_equal(phdr->h_source, adapter->mac_addr))
-                       goto drop_packet;
-       }
-
-       frag_count = skb_shinfo(skb)->nr_frags + 1;
-       /* 14 frags supported for normal packet and
-        * 32 frags supported for TSO packet
-        */
-       if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
-
-               for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
-                       delta += skb_frag_size(&skb_shinfo(skb)->frags[i]);
-
-               if (!__pskb_pull_tail(skb, delta))
-                       goto drop_packet;
-
-               frag_count = 1 + skb_shinfo(skb)->nr_frags;
-       }
-
-       if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
-               netif_stop_queue(netdev);
-               if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
-                       netif_start_queue(netdev);
-               else {
-                       adapter->stats.xmit_off++;
-                       return NETDEV_TX_BUSY;
-               }
-       }
-
-       producer = tx_ring->producer;
-       pbuf = &tx_ring->cmd_buf_arr[producer];
-
-       pdev = adapter->pdev;
-
-       first_desc = hwdesc = &tx_ring->desc_head[producer];
-       qlcnic_clear_cmddesc((u64 *)hwdesc);
-
-       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;
-
-       qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
-       qlcnic_set_tx_port(first_desc, adapter->portnum);
-
-       for (i = 0; i < frag_count; i++) {
-
-               k = i % 4;
-
-               if ((k == 0) && (i > 0)) {
-                       /* move to next desc.*/
-                       producer = get_next_index(producer, num_txd);
-                       hwdesc = &tx_ring->desc_head[producer];
-                       qlcnic_clear_cmddesc((u64 *)hwdesc);
-                       tx_ring->cmd_buf_arr[producer].skb = NULL;
-               }
-
-               buffrag = &pbuf->frag_array[i];
-
-               hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
-               switch (k) {
-               case 0:
-                       hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
-                       break;
-               case 1:
-                       hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
-                       break;
-               case 2:
-                       hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
-                       break;
-               case 3:
-                       hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
-                       break;
-               }
-       }
-
-       tx_ring->producer = get_next_index(producer, num_txd);
-       smp_mb();
-
-       if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
-               goto unwind_buff;
-
-       if (adapter->mac_learn)
-               qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
-
-       adapter->stats.txbytes += skb->len;
-       adapter->stats.xmitcalled++;
-
-       qlcnic_update_cmd_producer(adapter, tx_ring);
-
-       return NETDEV_TX_OK;
-
-unwind_buff:
-       qlcnic_unmap_buffers(pdev, skb, pbuf);
-drop_packet:
-       adapter->stats.txdropped++;
-       dev_kfree_skb_any(skb);
-       return NETDEV_TX_OK;
-}
-
-static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
+int qlcnic_check_temp(struct qlcnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        u32 temp, temp_state, temp_val;
        int rv = 0;
 
-       temp = QLCRD32(adapter, CRB_TEMP_STATE);
+       temp = 0;
+
+       if (QLCNIC_IS_83XX(adapter))
+               temp = QLCRDX(adapter->ahw, QLC_83XX_ASIC_TEMP);
+       if (QLCNIC_IS_82XX(adapter))
+               temp = QLCRD(adapter, QLCNIC_ASIC_TEMP);
 
        temp_state = qlcnic_get_temp_state(temp);
        temp_val = qlcnic_get_temp_val(temp);
@@ -2367,7 +2294,7 @@ static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
                       temp_val);
                rv = 1;
        } else if (temp_state == QLCNIC_TEMP_WARN) {
-               if (adapter->temp == QLCNIC_TEMP_NORMAL) {
+               if (adapter->ahw->temp == QLCNIC_TEMP_NORMAL) {
                        dev_err(&netdev->dev,
                               "Device temperature %d degrees C "
                               "exceeds operating range."
@@ -2375,37 +2302,16 @@ static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
                               temp_val);
                }
        } else {
-               if (adapter->temp == QLCNIC_TEMP_WARN) {
+               if (adapter->ahw->temp == QLCNIC_TEMP_WARN) {
                        dev_info(&netdev->dev,
                               "Device temperature is now %d degrees C"
                               " in normal range.\n", temp_val);
                }
        }
-       adapter->temp = temp_state;
+       adapter->ahw->temp = temp_state;
        return rv;
 }
 
-void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
-{
-       struct net_device *netdev = adapter->netdev;
-
-       if (adapter->ahw->linkup && !linkup) {
-               netdev_info(netdev, "NIC Link is down\n");
-               adapter->ahw->linkup = 0;
-               if (netif_running(netdev)) {
-                       netif_carrier_off(netdev);
-                       netif_stop_queue(netdev);
-               }
-       } else if (!adapter->ahw->linkup && linkup) {
-               netdev_info(netdev, "NIC Link is up\n");
-               adapter->ahw->linkup = 1;
-               if (netif_running(netdev)) {
-                       netif_carrier_on(netdev);
-                       netif_wake_queue(netdev);
-               }
-       }
-}
-
 static void qlcnic_tx_timeout(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -2418,7 +2324,7 @@ static void qlcnic_tx_timeout(struct net_device *netdev)
        if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
                adapter->need_fw_reset = 1;
        else
-               adapter->reset_context = 1;
+               adapter->ahw->reset_context = 1;
 }
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
@@ -2442,7 +2348,7 @@ static irqreturn_t qlcnic_clear_legacy_intr(struct qlcnic_adapter *adapter)
 
        status = readl(adapter->isr_int_vec);
 
-       if (!(status & adapter->int_vec_bit))
+       if (!(status & adapter->ahw->int_vec_bit))
                return IRQ_NONE;
 
        /* check interrupt state machine, to be sure */
@@ -2470,12 +2376,12 @@ static irqreturn_t qlcnic_tmp_intr(int irq, void *data)
                goto done;
        }
 
-       if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
+       if (adapter->nic_ops->clear_legacy_intr(adapter) == IRQ_NONE)
                return IRQ_NONE;
 
 done:
-       adapter->diag_cnt++;
-       qlcnic_enable_int(sds_ring);
+       adapter->ahw->diag_cnt++;
+       QLCNIC_ENABLE_INTR(adapter, sds_ring->crb_intr_mask);
        return IRQ_HANDLED;
 }
 
@@ -2484,7 +2390,7 @@ static irqreturn_t qlcnic_intr(int irq, void *data)
        struct qlcnic_host_sds_ring *sds_ring = data;
        struct qlcnic_adapter *adapter = sds_ring->adapter;
 
-       if (qlcnic_clear_legacy_intr(adapter) == IRQ_NONE)
+       if (adapter->nic_ops->clear_legacy_intr(adapter) == IRQ_NONE)
                return IRQ_NONE;
 
        napi_schedule(&sds_ring->napi);
@@ -2512,129 +2418,21 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
+static irqreturn_t qlcnic_msix_tx_intr(int irq, void *data)
 {
-       u32 sw_consumer, hw_consumer;
-       int count = 0, i;
-       struct qlcnic_cmd_buffer *buffer;
-       struct pci_dev *pdev = adapter->pdev;
-       struct net_device *netdev = adapter->netdev;
-       struct qlcnic_skb_frag *frag;
-       int done;
-       struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
-
-       if (!spin_trylock(&adapter->tx_clean_lock))
-               return 1;
+       struct qlcnic_host_tx_ring *tx_ring = data;
 
-       sw_consumer = tx_ring->sw_consumer;
-       hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
-
-       while (sw_consumer != hw_consumer) {
-               buffer = &tx_ring->cmd_buf_arr[sw_consumer];
-               if (buffer->skb) {
-                       frag = &buffer->frag_array[0];
-                       pci_unmap_single(pdev, frag->dma, frag->length,
-                                        PCI_DMA_TODEVICE);
-                       frag->dma = 0ULL;
-                       for (i = 1; i < buffer->frag_count; i++) {
-                               frag++;
-                               pci_unmap_page(pdev, frag->dma, frag->length,
-                                              PCI_DMA_TODEVICE);
-                               frag->dma = 0ULL;
-                       }
+       napi_schedule(&tx_ring->napi);
+       return IRQ_HANDLED;
+}
 
-                       adapter->stats.xmitfinished++;
-                       dev_kfree_skb_any(buffer->skb);
-                       buffer->skb = NULL;
-               }
-
-               sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
-               if (++count >= MAX_STATUS_HANDLE)
-                       break;
-       }
-
-       if (count && netif_running(netdev)) {
-               tx_ring->sw_consumer = sw_consumer;
-
-               smp_mb();
-
-               if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
-                       if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
-                               netif_wake_queue(netdev);
-                               adapter->stats.xmit_on++;
-                       }
-               }
-               adapter->tx_timeo_cnt = 0;
-       }
-       /*
-        * If everything is freed up to consumer then check if the ring is full
-        * If the ring is full then check if more needs to be freed and
-        * schedule the call back again.
-        *
-        * This happens when there are 2 CPUs. One could be freeing and the
-        * other filling it. If the ring is full when we get out of here and
-        * the card has already interrupted the host then the host can miss the
-        * interrupt.
-        *
-        * There is still a possible race condition and the host could miss an
-        * interrupt. The card has to take care of this.
-        */
-       hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
-       done = (sw_consumer == hw_consumer);
-       spin_unlock(&adapter->tx_clean_lock);
-
-       return done;
-}
-
-static int qlcnic_poll(struct napi_struct *napi, int budget)
-{
-       struct qlcnic_host_sds_ring *sds_ring =
-               container_of(napi, struct qlcnic_host_sds_ring, napi);
-
-       struct qlcnic_adapter *adapter = sds_ring->adapter;
-
-       int tx_complete;
-       int work_done;
-
-       tx_complete = qlcnic_process_cmd_ring(adapter);
-
-       work_done = qlcnic_process_rcv_ring(sds_ring, budget);
-
-       if ((work_done < budget) && tx_complete) {
-               napi_complete(&sds_ring->napi);
-               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
-                       qlcnic_enable_int(sds_ring);
-       }
-
-       return work_done;
-}
-
-static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
-{
-       struct qlcnic_host_sds_ring *sds_ring =
-               container_of(napi, struct qlcnic_host_sds_ring, napi);
-
-       struct qlcnic_adapter *adapter = sds_ring->adapter;
-       int work_done;
-
-       work_done = qlcnic_process_rcv_ring(sds_ring, budget);
-
-       if (work_done < budget) {
-               napi_complete(&sds_ring->napi);
-               if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
-                       qlcnic_enable_int(sds_ring);
-       }
-
-       return work_done;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void qlcnic_poll_controller(struct net_device *netdev)
-{
-       int ring;
-       struct qlcnic_host_sds_ring *sds_ring;
-       struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void qlcnic_poll_controller(struct net_device *netdev)
+{
+       int ring;
+       struct qlcnic_host_sds_ring *sds_ring;
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
 
        disable_irq(adapter->irq);
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
@@ -2654,7 +2452,7 @@ qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
        val |= encoding << 7;
        val |= (jiffies - adapter->dev_rst_time) << 8;
 
-       QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
+       QLCWR(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
        adapter->dev_rst_time = jiffies;
 }
 
@@ -2666,19 +2464,19 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
        WARN_ON(state != QLCNIC_DEV_NEED_RESET &&
                        state != QLCNIC_DEV_NEED_QUISCENT);
 
-       if (qlcnic_api_lock(adapter))
+       if (adapter->ahw->hw_ops->api_lock(adapter))
                return -EIO;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
 
        if (state == QLCNIC_DEV_NEED_RESET)
                QLC_DEV_SET_RST_RDY(val, adapter->portnum);
        else if (state == QLCNIC_DEV_NEED_QUISCENT)
                QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
 
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLCWR(adapter, QLCNIC_CRB_DRV_STATE, val);
 
-       qlcnic_api_unlock(adapter);
+       adapter->ahw->hw_ops->api_unlock(adapter);
 
        return 0;
 }
@@ -2688,14 +2486,14 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
 {
        u32  val;
 
-       if (qlcnic_api_lock(adapter))
+       if (adapter->ahw->hw_ops->api_lock(adapter))
                return -EBUSY;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
        QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLCWR(adapter, QLCNIC_CRB_DRV_STATE, val);
 
-       qlcnic_api_unlock(adapter);
+       adapter->ahw->hw_ops->api_unlock(adapter);
 
        return 0;
 }
@@ -2705,25 +2503,25 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed)
 {
        u32  val;
 
-       if (qlcnic_api_lock(adapter))
+       if (adapter->ahw->hw_ops->api_lock(adapter))
                goto err;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+       val = QLCRD(adapter, QLCNIC_CRB_DRV_ACTIVE);
        QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+       QLCWR(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
 
        if (failed) {
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+               QLCWR(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
                dev_info(&adapter->pdev->dev,
                                "Device state set to Failed. Please Reboot\n");
        } else if (!(val & 0x11111111))
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
+               QLCWR(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_COLD);
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
        QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLCWR(adapter, QLCNIC_CRB_DRV_STATE, val);
 
-       qlcnic_api_unlock(adapter);
+       adapter->ahw->hw_ops->api_unlock(adapter);
 err:
        adapter->fw_fail_cnt = 0;
        adapter->flags &= ~QLCNIC_FW_HANG;
@@ -2736,12 +2534,13 @@ static int
 qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 {
        int act, state, active_mask;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       act = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+       state = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
+       act = QLCRD(adapter, QLCNIC_CRB_DRV_ACTIVE);
 
        if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
-               active_mask = (~(1 << (adapter->ahw->pci_func * 4)));
+               active_mask = (~(1 << (ahw->pci_func * 4)));
                act = act & active_mask;
        }
 
@@ -2754,7 +2553,7 @@ qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 
 static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
 {
-       u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
+       u32 val = QLCRD(adapter, QLCNIC_CRB_DRV_IDC_VER);
 
        if (val != QLCNIC_DRV_IDC_VER) {
                dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
@@ -2771,50 +2570,51 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
        u8 dev_init_timeo = adapter->dev_init_timeo;
        u8 portnum = adapter->portnum;
        u8 ret;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
                return 1;
 
-       if (qlcnic_api_lock(adapter))
+       if (ahw->hw_ops->api_lock(adapter))
                return -1;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
+       val = QLCRD(adapter, QLCNIC_CRB_DRV_ACTIVE);
        if (!(val & (1 << (portnum * 4)))) {
                QLC_DEV_SET_REF_CNT(val, portnum);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
+               QLCWR(adapter, QLCNIC_CRB_DRV_ACTIVE, val);
        }
 
-       prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       prev_state = QLCRD(adapter, QLCNIC_CRB_DEV_STATE);
        QLCDB(adapter, HW, "Device state = %u\n", prev_state);
 
        switch (prev_state) {
        case QLCNIC_DEV_COLD:
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
+               QLCWR(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+               QLCWR(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
                qlcnic_idc_debug_info(adapter, 0);
-               qlcnic_api_unlock(adapter);
+               ahw->hw_ops->api_unlock(adapter);
                return 1;
 
        case QLCNIC_DEV_READY:
                ret = qlcnic_check_idc_ver(adapter);
-               qlcnic_api_unlock(adapter);
+               ahw->hw_ops->api_unlock(adapter);
                return ret;
 
        case QLCNIC_DEV_NEED_RESET:
-               val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+               val = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
                QLC_DEV_SET_RST_RDY(val, portnum);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+               QLCWR(adapter, QLCNIC_CRB_DRV_STATE, val);
                break;
 
        case QLCNIC_DEV_NEED_QUISCENT:
-               val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+               val = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
                QLC_DEV_SET_QSCNT_RDY(val, portnum);
-               QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+               QLCWR(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);
+               ahw->hw_ops->api_unlock(adapter);
                return -1;
 
        case QLCNIC_DEV_INITIALIZING:
@@ -2822,11 +2622,11 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
                break;
        }
 
-       qlcnic_api_unlock(adapter);
+       ahw->hw_ops->api_unlock(adapter);
 
        do {
                msleep(1000);
-               prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+               prev_state = QLCRD(adapter, QLCNIC_CRB_DEV_STATE);
 
                if (prev_state == QLCNIC_DEV_QUISCENT)
                        continue;
@@ -2838,15 +2638,15 @@ qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
                return -1;
        }
 
-       if (qlcnic_api_lock(adapter))
+       if (ahw->hw_ops->api_lock(adapter))
                return -1;
 
-       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+       val = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
        QLC_DEV_CLR_RST_QSCNT(val, portnum);
-       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+       QLCWR(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        ret = qlcnic_check_idc_ver(adapter);
-       qlcnic_api_unlock(adapter);
+       ahw->hw_ops->api_unlock(adapter);
 
        return ret;
 }
@@ -2858,21 +2658,22 @@ qlcnic_fwinit_work(struct work_struct *work)
                        struct qlcnic_adapter, fw_work.work);
        u32 dev_state = 0xf;
        u32 val;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       if (qlcnic_api_lock(adapter))
+       if (ahw->hw_ops->api_lock(adapter))
                goto err_ret;
 
-       dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       dev_state = QLCRD(adapter, QLCNIC_CRB_DEV_STATE);
        if (dev_state == QLCNIC_DEV_QUISCENT ||
            dev_state == QLCNIC_DEV_NEED_QUISCENT) {
-               qlcnic_api_unlock(adapter);
+               ahw->hw_ops->api_unlock(adapter);
                qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
                                                FW_POLL_DELAY * 2);
                return;
        }
 
-       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
-               qlcnic_api_unlock(adapter);
+       if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               ahw->hw_ops->api_unlock(adapter);
                goto wait_npar;
        }
 
@@ -2891,25 +2692,23 @@ qlcnic_fwinit_work(struct work_struct *work)
 
        if (!qlcnic_check_drv_state(adapter)) {
 skip_ack_check:
-               dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+               dev_state = QLCRD(adapter, QLCNIC_CRB_DEV_STATE);
 
                if (dev_state == QLCNIC_DEV_NEED_RESET) {
-                       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
+                       QLCWR(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);
-                       val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
+                       val = QLCRD(adapter, QLCNIC_CRB_DRV_STATE);
                        QLC_DEV_SET_RST_RDY(val, adapter->portnum);
-                       QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
+                       QLCWR(adapter, QLCNIC_CRB_DRV_STATE, val);
                }
 
-               qlcnic_api_unlock(adapter);
+               ahw->hw_ops->api_unlock(adapter);
 
                rtnl_lock();
-               if (adapter->ahw->fw_dump.enable &&
-                   (adapter->flags & QLCNIC_FW_RESET_OWNER)) {
-                       QLCDB(adapter, DRV, "Take FW dump\n");
+               if (adapter->flags & QLCNIC_FW_RESET_OWNER) {
                        qlcnic_dump_fw(adapter);
                        adapter->flags |= QLCNIC_FW_HANG;
                }
@@ -2924,10 +2723,10 @@ skip_ack_check:
                goto err_ret;
        }
 
-       qlcnic_api_unlock(adapter);
+       ahw->hw_ops->api_unlock(adapter);
 
 wait_npar:
-       dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       dev_state = QLCRD(adapter, QLCNIC_CRB_DEV_STATE);
        QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
 
        switch (dev_state) {
@@ -2969,7 +2768,7 @@ qlcnic_detach_work(struct work_struct *work)
        } else
                qlcnic_down(adapter, netdev);
 
-       status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+       status = QLCRD(adapter, QLCNIC_PEG_HALT_STATUS1);
 
        if (status & QLCNIC_RCODE_FATAL_ERROR) {
                dev_err(&adapter->pdev->dev,
@@ -2987,9 +2786,9 @@ qlcnic_detach_work(struct work_struct *work)
                goto err_ret;
        }
 
-       if (adapter->temp == QLCNIC_TEMP_PANIC) {
+       if (adapter->ahw->temp == QLCNIC_TEMP_PANIC) {
                dev_err(&adapter->pdev->dev, "Detaching the device: temp=%d\n",
-                       adapter->temp);
+                       adapter->ahw->temp);
                goto err_ret;
        }
 
@@ -3020,19 +2819,19 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
 {
        u32 state;
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+       state = QLCRD(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
        if (state == QLCNIC_DEV_NPAR_NON_OPER)
                return;
 
-       if (qlcnic_api_lock(adapter))
+       if (adapter->ahw->hw_ops->api_lock(adapter))
                return;
-       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
-       qlcnic_api_unlock(adapter);
+       QLCWR(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
+       adapter->ahw->hw_ops->api_unlock(adapter);
 }
 
 /*Transit to RESET state from READY state only */
 void
-qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
+qlcnic_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
 {
        u32 state, xg_val = 0, gb_val = 0;
 
@@ -3047,42 +2846,38 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
        dev_info(&adapter->pdev->dev, "Pause control frames disabled"
                                " on all ports\n");
        adapter->need_fw_reset = 1;
-       if (qlcnic_api_lock(adapter))
-               return;
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-       if (state  == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
-               netdev_err(adapter->netdev,
-                               "Device is in FAILED state, Please Reboot\n");
-               qlcnic_api_unlock(adapter);
+       if (adapter->ahw->hw_ops->api_lock(adapter))
                return;
-       }
+
+       state = QLCRD(adapter, QLCNIC_CRB_DEV_STATE);
 
        if (state == QLCNIC_DEV_READY) {
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
+               QLCWR(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
                adapter->flags |= QLCNIC_FW_RESET_OWNER;
                QLCDB(adapter, DRV, "NEED_RESET state set\n");
                qlcnic_idc_debug_info(adapter, 0);
        }
 
-       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_NON_OPER);
-       qlcnic_api_unlock(adapter);
+       QLCWR(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+               QLCNIC_DEV_NPAR_NON_OPER);
+       adapter->ahw->hw_ops->api_unlock(adapter);
 }
 
 /* Transit to NPAR READY state from NPAR NOT READY state */
 static void
 qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
 {
-       if (qlcnic_api_lock(adapter))
+       if (adapter->ahw->hw_ops->api_lock(adapter))
                return;
 
-       QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
+       QLCWR(adapter, QLCNIC_CRB_DEV_NPAR_STATE, QLCNIC_DEV_NPAR_OPER);
        QLCDB(adapter, DRV, "NPAR operational state set\n");
 
-       qlcnic_api_unlock(adapter);
+       adapter->ahw->hw_ops->api_unlock(adapter);
 }
 
-static void
+void
 qlcnic_schedule_work(struct qlcnic_adapter *adapter,
                work_func_t func, int delay)
 {
@@ -3090,19 +2885,16 @@ qlcnic_schedule_work(struct qlcnic_adapter *adapter,
                return;
 
        INIT_DELAYED_WORK(&adapter->fw_work, func);
-       queue_delayed_work(qlcnic_wq, &adapter->fw_work,
-                                       round_jiffies_relative(delay));
+       queue_delayed_work(adapter->qlcnic_wq, &adapter->fw_work,
+                               round_jiffies_relative(delay));
 }
 
-static void
-qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
+void
+qlcnic_cancel_idc_work(struct qlcnic_adapter *adapter)
 {
        while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
                msleep(10);
 
-       if (!adapter->fw_work.work.func)
-               return;
-
        cancel_delayed_work_sync(&adapter->fw_work);
 }
 
@@ -3114,8 +2906,8 @@ qlcnic_attach_work(struct work_struct *work)
        struct net_device *netdev = adapter->netdev;
        u32 npar_state;
 
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC) {
-               npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) {
+               npar_state = QLCRD(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
                if (adapter->fw_wait_cnt++ > QLCNIC_DEV_NPAR_OPER_TIMEO)
                        qlcnic_clr_all_drv_state(adapter, 0);
                else if (npar_state != QLCNIC_DEV_NPAR_OPER)
@@ -3148,6 +2940,7 @@ done:
 static int
 qlcnic_check_health(struct qlcnic_adapter *adapter)
 {
+       int err;
        u32 state = 0, heartbeat;
        u32 peg_status;
 
@@ -3155,23 +2948,23 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
                goto detach;
 
        if (adapter->need_fw_reset)
-               qlcnic_dev_request_reset(adapter);
+               adapter->nic_ops->request_reset(adapter, 0);
 
-       state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       state = QLCRD(adapter, QLCNIC_CRB_DEV_STATE);
        if (state == QLCNIC_DEV_NEED_RESET) {
                qlcnic_set_npar_non_operational(adapter);
                adapter->need_fw_reset = 1;
        } else if (state == QLCNIC_DEV_NEED_QUISCENT)
                goto detach;
 
-       heartbeat = QLCRD32(adapter, QLCNIC_PEG_ALIVE_COUNTER);
+       heartbeat = QLCRD(adapter, QLCNIC_PEG_ALIVE_COUNTER);
        if (heartbeat != adapter->heartbeat) {
                adapter->heartbeat = heartbeat;
                adapter->fw_fail_cnt = 0;
                if (adapter->need_fw_reset)
                        goto detach;
 
-               if (adapter->reset_context && auto_fw_reset) {
+               if (adapter->ahw->reset_context && auto_fw_reset) {
                        qlcnic_reset_hw_context(adapter);
                        adapter->netdev->trans_start = jiffies;
                }
@@ -3184,25 +2977,25 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
 
        adapter->flags |= QLCNIC_FW_HANG;
 
-       qlcnic_dev_request_reset(adapter);
+       adapter->nic_ops->request_reset(adapter, 0);
 
        if (auto_fw_reset)
                clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state);
 
        dev_err(&adapter->pdev->dev, "firmware hang detected\n");
+       peg_status = QLCRD(adapter, QLCNIC_PEG_HALT_STATUS1);
        dev_err(&adapter->pdev->dev, "Dumping hw/fw registers\n"
                        "PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
                        "PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
                        "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
                        "PEG_NET_4_PC: 0x%x\n",
-                       QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1),
-                       QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS2),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
-       peg_status = QLCRD32(adapter, QLCNIC_PEG_HALT_STATUS1);
+                       peg_status,
+                       QLCRD(adapter, QLCNIC_PEG_HALT_STATUS2),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err));
        if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
                dev_err(&adapter->pdev->dev,
                        "Firmware aborted with error code 0x00006700. "
@@ -3267,6 +3060,7 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
        int err, first_func;
        struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
        struct net_device *netdev = adapter->netdev;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        pdev->error_state = pci_channel_io_normal;
 
@@ -3280,23 +3074,36 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
 
        first_func = qlcnic_is_first_func(pdev);
 
-       if (qlcnic_api_lock(adapter))
+       if (ahw->hw_ops->api_lock(adapter))
                return -EINVAL;
 
-       if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
+       if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC && first_func) {
                adapter->need_fw_reset = 1;
                set_bit(__QLCNIC_START_FW, &adapter->state);
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+               QLCWR(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
                QLCDB(adapter, DRV, "Restarting fw\n");
        }
-       qlcnic_api_unlock(adapter);
+       ahw->hw_ops->api_unlock(adapter);
 
        err = adapter->nic_ops->start_firmware(adapter);
        if (err)
                return err;
 
        qlcnic_clr_drv_state(adapter);
-       qlcnic_setup_intr(adapter);
+       kfree(adapter->msix_entries);
+       adapter->msix_entries = NULL;
+       err = ahw->hw_ops->setup_intr(adapter, 0);
+
+       if (QLCNIC_IS_83XX(adapter)) {
+               qlcnic_83xx_register_nic_idc_func(adapter, 1);
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err) {
+                       netdev_err(netdev, "failed to setup mbx interrupt\n");
+                       qlcnic_clr_all_drv_state(adapter, 1);
+                       clear_bit(__QLCNIC_AER, &adapter->state);
+                       goto done;
+               }
+       }
 
        if (netif_running(netdev)) {
                err = qlcnic_attach(adapter);
@@ -3338,6 +3145,14 @@ static pci_ers_result_t qlcnic_io_error_detected(struct pci_dev *pdev,
        if (netif_running(netdev))
                qlcnic_down(adapter, netdev);
 
+       if (QLCNIC_IS_83XX(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+               qlcnic_83xx_register_nic_idc_func(adapter, 0);
+               cancel_delayed_work_sync(&adapter->idc_aen_work);
+       }
+
        qlcnic_detach(adapter);
        qlcnic_teardown_intr(adapter);
 
@@ -3361,7 +3176,7 @@ static void qlcnic_io_resume(struct pci_dev *pdev)
 
        pci_cleanup_aer_uncorrect_error_status(pdev);
 
-       if (QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
+       if (QLCRD(adapter, QLCNIC_CRB_DEV_STATE) == QLCNIC_DEV_READY &&
            test_and_clear_bit(__QLCNIC_AER, &adapter->state))
                qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
                                                FW_POLL_DELAY);
@@ -3407,93 +3222,16 @@ qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
        return -EOPNOTSUPP;
 }
 
-static ssize_t
-qlcnic_store_bridged_mode(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t len)
+int qlcnic_validate_max_rss(u8 max_hw, u8 val)
 {
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       unsigned long new;
-       int ret = -EINVAL;
-
-       if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
-               goto err_out;
+       u32 max_allowed;
 
-       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
-               goto err_out;
-
-       if (strict_strtoul(buf, 2, &new))
-               goto err_out;
-
-       if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
-               ret = len;
-
-err_out:
-       return ret;
-}
-
-static ssize_t
-qlcnic_show_bridged_mode(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       int bridged_mode = 0;
+       max_allowed = rounddown_pow_of_two(
+                               min_t(int, max_hw, num_online_cpus()));
 
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
-               bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
+       if ((val > max_allowed) || (val <  1) || !is_power_of_2(val))
+               return max_allowed;
 
-       return sprintf(buf, "%d\n", bridged_mode);
-}
-
-static struct device_attribute dev_attr_bridged_mode = {
-       .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
-       .show = qlcnic_show_bridged_mode,
-       .store = qlcnic_store_bridged_mode,
-};
-
-static ssize_t
-qlcnic_store_diag_mode(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t len)
-{
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       unsigned long new;
-
-       if (strict_strtoul(buf, 2, &new))
-               return -EINVAL;
-
-       if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
-               adapter->flags ^= QLCNIC_DIAG_ENABLED;
-
-       return len;
-}
-
-static ssize_t
-qlcnic_show_diag_mode(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%d\n",
-                       !!(adapter->flags & QLCNIC_DIAG_ENABLED));
-}
-
-static struct device_attribute dev_attr_diag_mode = {
-       .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
-       .show = qlcnic_show_diag_mode,
-       .store = qlcnic_store_diag_mode,
-};
-
-int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
-{
-       if (!use_msi_x && !use_msi) {
-               netdev_info(netdev, "no msix or msi support, hence no rss\n");
-               return -EINVAL;
-       }
-
-       if ((val > max_hw) || (val <  2) || !is_power_of_2(val)) {
-               netdev_info(netdev, "rss_ring valid range [2 - %x] in "
-                       " powers of 2\n", max_hw);
-               return -EINVAL;
-       }
        return 0;
 
 }
@@ -3509,12 +3247,26 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
        netif_device_detach(netdev);
        if (netif_running(netdev))
                __qlcnic_down(adapter, netdev);
+
+       if (QLCNIC_IS_83XX(adapter)) {
+               if (adapter->flags & QLCNIC_MSIX_ENABLED)
+                       qlcnic_83xx_config_intrpt(adapter, 0);
+               qlcnic_83xx_free_mbx_intr(adapter);
+       }
+
        qlcnic_detach(adapter);
        qlcnic_teardown_intr(adapter);
 
-       if (qlcnic_enable_msix(adapter, data)) {
-               netdev_info(netdev, "failed setting max_rss; rss disabled\n");
-               qlcnic_enable_msi_legacy(adapter);
+       err = adapter->ahw->hw_ops->setup_intr(adapter, data);
+       if (err)
+               netdev_err(netdev, "failed setting max_rss; rss disabled\n");
+
+       if (QLCNIC_IS_83XX(adapter)) {
+               err = qlcnic_83xx_setup_mbx_intr(adapter);
+               if (err) {
+                       netdev_err(netdev, "failed to setup mbx interrupt\n");
+                       goto done;
+               }
        }
 
        if (netif_running(netdev)) {
@@ -3532,864 +3284,11 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
        return err;
 }
 
-static int
-qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
-                       u8 *rate)
-{
-       *rate = LSB(beacon);
-       *state = MSB(beacon);
-
-       QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state);
-
-       if (!*state) {
-               *rate = __QLCNIC_MAX_LED_RATE;
-               return 0;
-       } else if (*state > __QLCNIC_MAX_LED_STATE)
-               return -EINVAL;
-
-       if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
-               return -EINVAL;
-
-       return 0;
-}
-
-static ssize_t
-qlcnic_store_beacon(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t len)
-{
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       int max_sds_rings = adapter->max_sds_rings;
-       u16 beacon;
-       u8 b_state, b_rate;
-       int err;
-
-       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
-               dev_warn(dev, "LED test not supported for non "
-                               "privilege function\n");
-               return -EOPNOTSUPP;
-       }
-
-       if (len != sizeof(u16))
-               return QL_STATUS_INVALID_PARAM;
-
-       memcpy(&beacon, buf, sizeof(u16));
-       err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
-       if (err)
-               return err;
-
-       if (adapter->ahw->beacon_state == b_state)
-               return len;
-
-       rtnl_lock();
-
-       if (!adapter->ahw->beacon_state)
-               if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
-                       rtnl_unlock();
-                       return -EBUSY;
-               }
-
-       if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
-               err = -EIO;
-               goto out;
-       }
-
-       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
-               err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
-               if (err)
-                       goto out;
-               set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
-       }
-
-       err = qlcnic_config_led(adapter, b_state, b_rate);
-
-       if (!err) {
-               err = len;
-               adapter->ahw->beacon_state = b_state;
-       }
-
-       if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
-               qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
-
- out:
-       if (!adapter->ahw->beacon_state)
-               clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
-       rtnl_unlock();
-
-       return err;
-}
-
-static ssize_t
-qlcnic_show_beacon(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%d\n", adapter->ahw->beacon_state);
-}
-
-static struct device_attribute dev_attr_beacon = {
-       .attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)},
-       .show = qlcnic_show_beacon,
-       .store = qlcnic_store_beacon,
-};
-
-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 (offset < QLCNIC_PCI_CRBSPACE) {
-               if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
-                                       QLCNIC_PCI_CAMQM_END))
-                       crb_size = 8;
-               else
-                       return -EINVAL;
-       }
-
-       if ((size != crb_size) || (offset & (crb_size-1)))
-               return  -EINVAL;
-
-       return 0;
-}
-
-static ssize_t
-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;
-
-       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 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;
-
-       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;
-}
-
-static int
-qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
-               loff_t offset, size_t size)
-{
-       if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
-               return -EIO;
-
-       if ((size != 8) || (offset & 0x7))
-               return  -EIO;
-
-       return 0;
-}
-
-static ssize_t
-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);
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u64 data;
-       int ret;
-
-       ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
-       if (ret != 0)
-               return ret;
-
-       if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
-               return -EIO;
-
-       memcpy(buf, &data, size);
-
-       return size;
-}
-
-static ssize_t
-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);
-       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u64 data;
-       int ret;
-
-       ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
-       if (ret != 0)
-               return ret;
-
-       memcpy(&data, buf, size);
-
-       if (qlcnic_pci_mem_write_2M(adapter, offset, data))
-               return -EIO;
-
-       return size;
-}
-
-static struct bin_attribute bin_attr_crb = {
-       .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_read_crb,
-       .write = qlcnic_sysfs_write_crb,
-};
-
-static struct bin_attribute bin_attr_mem = {
-       .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_read_mem,
-       .write = qlcnic_sysfs_write_mem,
-};
-
-static int
-validate_pm_config(struct qlcnic_adapter *adapter,
-                       struct qlcnic_pm_func_cfg *pm_cfg, int count)
-{
-
-       u8 src_pci_func, s_esw_id, d_esw_id;
-       u8 dest_pci_func;
-       int i;
-
-       for (i = 0; i < count; i++) {
-               src_pci_func = pm_cfg[i].pci_func;
-               dest_pci_func = pm_cfg[i].dest_npar;
-               if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
-                               || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
-                       return QL_STATUS_INVALID_PARAM;
-
-               if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
-                       return QL_STATUS_INVALID_PARAM;
-
-               if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
-                       return QL_STATUS_INVALID_PARAM;
-
-               s_esw_id = adapter->npars[src_pci_func].phy_port;
-               d_esw_id = adapter->npars[dest_pci_func].phy_port;
-
-               if (s_esw_id != d_esw_id)
-                       return QL_STATUS_INVALID_PARAM;
-
-       }
-       return 0;
-
-}
-
-static ssize_t
-qlcnic_sysfs_write_pm_config(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);
-       struct qlcnic_pm_func_cfg *pm_cfg;
-       u32 id, action, pci_func;
-       int count, rem, i, ret;
-
-       count   = size / sizeof(struct qlcnic_pm_func_cfg);
-       rem     = size % sizeof(struct qlcnic_pm_func_cfg);
-       if (rem)
-               return QL_STATUS_INVALID_PARAM;
-
-       pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
-
-       ret = validate_pm_config(adapter, pm_cfg, count);
-       if (ret)
-               return ret;
-       for (i = 0; i < count; i++) {
-               pci_func = pm_cfg[i].pci_func;
-               action = !!pm_cfg[i].action;
-               id = adapter->npars[pci_func].phy_port;
-               ret = qlcnic_config_port_mirroring(adapter, id,
-                                               action, pci_func);
-               if (ret)
-                       return ret;
-       }
-
-       for (i = 0; i < count; i++) {
-               pci_func = pm_cfg[i].pci_func;
-               id = adapter->npars[pci_func].phy_port;
-               adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
-               adapter->npars[pci_func].dest_npar = id;
-       }
-       return size;
-}
-
-static ssize_t
-qlcnic_sysfs_read_pm_config(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);
-       struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
-       int i;
-
-       if (size != sizeof(pm_cfg))
-               return QL_STATUS_INVALID_PARAM;
-
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-                       continue;
-               pm_cfg[i].action = adapter->npars[i].enable_pm;
-               pm_cfg[i].dest_npar = 0;
-               pm_cfg[i].pci_func = i;
-       }
-       memcpy(buf, &pm_cfg, size);
-
-       return size;
-}
-
-static int
-validate_esw_config(struct qlcnic_adapter *adapter,
-       struct qlcnic_esw_func_cfg *esw_cfg, int count)
-{
-       u32 op_mode;
-       u8 pci_func;
-       int i;
-
-       op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
-
-       for (i = 0; i < count; i++) {
-               pci_func = esw_cfg[i].pci_func;
-               if (pci_func >= QLCNIC_MAX_PCI_FUNC)
-                       return QL_STATUS_INVALID_PARAM;
-
-               if (adapter->op_mode == QLCNIC_MGMT_FUNC)
-                       if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
-                               return QL_STATUS_INVALID_PARAM;
-
-               switch (esw_cfg[i].op_mode) {
-               case QLCNIC_PORT_DEFAULTS:
-                       if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
-                                               QLCNIC_NON_PRIV_FUNC) {
-                               if (esw_cfg[i].mac_anti_spoof != 0)
-                                       return QL_STATUS_INVALID_PARAM;
-                               if (esw_cfg[i].mac_override != 1)
-                                       return QL_STATUS_INVALID_PARAM;
-                               if (esw_cfg[i].promisc_mode != 1)
-                                       return QL_STATUS_INVALID_PARAM;
-                       }
-                       break;
-               case QLCNIC_ADD_VLAN:
-                       if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
-                               return QL_STATUS_INVALID_PARAM;
-                       if (!esw_cfg[i].op_type)
-                               return QL_STATUS_INVALID_PARAM;
-                       break;
-               case QLCNIC_DEL_VLAN:
-                       if (!esw_cfg[i].op_type)
-                               return QL_STATUS_INVALID_PARAM;
-                       break;
-               default:
-                       return QL_STATUS_INVALID_PARAM;
-               }
-       }
-       return 0;
-}
-
-static ssize_t
-qlcnic_sysfs_write_esw_config(struct file *file, 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);
-       struct qlcnic_esw_func_cfg *esw_cfg;
-       struct qlcnic_npar_info *npar;
-       int count, rem, i, ret;
-       u8 pci_func, op_mode = 0;
-
-       count   = size / sizeof(struct qlcnic_esw_func_cfg);
-       rem     = size % sizeof(struct qlcnic_esw_func_cfg);
-       if (rem)
-               return QL_STATUS_INVALID_PARAM;
-
-       esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
-       ret = validate_esw_config(adapter, esw_cfg, count);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < count; i++) {
-               if (adapter->op_mode == QLCNIC_MGMT_FUNC)
-                       if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
-                               return QL_STATUS_INVALID_PARAM;
-
-               if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
-                       continue;
-
-               op_mode = esw_cfg[i].op_mode;
-               qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
-               esw_cfg[i].op_mode = op_mode;
-               esw_cfg[i].pci_func = adapter->ahw->pci_func;
-
-               switch (esw_cfg[i].op_mode) {
-               case QLCNIC_PORT_DEFAULTS:
-                       qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
-                       break;
-               case QLCNIC_ADD_VLAN:
-                       qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
-                       break;
-               case QLCNIC_DEL_VLAN:
-                       esw_cfg[i].vlan_id = 0;
-                       qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
-                       break;
-               }
-       }
-
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
-               goto out;
-
-       for (i = 0; i < count; i++) {
-               pci_func = esw_cfg[i].pci_func;
-               npar = &adapter->npars[pci_func];
-               switch (esw_cfg[i].op_mode) {
-               case QLCNIC_PORT_DEFAULTS:
-                       npar->promisc_mode = esw_cfg[i].promisc_mode;
-                       npar->mac_override = esw_cfg[i].mac_override;
-                       npar->offload_flags = esw_cfg[i].offload_flags;
-                       npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
-                       npar->discard_tagged = esw_cfg[i].discard_tagged;
-                       break;
-               case QLCNIC_ADD_VLAN:
-                       npar->pvid = esw_cfg[i].vlan_id;
-                       break;
-               case QLCNIC_DEL_VLAN:
-                       npar->pvid = 0;
-                       break;
-               }
-       }
-out:
-       return size;
-}
-
-static ssize_t
-qlcnic_sysfs_read_esw_config(struct file *file, 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);
-       struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
-       u8 i;
-
-       if (size != sizeof(esw_cfg))
-               return QL_STATUS_INVALID_PARAM;
-
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-                       continue;
-               esw_cfg[i].pci_func = i;
-               if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
-                       return QL_STATUS_INVALID_PARAM;
-       }
-       memcpy(buf, &esw_cfg, size);
-
-       return size;
-}
-
-static int
-validate_npar_config(struct qlcnic_adapter *adapter,
-                               struct qlcnic_npar_func_cfg *np_cfg, int count)
-{
-       u8 pci_func, i;
-
-       for (i = 0; i < count; i++) {
-               pci_func = np_cfg[i].pci_func;
-               if (pci_func >= QLCNIC_MAX_PCI_FUNC)
-                       return QL_STATUS_INVALID_PARAM;
-
-               if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
-                       return QL_STATUS_INVALID_PARAM;
-
-               if (!IS_VALID_BW(np_cfg[i].min_bw) ||
-                   !IS_VALID_BW(np_cfg[i].max_bw))
-                       return QL_STATUS_INVALID_PARAM;
-       }
-       return 0;
-}
-
-static ssize_t
-qlcnic_sysfs_write_npar_config(struct file *file, 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);
-       struct qlcnic_info nic_info;
-       struct qlcnic_npar_func_cfg *np_cfg;
-       int i, count, rem, ret;
-       u8 pci_func;
-
-       count   = size / sizeof(struct qlcnic_npar_func_cfg);
-       rem     = size % sizeof(struct qlcnic_npar_func_cfg);
-       if (rem)
-               return QL_STATUS_INVALID_PARAM;
-
-       np_cfg = (struct qlcnic_npar_func_cfg *) buf;
-       ret = validate_npar_config(adapter, np_cfg, count);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < count ; i++) {
-               pci_func = np_cfg[i].pci_func;
-               ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
-               if (ret)
-                       return ret;
-               nic_info.pci_func = pci_func;
-               nic_info.min_tx_bw = np_cfg[i].min_bw;
-               nic_info.max_tx_bw = np_cfg[i].max_bw;
-               ret = qlcnic_set_nic_info(adapter, &nic_info);
-               if (ret)
-                       return ret;
-               adapter->npars[i].min_bw = nic_info.min_tx_bw;
-               adapter->npars[i].max_bw = nic_info.max_tx_bw;
-       }
-
-       return size;
-
-}
-static ssize_t
-qlcnic_sysfs_read_npar_config(struct file *file, 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);
-       struct qlcnic_info nic_info;
-       struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
-       int i, ret;
-
-       if (size != sizeof(np_cfg))
-               return QL_STATUS_INVALID_PARAM;
-
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
-               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
-                       continue;
-               ret = qlcnic_get_nic_info(adapter, &nic_info, i);
-               if (ret)
-                       return ret;
-
-               np_cfg[i].pci_func = i;
-               np_cfg[i].op_mode = (u8)nic_info.op_mode;
-               np_cfg[i].port_num = nic_info.phys_port;
-               np_cfg[i].fw_capab = nic_info.capabilities;
-               np_cfg[i].min_bw = nic_info.min_tx_bw ;
-               np_cfg[i].max_bw = nic_info.max_tx_bw;
-               np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
-               np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
-       }
-       memcpy(buf, &np_cfg, size);
-       return size;
-}
-
-static ssize_t
-qlcnic_sysfs_get_port_stats(struct file *file, 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);
-       struct qlcnic_esw_statistics port_stats;
-       int ret;
-
-       if (size != sizeof(struct qlcnic_esw_statistics))
-               return QL_STATUS_INVALID_PARAM;
-
-       if (offset >= QLCNIC_MAX_PCI_FUNC)
-               return QL_STATUS_INVALID_PARAM;
-
-       memset(&port_stats, 0, size);
-       ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
-                                                               &port_stats.rx);
-       if (ret)
-               return ret;
-
-       ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
-                                                               &port_stats.tx);
-       if (ret)
-               return ret;
-
-       memcpy(buf, &port_stats, size);
-       return size;
-}
-
-static ssize_t
-qlcnic_sysfs_get_esw_stats(struct file *file, 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);
-       struct qlcnic_esw_statistics esw_stats;
-       int ret;
-
-       if (size != sizeof(struct qlcnic_esw_statistics))
-               return QL_STATUS_INVALID_PARAM;
-
-       if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
-               return QL_STATUS_INVALID_PARAM;
-
-       memset(&esw_stats, 0, size);
-       ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
-                                                               &esw_stats.rx);
-       if (ret)
-               return ret;
-
-       ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
-                                                               &esw_stats.tx);
-       if (ret)
-               return ret;
-
-       memcpy(buf, &esw_stats, size);
-       return size;
-}
-
-static ssize_t
-qlcnic_sysfs_clear_esw_stats(struct file *file, 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);
-       int ret;
-
-       if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
-               return QL_STATUS_INVALID_PARAM;
-
-       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
-                                               QLCNIC_QUERY_RX_COUNTER);
-       if (ret)
-               return ret;
-
-       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
-                                               QLCNIC_QUERY_TX_COUNTER);
-       if (ret)
-               return ret;
-
-       return size;
-}
-
-static ssize_t
-qlcnic_sysfs_clear_port_stats(struct file *file, 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);
-       int ret;
-
-       if (offset >= QLCNIC_MAX_PCI_FUNC)
-               return QL_STATUS_INVALID_PARAM;
-
-       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
-                                               QLCNIC_QUERY_RX_COUNTER);
-       if (ret)
-               return ret;
-
-       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
-                                               QLCNIC_QUERY_TX_COUNTER);
-       if (ret)
-               return ret;
-
-       return size;
-}
-
-static ssize_t
-qlcnic_sysfs_read_pci_config(struct file *file, 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);
-       struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
-       struct qlcnic_pci_info *pci_info;
-       int i, ret;
-
-       if (size != sizeof(pci_cfg))
-               return QL_STATUS_INVALID_PARAM;
-
-       pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
-       if (!pci_info)
-               return -ENOMEM;
-
-       ret = qlcnic_get_pci_info(adapter, pci_info);
-       if (ret) {
-               kfree(pci_info);
-               return ret;
-       }
-
-       for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
-               pci_cfg[i].pci_func = pci_info[i].id;
-               pci_cfg[i].func_type = pci_info[i].type;
-               pci_cfg[i].port_num = pci_info[i].default_port;
-               pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
-               pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
-               memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
-       }
-       memcpy(buf, &pci_cfg, size);
-       kfree(pci_info);
-       return size;
-}
-static struct bin_attribute bin_attr_npar_config = {
-       .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_read_npar_config,
-       .write = qlcnic_sysfs_write_npar_config,
-};
-
-static struct bin_attribute bin_attr_pci_config = {
-       .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_read_pci_config,
-       .write = NULL,
-};
-
-static struct bin_attribute bin_attr_port_stats = {
-       .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_get_port_stats,
-       .write = qlcnic_sysfs_clear_port_stats,
-};
-
-static struct bin_attribute bin_attr_esw_stats = {
-       .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_get_esw_stats,
-       .write = qlcnic_sysfs_clear_esw_stats,
-};
-
-static struct bin_attribute bin_attr_esw_config = {
-       .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_read_esw_config,
-       .write = qlcnic_sysfs_write_esw_config,
-};
-
-static struct bin_attribute bin_attr_pm_config = {
-       .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
-       .size = 0,
-       .read = qlcnic_sysfs_read_pm_config,
-       .write = qlcnic_sysfs_write_pm_config,
-};
-
-static void
-qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
-{
-       struct device *dev = &adapter->pdev->dev;
-
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
-               if (device_create_file(dev, &dev_attr_bridged_mode))
-                       dev_warn(dev,
-                               "failed to create bridged_mode sysfs entry\n");
-}
-
-static void
-qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
-{
-       struct device *dev = &adapter->pdev->dev;
-
-       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
-               device_remove_file(dev, &dev_attr_bridged_mode);
-}
-
-static void
-qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
-{
-       struct device *dev = &adapter->pdev->dev;
-       u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-
-       if (device_create_bin_file(dev, &bin_attr_port_stats))
-               dev_info(dev, "failed to create port stats sysfs entry");
-
-       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
-               return;
-       if (device_create_file(dev, &dev_attr_diag_mode))
-               dev_info(dev, "failed to create diag_mode sysfs entry\n");
-       if (device_create_bin_file(dev, &bin_attr_crb))
-               dev_info(dev, "failed to create crb sysfs entry\n");
-       if (device_create_bin_file(dev, &bin_attr_mem))
-               dev_info(dev, "failed to create mem sysfs entry\n");
-
-       if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-               return;
-
-       if (device_create_bin_file(dev, &bin_attr_pci_config))
-               dev_info(dev, "failed to create pci config sysfs entry");
-       if (device_create_file(dev, &dev_attr_beacon))
-               dev_info(dev, "failed to create beacon sysfs entry");
-
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
-               return;
-       if (device_create_bin_file(dev, &bin_attr_esw_config))
-               dev_info(dev, "failed to create esw config sysfs entry");
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
-               return;
-       if (device_create_bin_file(dev, &bin_attr_npar_config))
-               dev_info(dev, "failed to create npar config sysfs entry");
-       if (device_create_bin_file(dev, &bin_attr_pm_config))
-               dev_info(dev, "failed to create pm config sysfs entry");
-       if (device_create_bin_file(dev, &bin_attr_esw_stats))
-               dev_info(dev, "failed to create eswitch stats sysfs entry");
-}
-
-static void
-qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
-{
-       struct device *dev = &adapter->pdev->dev;
-       u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-
-       device_remove_bin_file(dev, &bin_attr_port_stats);
-
-       if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
-               return;
-       device_remove_file(dev, &dev_attr_diag_mode);
-       device_remove_bin_file(dev, &bin_attr_crb);
-       device_remove_bin_file(dev, &bin_attr_mem);
-       if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-               return;
-       device_remove_bin_file(dev, &bin_attr_pci_config);
-       device_remove_file(dev, &dev_attr_beacon);
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
-               return;
-       device_remove_bin_file(dev, &bin_attr_esw_config);
-       if (adapter->op_mode != QLCNIC_MGMT_FUNC)
-               return;
-       device_remove_bin_file(dev, &bin_attr_npar_config);
-       device_remove_bin_file(dev, &bin_attr_pm_config);
-       device_remove_bin_file(dev, &bin_attr_esw_stats);
-}
-
 #ifdef CONFIG_INET
 
 #define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
 
-static void
+void
 qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
                        struct net_device *dev, unsigned long event)
 {
@@ -4402,12 +3301,12 @@ qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
        for_ifa(indev) {
                switch (event) {
                case NETDEV_UP:
-                       qlcnic_config_ipaddr(adapter,
-                                       ifa->ifa_address, QLCNIC_IP_UP);
+                       adapter->nic_ops->config_ipaddr(adapter,
+                                ifa->ifa_address, QLCNIC_IP_UP);
                        break;
                case NETDEV_DOWN:
-                       qlcnic_config_ipaddr(adapter,
-                                       ifa->ifa_address, QLCNIC_IP_DOWN);
+                       adapter->nic_ops->config_ipaddr(adapter,
+                                ifa->ifa_address, QLCNIC_IP_DOWN);
                        break;
                default:
                        break;
@@ -4417,7 +3316,7 @@ qlcnic_config_indev_addr(struct qlcnic_adapter *adapter,
        in_dev_put(indev);
 }
 
-static void
+void
 qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -4503,10 +3402,12 @@ recheck:
 
        switch (event) {
        case NETDEV_UP:
-               qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_UP);
+               adapter->nic_ops->config_ipaddr(adapter, ifa->ifa_address,
+                                                QLCNIC_IP_UP);
                break;
        case NETDEV_DOWN:
-               qlcnic_config_ipaddr(adapter, ifa->ifa_address, QLCNIC_IP_DOWN);
+               adapter->nic_ops->config_ipaddr(adapter, ifa->ifa_address,
+                                                QLCNIC_IP_DOWN);
                break;
        default:
                break;
@@ -4524,11 +3425,11 @@ static struct notifier_block qlcnic_inetaddr_cb = {
        .notifier_call = qlcnic_inetaddr_event,
 };
 #else
-static void
+void
 qlcnic_restore_indev_addr(struct net_device *dev, unsigned long event)
 { }
 #endif
-static const struct pci_error_handlers qlcnic_err_handler = {
+static struct pci_error_handlers qlcnic_err_handler = {
        .error_detected = qlcnic_io_error_detected,
        .slot_reset = qlcnic_io_slot_reset,
        .resume = qlcnic_io_resume,
@@ -4554,12 +3455,6 @@ static int __init qlcnic_init_module(void)
 
        printk(KERN_INFO "%s\n", qlcnic_driver_string);
 
-       qlcnic_wq = create_singlethread_workqueue("qlcnic");
-       if (qlcnic_wq == NULL) {
-               printk(KERN_ERR "qlcnic: cannot create workqueue\n");
-               return -ENOMEM;
-       }
-
 #ifdef CONFIG_INET
        register_netdevice_notifier(&qlcnic_netdev_cb);
        register_inetaddr_notifier(&qlcnic_inetaddr_cb);
@@ -4571,7 +3466,6 @@ static int __init qlcnic_init_module(void)
                unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
                unregister_netdevice_notifier(&qlcnic_netdev_cb);
 #endif
-               destroy_workqueue(qlcnic_wq);
        }
 
        return ret;
@@ -4581,14 +3475,12 @@ module_init(qlcnic_init_module);
 
 static void __exit qlcnic_exit_module(void)
 {
-
        pci_unregister_driver(&qlcnic_driver);
 
 #ifdef CONFIG_INET
        unregister_inetaddr_notifier(&qlcnic_inetaddr_cb);
        unregister_netdevice_notifier(&qlcnic_netdev_cb);
 #endif
-       destroy_workqueue(qlcnic_wq);
 }
 
 module_exit(qlcnic_exit_module);
diff --git a/drivers/net/qlcnic/qlcnic_minidump.c b/drivers/net/qlcnic/qlcnic_minidump.c
new file mode 100644 (file)
index 0000000..3c9019f
--- /dev/null
@@ -0,0 +1,842 @@
+
+#include "qlcnic.h"
+#include "qlcnic_hdr.h"
+#include "qlcnic_83xx.h"
+#include "qlcnic_hw.h"
+
+#include <net/ip.h>
+
+#define QLC_83XX_MINIDUMP_FLASH                        0x520000
+#define QLC_83XX_OCM_INDEX                     3
+#define QLC_83XX_PCI_INDEX                     0
+
+static u32
+qlcnic_dump_crb(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+               u32 *buffer)
+{
+       int i;
+       u32 addr, data;
+       struct __crb *crb = &entry->region.crb;
+
+       addr = crb->addr;
+
+       for (i = 0; i < crb->no_ops; i++) {
+               data = qlcnic_ind_rd(adapter, addr);
+               *buffer++ = cpu_to_le32(addr);
+               *buffer++ = cpu_to_le32(data);
+               addr += crb->stride;
+       }
+       return crb->no_ops * 2 * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       int i, k, timeout = 0;
+       u32 addr, data;
+       u8 opcode, no_ops;
+       struct __ctrl *ctr = &entry->region.ctrl;
+       struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
+
+       addr = ctr->addr;
+       no_ops = ctr->no_ops;
+
+       for (i = 0; i < no_ops; i++) {
+               k = 0;
+               opcode = 0;
+               for (k = 0; k < 8; k++) {
+                       if (!(ctr->opcode & (1 << k)))
+                               continue;
+                       switch (1 << k) {
+                       case QLCNIC_DUMP_WCRB:
+                               qlcnic_ind_wr(adapter, addr, ctr->val1);
+                               break;
+                       case QLCNIC_DUMP_RWCRB:
+                               data = qlcnic_ind_rd(adapter, addr);
+                               qlcnic_ind_wr(adapter, addr, data);
+                               break;
+                       case QLCNIC_DUMP_ANDCRB:
+                               data = qlcnic_ind_rd(adapter, addr);
+                               qlcnic_ind_wr(adapter, addr,
+                                               (data & ctr->val2));
+                               break;
+                       case QLCNIC_DUMP_ORCRB:
+                               data = qlcnic_ind_rd(adapter, addr);
+                               qlcnic_ind_wr(adapter, addr,
+                                               (data | ctr->val3));
+                               break;
+                       case QLCNIC_DUMP_POLLCRB:
+                               while (timeout <= ctr->timeout) {
+                                       data = qlcnic_ind_rd(adapter, addr);
+                                       if ((data & ctr->val2) == ctr->val1)
+                                               break;
+                                       msleep(1);
+                                       timeout++;
+                               }
+                               if (timeout > ctr->timeout) {
+                                       dev_info(&adapter->pdev->dev,
+                                       "Timed out, aborting poll CRB\n");
+                                       return 0;
+                               }
+                               break;
+                       case QLCNIC_DUMP_RD_SAVE:
+                               if (ctr->index_a)
+                                       addr = t_hdr->saved_state[ctr->index_a];
+                               data = qlcnic_ind_rd(adapter, addr);
+                               t_hdr->saved_state[ctr->index_v] = data;
+                               break;
+                       case QLCNIC_DUMP_WRT_SAVED:
+                               if (ctr->index_v)
+                                       data = t_hdr->saved_state[ctr->index_v];
+                               else
+                                       data = ctr->val1;
+                               if (ctr->index_a)
+                                       addr = t_hdr->saved_state[ctr->index_a];
+                               qlcnic_ind_wr(adapter, addr, data);
+                               break;
+                       case QLCNIC_DUMP_MOD_SAVE_ST:
+                               data = t_hdr->saved_state[ctr->index_v];
+                               data <<= ctr->shl_val;
+                               data >>= ctr->shr_val;
+                               if (ctr->val2)
+                                       data &= ctr->val2;
+                               data |= ctr->val3;
+                               data += ctr->val1;
+                               t_hdr->saved_state[ctr->index_v] = data;
+                               break;
+                       default:
+                               dev_info(&adapter->pdev->dev,
+                                       "Unknown opcode\n");
+                               break;
+                       }
+               }
+               addr += ctr->stride;
+       }
+       return 0;
+}
+
+static u32
+qlcnic_dump_mux(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+       u32 *buffer)
+{
+       int loop;
+       u32 val, data = 0;
+       struct __mux *mux = &entry->region.mux;
+
+       val = mux->val;
+       for (loop = 0; loop < mux->no_ops; loop++) {
+               qlcnic_ind_wr(adapter, mux->addr, val);
+               data = qlcnic_ind_rd(adapter, mux->read_addr);
+               *buffer++ = cpu_to_le32(val);
+               *buffer++ = cpu_to_le32(data);
+               val += mux->val_stride;
+       }
+       return 2 * mux->no_ops * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+       u32 *buffer)
+{
+       int i, loop;
+       u32 cnt, addr, data, que_id = 0;
+       struct __queue *que = &entry->region.que;
+
+       addr = que->read_addr;
+       cnt = que->read_addr_cnt;
+
+       for (loop = 0; loop < que->no_ops; loop++) {
+               qlcnic_ind_wr(adapter, que->sel_addr, que_id);
+               addr = que->read_addr;
+               for (i = 0; i < cnt; i++) {
+                       data = qlcnic_ind_rd(adapter, addr);
+                       *buffer++ = cpu_to_le32(data);
+                       addr += que->read_addr_stride;
+               }
+               que_id += que->stride;
+       }
+       return que->no_ops * cnt * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_ocm(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+       u32 *buffer)
+{
+       int i;
+       u32 data;
+       void __iomem *addr;
+       struct __ocm *ocm = &entry->region.ocm;
+
+       addr = adapter->ahw->pci_base0 + ocm->read_addr;
+       for (i = 0; i < ocm->no_ops; i++) {
+               data = readl(addr);
+               *buffer++ = cpu_to_le32(data);
+               addr += ocm->read_addr_stride;
+       }
+       return ocm->no_ops * sizeof(u32);
+}
+
+static u32
+qlcnic_read_rom(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+       u32 *buffer)
+{
+       int i, count = 0;
+       u32 fl_addr, size, val, lck_val, addr;
+       struct __mem *rom = &entry->region.mem;
+
+       fl_addr = rom->addr;
+       size = rom->size/4;
+lock_try:
+       lck_val = QLCRD(adapter, QLCNIC_FLASH_LOCK);
+       if (!lck_val && count < MAX_CTL_CHECK) {
+               msleep(10);
+               count++;
+               goto lock_try;
+       }
+       QLCWR(adapter, QLCNIC_FLASH_LOCK_OWNER, adapter->ahw->pci_func);
+       for (i = 0; i < size; i++) {
+               addr = fl_addr & 0xFFFF0000;
+               qlcnic_ind_wr(adapter, FLASH_ROM_WINDOW, addr);
+               addr = LSW(fl_addr) + FLASH_ROM_DATA;
+               val = qlcnic_ind_rd(adapter, addr);
+               fl_addr += 4;
+               *buffer++ = cpu_to_le32(val);
+       }
+       QLCRD(adapter, QLCNIC_FLASH_UNLOCK);
+       return rom->size;
+}
+
+static u32
+qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       int i;
+       u32 cnt, val, data, addr;
+       struct __cache *l1 = &entry->region.cache;
+
+       val = l1->init_tag_val;
+
+       for (i = 0; i < l1->no_ops; i++) {
+               qlcnic_ind_wr(adapter, l1->addr, val);
+               qlcnic_ind_wr(adapter, l1->ctrl_addr, LSW(l1->ctrl_val));
+               addr = l1->read_addr;
+               cnt = l1->read_addr_num;
+               while (cnt) {
+                       data = qlcnic_ind_rd(adapter, addr);
+                       *buffer++ = cpu_to_le32(data);
+                       addr += l1->read_addr_stride;
+                       cnt--;
+               }
+               val += l1->stride;
+       }
+       return l1->no_ops * l1->read_addr_num * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       int i;
+       u32 cnt, val, data, addr;
+       u8 poll_mask, poll_to, time_out = 0;
+       struct __cache *l2 = &entry->region.cache;
+
+       val = l2->init_tag_val;
+       poll_mask = LSB(MSW(l2->ctrl_val));
+       poll_to = MSB(MSW(l2->ctrl_val));
+
+       for (i = 0; i < l2->no_ops; i++) {
+               qlcnic_ind_wr(adapter, l2->addr, val);
+               if (LSW(l2->ctrl_val))
+                       qlcnic_ind_wr(adapter, l2->ctrl_addr,
+                                               LSW(l2->ctrl_val));
+               if (!poll_mask)
+                       goto skip_poll;
+               do {
+                       data = qlcnic_ind_rd(adapter, l2->ctrl_addr);
+                       if (!(data & poll_mask))
+                               break;
+                       msleep(1);
+                       time_out++;
+               } while (time_out <= poll_to);
+
+               if (time_out > poll_to) {
+                       dev_err(&adapter->pdev->dev,
+                               "Timeout exceeded in %s, aborting dump\n",
+                               __func__);
+                       return 0;
+               }
+skip_poll:
+               addr = l2->read_addr;
+               cnt = l2->read_addr_num;
+               while (cnt) {
+                       data = qlcnic_ind_rd(adapter, addr);
+                       *buffer++ = cpu_to_le32(data);
+                       addr += l2->read_addr_stride;
+                       cnt--;
+               }
+               val += l2->stride;
+       }
+       return l2->no_ops * l2->read_addr_num * sizeof(u32);
+}
+
+static u32
+qlcnic_read_memory(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       u32 addr, data, test, ret = 0;
+       int i, reg_read;
+       struct __mem *mem = &entry->region.mem;
+
+       reg_read = mem->size;
+       addr = mem->addr;
+       /* check for data size of multiple of 16 and 16 byte alignment */
+       if ((addr & 0xf) || (reg_read%16)) {
+               dev_info(&adapter->pdev->dev,
+                       "Unaligned memory addr:0x%x size:0x%x\n",
+                       addr, reg_read);
+               return 0;
+       }
+
+       mutex_lock(&adapter->ahw->mem_lock);
+
+       while (reg_read != 0) {
+               qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_LO, addr);
+               qlcnic_ind_wr(adapter, QLCNIC_MS_ADDR_HI, 0);
+               qlcnic_ind_wr(adapter, QLCNIC_MS_CTRL, QLC_TA_START_ENABLE);
+
+               for (i = 0; i < MAX_CTL_CHECK; i++) {
+                       test = qlcnic_ind_rd(adapter, QLCNIC_MS_CTRL);
+                       if (!(test & TA_CTL_BUSY))
+                               break;
+               }
+               if (i == MAX_CTL_CHECK) {
+                       if (printk_ratelimit()) {
+                               dev_err(&adapter->pdev->dev,
+                                       "failed to read through agent\n");
+                               ret = 0;
+                               goto out;
+                       }
+               }
+               for (i = 0; i < 4; i++) {
+                       data = qlcnic_ind_rd(adapter, QLCNIC_MS_READ_DATA[i]);
+                       *buffer++ = cpu_to_le32(data);
+               }
+               addr += 16;
+               reg_read -= 16;
+               ret += 16;
+       }
+out:
+       mutex_unlock(&adapter->ahw->mem_lock);
+       return mem->size;
+}
+
+static u32
+qlcnic_dump_nop(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+       return 0;
+}
+
+/* Walk the template and collect dump for each entry in the dump template */
+static int
+qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
+       u32 size)
+{
+       int ret = 1;
+       if (size != entry->hdr.cap_size) {
+               dev_info(dev,
+               "Invalid entry, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+               entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
+               ret = 0;
+       }
+       return ret;
+}
+
+static u32
+qlcnic_read_pollrdmwr(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       struct __pollrdmwr *poll = &entry->region.pollrdmwr;
+       u32 data, wait_count, poll_wait, temp;
+
+       poll_wait = poll->poll_wait;
+
+       qlcnic_ind_wr(adapter, poll->addr1, poll->val1);
+       wait_count = 0;
+
+       while (wait_count < poll_wait) {
+               data = qlcnic_ind_rd(adapter, poll->addr1);
+               if ((data & poll->poll_mask) != 0)
+                       break;
+               wait_count++;
+       }
+
+       if (wait_count == poll_wait) {
+               dev_err(&adapter->pdev->dev,
+                       "Timeout exceeded in %s, aborting dump\n",
+                       __func__);
+               return 0;
+       }
+
+       data = qlcnic_ind_rd(adapter, poll->addr2) & poll->mod_mask;
+       qlcnic_ind_wr(adapter, poll->addr2, data);
+       qlcnic_ind_wr(adapter, poll->addr1, poll->val2);
+       wait_count = 0;
+
+       while (wait_count < poll_wait) {
+               temp = qlcnic_ind_rd(adapter, poll->addr1);
+               if ((temp & poll->poll_mask) != 0)
+                       break;
+               wait_count++;
+       }
+
+       *buffer++ = cpu_to_le32(poll->addr2);
+       *buffer++ = cpu_to_le32(data);
+
+       return 2 * sizeof(u32);
+
+}
+
+static u32
+qlcnic_read_pollrd(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       struct __pollrd *pollrd = &entry->region.pollrd;
+       u32 data, wait_count, poll_wait, sel_val;
+       int i;
+
+       poll_wait = pollrd->poll_wait;
+       sel_val = pollrd->sel_val;
+
+       for (i = 0; i < pollrd->no_ops; i++)  {
+               qlcnic_ind_wr(adapter, pollrd->sel_addr, sel_val);
+               wait_count = 0;
+               while (wait_count < poll_wait) {
+                       data = qlcnic_ind_rd(adapter, pollrd->sel_addr);
+                       if ((data & pollrd->poll_mask) != 0)
+                               break;
+                       wait_count++;
+               }
+
+               if (wait_count == poll_wait) {
+                       dev_err(&adapter->pdev->dev,
+                               "Timeout exceeded in %s, aborting dump\n",
+                               __func__);
+                       return 0;
+               }
+
+               data = qlcnic_ind_rd(adapter, pollrd->read_addr);
+               *buffer++ = cpu_to_le32(sel_val);
+               *buffer++ = cpu_to_le32(data);
+               sel_val += pollrd->sel_val_stride;
+       }
+       return pollrd->no_ops * (2 * sizeof(u32));
+}
+
+static u32
+qlcnic_read_mux2(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       struct __mux2 *mux2 = &entry->region.mux2;
+       u32 data;
+       u32 t_sel_val, sel_val1, sel_val2;
+       int i;
+
+       sel_val1 = mux2->sel_val1;
+       sel_val2 = mux2->sel_val2;
+
+       for (i = 0; i < mux2->no_ops; i++)  {
+               qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val1);
+               t_sel_val = sel_val1 & mux2->sel_val_mask;
+               qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+               data = qlcnic_ind_rd(adapter, mux2->read_addr);
+               *buffer++ = cpu_to_le32(t_sel_val);
+               *buffer++ = cpu_to_le32(data);
+               qlcnic_ind_wr(adapter, mux2->sel_addr1, sel_val2);
+               t_sel_val = sel_val2 & mux2->sel_val_mask;
+               qlcnic_ind_wr(adapter, mux2->sel_addr2, t_sel_val);
+               data = qlcnic_ind_rd(adapter, mux2->read_addr);
+               *buffer++ = cpu_to_le32(t_sel_val);
+               *buffer++ = cpu_to_le32(data);
+               sel_val1 += mux2->sel_val_stride;
+               sel_val2 += mux2->sel_val_stride;
+       }
+
+       return mux2->no_ops * (4 * sizeof(u32));
+}
+
+static u32
+qlcnic_83xx_dump_rom(struct qlcnic_adapter *adapter,
+       struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+       u32 fl_addr, size;
+       struct __mem *rom = &entry->region.mem;
+
+       fl_addr = rom->addr;
+       size = rom->size/4;
+
+       if (!qlcnic_83xx_lockless_flash_read_u32(adapter,
+                                       fl_addr, (u8 *)buffer, size))
+               return rom->size;
+
+       return 0;
+}
+
+struct qlcnic_dump_operations qlcnic_fw_dump_ops[] = {
+       { QLCNIC_DUMP_NOP, qlcnic_dump_nop },
+       { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
+       { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
+       { QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
+       { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
+       { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
+       { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
+       { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
+       { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
+       { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
+       { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
+       { QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
+};
+
+struct qlcnic_dump_operations qlcnic_83xx_fw_dump_ops[] = {
+       { QLCNIC_DUMP_NOP, qlcnic_dump_nop },
+       { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
+       { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
+       { QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
+       { QLCNIC_DUMP_BRD_CONFIG, qlcnic_83xx_dump_rom },
+       { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
+       { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
+       { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
+       { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
+       { QLCNIC_DUMP_POLL_RD, qlcnic_read_pollrd },
+       { QLCNIC_READ_MUX2, qlcnic_read_mux2 },
+       { QLCNIC_READ_POLLRDMWR, qlcnic_read_pollrdmwr },
+       { QLCNIC_DUMP_READ_ROM, qlcnic_83xx_dump_rom },
+       { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
+       { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
+       { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
+       { QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
+};
+
+static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u32 temp_size)
+{
+       uint64_t sum = 0;
+       int count = temp_size / sizeof(uint32_t);
+       while (count-- > 0)
+               sum += *temp_buffer++;
+       while (sum >> 32)
+               sum = (sum & 0xFFFFFFFF) + (sum >> 32);
+       return ~sum;
+}
+
+static int
+qlcnic_fw_flash_get_minidump_temp(struct qlcnic_adapter *adapter,
+                                       u8 *buffer, u32 size)
+{
+       int ret = 0;
+
+       if (QLCNIC_IS_82XX(adapter))
+               return -EIO;
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       ret = qlcnic_83xx_lockless_flash_read_u32(adapter,
+                       QLC_83XX_MINIDUMP_FLASH, buffer, size/sizeof(u32));
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       return ret;
+}
+
+static int
+qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+                               struct qlcnic_cmd_args *cmd)
+{
+       struct qlcnic_dump_template_hdr tmp_hdr;
+       u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+       int ret = 0;
+
+       if (QLCNIC_IS_82XX(adapter))
+               return -EIO;
+
+       if (qlcnic_83xx_lock_flash(adapter))
+               return -EIO;
+
+       ret = qlcnic_83xx_lockless_flash_read_u32(adapter,
+                       QLC_83XX_MINIDUMP_FLASH, (u8 *)&tmp_hdr, size);
+
+       qlcnic_83xx_unlock_flash(adapter);
+
+       cmd->rsp.arg[2] = tmp_hdr.size;
+       cmd->rsp.arg[3] = tmp_hdr.version;
+
+       return ret;
+}
+
+static int
+qlcnic_fw_get_minidump_temp_size(struct qlcnic_adapter *adapter,
+               u32 *version, u32 *temp_size, u8 *use_flash_temp)
+{
+       int err = 0;
+       struct qlcnic_cmd_args cmd;
+       struct qlcnic_hardware_context *ahw;
+
+       ahw = adapter->ahw;
+       if (adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                               QLCNIC_CMD_TEMP_SIZE))
+               return -ENOMEM;
+
+       err = ahw->hw_ops->mbx_cmd(adapter, &cmd);
+       if (err != QLCNIC_RCODE_SUCCESS) {
+               if (qlcnic_fw_flash_get_minidump_temp_size(adapter, &cmd)) {
+                       qlcnic_free_mbx_args(&cmd);
+                       return -EIO;
+               }
+               *use_flash_temp = 1;
+       }
+
+       *temp_size = cmd.rsp.arg[2];
+       *version = cmd.rsp.arg[3];
+       qlcnic_free_mbx_args(&cmd);
+
+       if (!(*temp_size))
+               return -EIO;
+
+       return 0;
+}
+
+static
+int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
+                               u32 *buffer, u32 temp_size)
+{
+       int err = 0, i;
+       void *tmp_addr;
+       u32 *tmp_buf;
+       struct qlcnic_cmd_args cmd;
+       dma_addr_t tmp_addr_t = 0;
+
+       tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
+                       &tmp_addr_t, GFP_KERNEL);
+       if (!tmp_addr) {
+               dev_err(&adapter->pdev->dev,
+                       "Can't get memory for FW dump template\n");
+               return -ENOMEM;
+       }
+
+       if (adapter->ahw->hw_ops->alloc_mbx_args(&cmd, adapter,
+                                       QLCNIC_CMD_GET_TEMP_HDR)) {
+               err = -ENOMEM;
+               goto free_mem;
+       }
+
+       cmd.req.arg[1] = LSD(tmp_addr_t);
+       cmd.req.arg[2] = MSD(tmp_addr_t);
+       cmd.req.arg[3] = temp_size;
+       err = adapter->ahw->hw_ops->mbx_cmd(adapter, &cmd);
+
+       tmp_buf = tmp_addr;
+       if (err == QLCNIC_RCODE_SUCCESS) {
+               for (i = 0; i < temp_size/sizeof(u32); i++)
+                       *buffer++ = __le32_to_cpu(*tmp_buf++);
+       }
+
+       qlcnic_free_mbx_args(&cmd);
+
+free_mem:
+       dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
+
+       return err;
+}
+
+int
+qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+{
+       int err;
+       u32 temp_size = 0;
+       u32 version, csum, *tmp_buf;
+       struct qlcnic_hardware_context *ahw;
+       struct qlcnic_dump_template_hdr *tmpl_hdr;
+       u8 use_flash_temp = 0;
+
+       ahw = adapter->ahw;
+
+       err = qlcnic_fw_get_minidump_temp_size(adapter, &version,
+                                       &temp_size, &use_flash_temp);
+
+       if (err) {
+               dev_info(&adapter->pdev->dev,
+                       "Can't get template size %d\n", err);
+               return -EIO;
+       }
+
+       ahw->fw_dump.tmpl_hdr = vmalloc(temp_size);
+
+       if (!ahw->fw_dump.tmpl_hdr)
+               return -ENOMEM;
+
+       memset(ahw->fw_dump.tmpl_hdr, 0, temp_size);
+       tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+
+       if (use_flash_temp)
+               goto flash_temp;
+
+       err = __qlcnic_fw_cmd_get_minidump_temp(adapter, tmp_buf, temp_size);
+
+       if (err) {
+flash_temp:
+               err = qlcnic_fw_flash_get_minidump_temp(adapter,
+                                       (u8 *)tmp_buf, temp_size);
+
+               if (err) {
+                       dev_err(&adapter->pdev->dev, "Failed to get mini dump"
+                                       "template header %d\n", err);
+                       vfree(ahw->fw_dump.tmpl_hdr);
+                       ahw->fw_dump.tmpl_hdr = NULL;
+                       return -EIO;
+               }
+       }
+
+       csum = qlcnic_temp_checksum((uint32_t *) tmp_buf, temp_size);
+
+       if (csum) {
+               dev_err(&adapter->pdev->dev,
+                       "Template header checksum validation failed\n");
+               vfree(ahw->fw_dump.tmpl_hdr);
+               ahw->fw_dump.tmpl_hdr = NULL;
+               return -EIO;
+       }
+
+       tmpl_hdr = ahw->fw_dump.tmpl_hdr;
+       tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+       ahw->fw_dump.enable = 1;
+
+       return 0;
+}
+
+int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
+{
+       u32 *buffer;
+       char mesg[64];
+       char *msg[] = {mesg, NULL};
+       int i, k, ops_cnt, ops_index, dump_size = 0;
+       u32 entry_offset, dump, no_entries, buf_offset = 0;
+       struct qlcnic_dump_entry *entry;
+       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
+       struct qlcnic_dump_operations *fw_dump_ops;
+
+       if (!fw_dump->enable) {
+               dev_info(&adapter->pdev->dev,
+                       "Dump not enabled\n");
+               return -EIO;
+       }
+
+       if (fw_dump->clr) {
+               dev_info(&adapter->pdev->dev,
+                       "Previous dump not cleared, not capturing dump\n");
+               return -EIO;
+       }
+
+       QLCDB(adapter, DRV, "Take FW dump\n");
+       /* Calculate the size for dump data area only */
+       for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
+               if (i & tmpl_hdr->drv_cap_mask)
+                       dump_size += tmpl_hdr->cap_sizes[k];
+       if (!dump_size)
+               return -EIO;
+
+       fw_dump->data = vmalloc(dump_size);
+       if (!fw_dump->data) {
+               dev_info(&adapter->pdev->dev,
+                       "Unable to allocate (%d KB) for fw dump\n",
+                       dump_size/1024);
+               return -ENOMEM;
+       }
+       memset(fw_dump->data, 0, dump_size);
+       buffer = fw_dump->data;
+       fw_dump->size = dump_size;
+       no_entries = tmpl_hdr->num_entries;
+       entry_offset = tmpl_hdr->offset;
+       tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
+       tmpl_hdr->sys_info[1] = adapter->fw_version;
+
+       if (QLCNIC_IS_82XX(adapter)) {
+               ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
+               fw_dump_ops = qlcnic_fw_dump_ops;
+       } else {
+               ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
+               fw_dump_ops = qlcnic_83xx_fw_dump_ops;
+               tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] =
+                       tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
+               tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] =
+                                               adapter->ahw->pci_func;
+       }
+
+       for (i = 0; i < no_entries; i++) {
+               entry = (void *)tmpl_hdr + entry_offset;
+               if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
+                       entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+                       entry_offset += entry->hdr.offset;
+                       continue;
+               }
+
+               /* Find the handler for this entry */
+               ops_index = 0;
+               while (ops_index < ops_cnt) {
+                       if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
+                               break;
+                       ops_index++;
+               }
+
+               if (ops_index == ops_cnt) {
+                       dev_info(&adapter->pdev->dev,
+                               "Invalid entry type %d, exiting dump\n",
+                               entry->hdr.type);
+                       goto error;
+               }
+
+               /* Collect dump for this entry */
+               dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
+               if (!qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, dump))
+                       entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+               buf_offset += entry->hdr.cap_size;
+               entry_offset += entry->hdr.offset;
+               buffer = fw_dump->data + buf_offset;
+       }
+       if (dump_size != buf_offset) {
+               dev_info(&adapter->pdev->dev,
+                       "Captured(%d) and expected size(%d) do not match\n",
+                       buf_offset, dump_size);
+               goto error;
+       } else {
+               fw_dump->clr = 1;
+               snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
+                       adapter->netdev->name);
+               netdev_info(adapter->netdev,
+                           "%s: Dump data, %d bytes captured\n",
+                           adapter->netdev->name, fw_dump->size);
+               /* Send a udev event to notify availability of FW dump */
+               kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
+               return 0;
+       }
+error:
+       vfree(fw_dump->data);
+       return -EINVAL;
+}
diff --git a/drivers/net/qlcnic/qlcnic_sysfs.c b/drivers/net/qlcnic/qlcnic_sysfs.c
new file mode 100644 (file)
index 0000000..01accc0
--- /dev/null
@@ -0,0 +1,1328 @@
+#include <linux/sysfs.h>
+#include "qlcnic.h"
+
+static ssize_t
+qlcnic_store_bridged_mode(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       unsigned long new;
+       int ret = -EINVAL;
+
+       if (!(adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG))
+               goto err_out;
+
+       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
+               goto err_out;
+
+       if (strict_strtoul(buf, 2, &new))
+               goto err_out;
+
+       if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
+               ret = len;
+
+err_out:
+       return ret;
+}
+
+static ssize_t
+qlcnic_show_bridged_mode(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       int bridged_mode = 0;
+
+       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+               bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
+
+       return sprintf(buf, "%d\n", bridged_mode);
+}
+
+static struct device_attribute dev_attr_bridged_mode = {
+       .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_bridged_mode,
+       .store = qlcnic_store_bridged_mode,
+};
+
+static ssize_t
+qlcnic_store_diag_mode(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       unsigned long new;
+
+       if (strict_strtoul(buf, 2, &new))
+               return -EINVAL;
+
+       if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
+               adapter->flags ^= QLCNIC_DIAG_ENABLED;
+
+       return len;
+}
+
+static ssize_t
+qlcnic_show_diag_mode(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n",
+                       !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+}
+
+static struct device_attribute dev_attr_diag_mode = {
+       .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_diag_mode,
+       .store = qlcnic_store_diag_mode,
+};
+
+static int
+qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
+                       u8 *rate)
+{
+       *rate = LSB(beacon);
+       *state = MSB(beacon);
+
+       QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state);
+
+       if (!*state) {
+               *rate = __QLCNIC_MAX_LED_RATE;
+               return 0;
+       } else if (*state > __QLCNIC_MAX_LED_STATE)
+               return -EINVAL;
+
+       if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
+               return -EINVAL;
+
+       return 0;
+}
+
+static ssize_t
+qlcnic_store_beacon(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int max_sds_rings = adapter->max_sds_rings;
+       int dev_down = 0;
+       u16 beacon;
+       u8 b_state, b_rate;
+       unsigned long h_beacon;
+       int err;
+
+       if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+               dev_warn(dev, "LED test not supported for non "
+                               "privilege function\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (QLCNIC_IS_83XX(adapter) &&
+                       !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+               if (strict_strtoul(buf, 2, &h_beacon))
+                       return -EINVAL;
+
+               if (ahw->beacon_state == h_beacon)
+                       return len;
+
+               rtnl_lock();
+               if (!ahw->beacon_state)
+                       if (test_and_set_bit(__QLCNIC_LED_ENABLE,
+                                               &adapter->state)) {
+                               rtnl_unlock();
+                               return -EBUSY;
+                       }
+               if (h_beacon) {
+                       err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
+                       if (err)
+                               goto beacon_err;
+               } else {
+                       err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
+                       if (err)
+                               goto beacon_err;
+               }
+               /* set the current beacon state */
+               ahw->beacon_state = h_beacon;
+beacon_err:
+               if (!ahw->beacon_state)
+                       clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+               rtnl_unlock();
+               return len;
+       }
+
+       if (len != sizeof(u16))
+               return QL_STATUS_INVALID_PARAM;
+
+       memcpy(&beacon, buf, sizeof(u16));
+       err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
+       if (err)
+               return err;
+
+       if (ahw->beacon_state == b_state)
+               return len;
+
+       if (!ahw->beacon_state)
+               if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
+                       return -EBUSY;
+
+       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+               if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+                       return -EIO;
+               err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
+               if (err) {
+                       clear_bit(__QLCNIC_RESETTING, &adapter->state);
+                       clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+                       return err;
+               }
+               dev_down = 1;
+       }
+
+       err = qlcnic_config_led(adapter, b_state, b_rate);
+
+       if (!err)
+               err = len;
+       else
+               adapter->ahw->beacon_state = b_state;
+
+       if (dev_down) {
+               qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
+               clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       }
+
+       if (!b_state)
+               clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+       return err;
+}
+
+static ssize_t
+qlcnic_show_beacon(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       return snprintf(buf, sizeof(u8) + 2, "%d\n",
+                       adapter->ahw->beacon_state);
+}
+
+static struct device_attribute dev_attr_beacon = {
+       .attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_beacon,
+       .store = qlcnic_store_beacon,
+};
+
+static ssize_t
+qlcnic_show_elb_mode(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       if (test_bit(__QLCNIC_ELB_INPROGRESS, &adapter->state))
+               return sprintf(buf, "1\n");
+
+       return sprintf(buf, "0\n");
+}
+
+static ssize_t
+qlcnic_store_elb_mode(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       unsigned long new;
+       int err;
+
+       if (strict_strtoul(buf, 2, &new))
+               return -EINVAL;
+
+       if (new == test_and_set_bit(__QLCNIC_ELB_INPROGRESS, &adapter->state))
+               return len;
+
+       rtnl_lock();
+       err = qlcnic_loopback_test(adapter->netdev, QLCNIC_ELB_MODE);
+       rtnl_unlock();
+
+       clear_bit(__QLCNIC_ELB_INPROGRESS, &adapter->state);
+
+       if (!err)
+               err = len;
+
+       return err;
+}
+
+static ssize_t
+qlcnic_show_max_rss(struct device *dev,
+                   struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       return sprintf(buf, "%d\n", adapter->max_sds_rings);
+}
+
+static ssize_t
+qlcnic_store_max_rss(struct device *dev,
+                    struct device_attribute *attr,
+                    const char *buf, size_t len)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct net_device *netdev = adapter->netdev;
+       unsigned long data;
+       int err;
+
+       if (strict_strtoul(buf, 10, &data)) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (!(adapter->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))) {
+               netdev_err(netdev, "no msix or msi support, hence no rss\n");
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (data == adapter->max_sds_rings) {
+               err = len;
+               goto done;
+       }
+
+       err = qlcnic_validate_max_rss(adapter->ahw->max_rx_ques, data);
+       if (err) {
+               netdev_err(netdev,
+                          "rss_ring valid range[1 - %d] in powers of 2\n",
+                          err);
+               err = -EINVAL;
+               goto done;
+       }
+
+       rtnl_lock();
+       err = qlcnic_set_max_rss(adapter, data);
+       rtnl_unlock();
+       err = len;
+done:
+       netdev_info(netdev, "allocated 0x%x sds rings\n",
+                   adapter->max_sds_rings);
+       return err;
+}
+
+static struct device_attribute dev_attr_max_rss = {
+       .attr = {.name = "max_rss", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_max_rss,
+       .store = qlcnic_store_max_rss,
+};
+
+static struct device_attribute dev_attr_elb_mode = {
+       .attr = {.name = "elb_mode", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_elb_mode,
+       .store = qlcnic_store_elb_mode,
+};
+
+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 (offset < QLCNIC_PCI_CRBSPACE) {
+               if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
+                                       QLCNIC_PCI_CAMQM_END))
+                       crb_size = 8;
+               else
+                       return -EINVAL;
+       }
+
+       if ((size != crb_size) || (offset & (crb_size-1)))
+               return  -EINVAL;
+
+       return 0;
+}
+
+static ssize_t
+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);
+       int ret;
+
+       ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       adapter->ahw->hw_ops->read_crb(adapter, buf, offset, size);
+       return size;
+}
+
+static ssize_t
+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);
+       int ret;
+
+       ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size);
+       return size;
+}
+
+static int
+qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
+               loff_t offset, size_t size)
+{
+       if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+               return -EIO;
+
+       if ((size != 8) || (offset & 0x7))
+               return  -EIO;
+
+       return 0;
+}
+
+static ssize_t
+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);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       u64 data;
+       int ret;
+
+       ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
+               return -EIO;
+
+       memcpy(buf, &data, size);
+
+       return size;
+}
+
+static ssize_t
+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);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       u64 data;
+       int ret;
+
+       ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+       if (ret != 0)
+               return ret;
+
+       memcpy(&data, buf, size);
+
+       if (qlcnic_pci_mem_write_2M(adapter, offset, data))
+               return -EIO;
+
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t offset, size_t size)
+{
+       void *tmp_buf;
+       int i, copy_sz, pos;
+       u32 *buf_ptr, *hdr_ptr;
+       size_t data_sz, ret = 0, tmp_sz = 0;
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+
+       if (offset >= size || offset < 0)
+               return 0;
+
+       if (!fw_dump->clr) {
+               dev_info(dev, "Dump not available\n");
+               return 0;
+       }
+
+       copy_sz = fw_dump->tmpl_hdr->size - fw_dump->pos;
+       /* Copy template header first */
+       if (copy_sz > 0) {
+               if (copy_sz < size)
+                       tmp_sz = copy_sz;
+               else
+                       tmp_sz = size;
+               tmp_buf = vmalloc(tmp_sz);
+               if (!tmp_buf)
+                       return -EIO;
+               memset(tmp_buf, 0, tmp_sz);
+               buf_ptr = (u32 *) tmp_buf;
+               hdr_ptr = (u32 *) ((void *) fw_dump->tmpl_hdr + fw_dump->pos);
+               for (i = 0; i < tmp_sz/sizeof(u32); i++)
+                       *buf_ptr++ = cpu_to_le32(*hdr_ptr++);
+
+               memcpy(buf, tmp_buf, tmp_sz);
+               ret = tmp_sz;
+               fw_dump->pos += tmp_sz;
+               data_sz = size - tmp_sz;
+               vfree(tmp_buf);
+               tmp_buf = NULL;
+       } else {
+               copy_sz = fw_dump->tmpl_hdr->size + fw_dump->size -
+                       fw_dump->pos;
+               if (copy_sz >= size)
+                       data_sz = size;
+               else
+                       data_sz = copy_sz;
+       }
+       /* Copy captured dump data */
+       if (data_sz > 0) {
+               pos = fw_dump->pos - fw_dump->tmpl_hdr->size;
+               memcpy((buf + tmp_sz), (fw_dump->data + pos), data_sz);
+               ret += data_sz;
+               fw_dump->pos += data_sz;
+       }
+       /* free dump area once the whoel dump data has been captured */
+       if (fw_dump->pos == fw_dump->size + fw_dump->tmpl_hdr->size) {
+               vfree(fw_dump->data);
+               fw_dump->size = 0;
+               fw_dump->data = NULL;
+               fw_dump->clr = 0;
+               fw_dump->pos = 0;
+               netdev_info(adapter->netdev,
+                               "extracted the FW dump Successfully\n");
+       }
+       return ret;
+}
+
+static ssize_t
+qlcnic_sysfs_write_fw_dump(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);
+       struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+       struct net_device *netdev = adapter->netdev;
+       unsigned long data;
+
+       data = simple_strtoul(buf, NULL, 16);
+       rtnl_lock();
+       switch (data) {
+       case QLCNIC_FORCE_FW_DUMP_KEY:
+               if (!fw_dump->enable) {
+                       netdev_info(netdev, "FW dump not enabled\n");
+                       goto out;
+               }
+               if (fw_dump->clr) {
+                       netdev_info(netdev,
+                          "Previous dump not cleared, not forcing dump\n");
+                       goto out;
+               }
+               netdev_info(netdev, "Forcing a fw dump\n");
+               adapter->nic_ops->request_reset(adapter,
+                                               QLCNIC_FORCE_FW_DUMP_KEY);
+               break;
+       case QLCNIC_DISABLE_FW_DUMP:
+               if (fw_dump->enable) {
+                       netdev_info(netdev, "Disabling FW dump\n");
+                       fw_dump->enable = 0;
+               }
+               break;
+       case QLCNIC_ENABLE_FW_DUMP:
+               if (!fw_dump->enable && fw_dump->tmpl_hdr) {
+                       netdev_info(netdev, "Enabling FW dump\n");
+                       fw_dump->enable = 1;
+               }
+               break;
+       case QLCNIC_FORCE_FW_RESET:
+               netdev_info(netdev, "Forcing a FW reset\n");
+               adapter->nic_ops->request_reset(adapter,
+                                               QLCNIC_FORCE_FW_RESET);
+               adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
+               break;
+       default:
+               netdev_info(netdev, "Invalid dump key, 0x%lx\n", data);
+               break;
+       }
+out:
+       rtnl_unlock();
+       return size;
+}
+
+static ssize_t
+qlcnic_store_fwdump_level(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       unsigned long int val;
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+       val = simple_strtoul(buf, NULL, 16);
+
+       if (val <= QLCNIC_DUMP_MASK_MAX && val >= QLCNIC_DUMP_MASK_MIN) {
+               rtnl_lock();
+               adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask = val & 0xff;
+               rtnl_unlock();
+               dev_info(dev, "Driver mask changed to: 0x%x\n",
+                       adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask);
+       } else
+               dev_info(dev, "Invalid Dump Level: 0x%lx\n",
+                       (unsigned long int) val);
+       return size;
+}
+
+static ssize_t
+qlcnic_show_fwdump_level(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       u32 size = adapter->ahw->fw_dump.tmpl_hdr->drv_cap_mask;
+       return sprintf(buf, "%u\n", size);
+}
+
+static ssize_t
+qlcnic_store_fwdump_size(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       return -EIO;
+}
+
+static ssize_t
+qlcnic_show_fwdump_size(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       u32 size = 0;
+       if (adapter->ahw->fw_dump.clr)
+               size = adapter->ahw->fw_dump.size +
+                       adapter->ahw->fw_dump.tmpl_hdr->size;
+       return sprintf(buf, "%u\n", size);
+}
+
+static ssize_t
+qlcnic_show_fwdump_state(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       u32 state = adapter->ahw->fw_dump.enable;
+       return sprintf(buf, "%u\n", state);
+}
+
+static ssize_t
+qlcnic_store_fwdump_state(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       return -EIO;
+}
+
+static struct device_attribute dev_attr_fwdump_size = {
+       .attr = {.name = "fwdump_size", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_fwdump_size,
+       .store = qlcnic_store_fwdump_size,
+};
+
+static struct device_attribute dev_attr_fwdump_level = {
+       .attr = {.name = "fwdump_level", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_fwdump_level,
+       .store = qlcnic_store_fwdump_level,
+};
+
+static struct bin_attribute bin_attr_crb = {
+       .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_crb,
+       .write = qlcnic_sysfs_write_crb,
+};
+
+static struct bin_attribute bin_attr_mem = {
+       .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_mem,
+       .write = qlcnic_sysfs_write_mem,
+};
+
+static struct bin_attribute bin_attr_fw_dump = {
+       .attr = {.name = "fw_dump", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_fw_dump,
+       .write = qlcnic_sysfs_write_fw_dump,
+};
+
+static struct device_attribute dev_attr_fwdump_state = {
+       .attr = {.name = "fwdump_state", .mode = (S_IRUGO | S_IWUSR)},
+       .show = qlcnic_show_fwdump_state,
+       .store = qlcnic_store_fwdump_state,
+};
+
+static int
+validate_pm_config(struct qlcnic_adapter *adapter,
+                       struct qlcnic_pm_func_cfg *pm_cfg, int count)
+{
+
+       u8 src_pci_func, s_esw_id, d_esw_id;
+       u8 dest_pci_func;
+       int i, src_index, dest_index;
+
+       for (i = 0; i < count; i++) {
+               src_pci_func = pm_cfg[i].pci_func;
+               dest_pci_func = pm_cfg[i].dest_npar;
+
+               src_index = qlcnic_is_valid_nic_func(adapter, src_pci_func);
+               if (src_index < 0)
+                       return QL_STATUS_INVALID_PARAM;
+
+               dest_index = qlcnic_is_valid_nic_func(adapter, dest_pci_func);
+               if (dest_index < 0)
+                       return QL_STATUS_INVALID_PARAM;
+
+               s_esw_id = adapter->npars[src_index].phy_port;
+               d_esw_id = adapter->npars[dest_index].phy_port;
+
+               if (s_esw_id != d_esw_id)
+                       return QL_STATUS_INVALID_PARAM;
+
+       }
+       return 0;
+
+}
+
+static ssize_t
+qlcnic_sysfs_write_pm_config(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);
+       struct qlcnic_pm_func_cfg *pm_cfg;
+       u32 id, action, pci_func;
+       int count, rem, i, ret, index;
+
+       count   = size / sizeof(struct qlcnic_pm_func_cfg);
+       rem     = size % sizeof(struct qlcnic_pm_func_cfg);
+       if (rem)
+               return QL_STATUS_INVALID_PARAM;
+
+       pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
+
+       ret = validate_pm_config(adapter, pm_cfg, count);
+       if (ret)
+               return ret;
+       for (i = 0; i < count; i++) {
+               pci_func = pm_cfg[i].pci_func;
+
+               action = !!pm_cfg[i].action;
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               if (index < 0)
+                       return QL_STATUS_INVALID_PARAM;
+
+               id = adapter->npars[index].phy_port;
+               ret = qlcnic_config_port_mirroring(adapter, id,
+                                               action, pci_func);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < count; i++) {
+               pci_func = pm_cfg[i].pci_func;
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               id = adapter->npars[index].phy_port;
+               adapter->npars[index].enable_pm = !!pm_cfg[i].action;
+               adapter->npars[index].dest_npar = id;
+       }
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pm_config(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);
+       struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
+       int i;
+       u8 pci_func;
+
+       if (size != sizeof(pm_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       memset(&pm_cfg, 0,
+               sizeof(struct qlcnic_pm_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+               pci_func = adapter->npars[i].pci_func;
+               pm_cfg[pci_func].action = adapter->npars[i].enable_pm;
+               pm_cfg[pci_func].dest_npar = 0;
+               pm_cfg[pci_func].pci_func = i;
+       }
+       memcpy(buf, &pm_cfg, size);
+
+       return size;
+}
+
+static int
+validate_esw_config(struct qlcnic_adapter *adapter,
+       struct qlcnic_esw_func_cfg *esw_cfg, int count)
+{
+       u32 op_mode;
+       u8 pci_func;
+       int i, ret;
+
+       if (QLCNIC_IS_82XX(adapter))
+               op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+       else
+               op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+
+       for (i = 0; i < count; i++) {
+               pci_func = esw_cfg[i].pci_func;
+               if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+                       if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
+                               return QL_STATUS_INVALID_PARAM;
+
+               switch (esw_cfg[i].op_mode) {
+               case QLCNIC_PORT_DEFAULTS:
+                       if (QLCNIC_IS_82XX(adapter)) {
+                               ret = QLC_DEV_GET_DRV(op_mode, pci_func);
+                       } else {
+                               ret = QLC_83XX_GET_FUNC_PRIVILEGE_LEVEL(
+                                                       op_mode, pci_func);
+                               esw_cfg[i].offload_flags = 0;
+                       }
+
+                       if (ret !=  QLCNIC_NON_PRIV_FUNC) {
+                               if (esw_cfg[i].mac_anti_spoof != 0)
+                                       return QL_STATUS_INVALID_PARAM;
+                               if (esw_cfg[i].mac_override != 1)
+                                       return QL_STATUS_INVALID_PARAM;
+                               if (esw_cfg[i].promisc_mode != 1)
+                                       return QL_STATUS_INVALID_PARAM;
+                       }
+                       break;
+               case QLCNIC_ADD_VLAN:
+                       if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
+                               return QL_STATUS_INVALID_PARAM;
+                       if (!esw_cfg[i].op_type)
+                               return QL_STATUS_INVALID_PARAM;
+                       break;
+               case QLCNIC_DEL_VLAN:
+                       if (!esw_cfg[i].op_type)
+                               return QL_STATUS_INVALID_PARAM;
+                       break;
+               default:
+                       return QL_STATUS_INVALID_PARAM;
+               }
+       }
+       return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_esw_config(struct file *file, 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);
+       struct qlcnic_esw_func_cfg *esw_cfg;
+       struct qlcnic_npar_info *npar;
+       int count, rem, i, ret;
+       int index;
+       u8 op_mode = 0, pci_func;
+
+       count   = size / sizeof(struct qlcnic_esw_func_cfg);
+       rem     = size % sizeof(struct qlcnic_esw_func_cfg);
+       if (rem)
+               return QL_STATUS_INVALID_PARAM;
+
+       esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
+       ret = validate_esw_config(adapter, esw_cfg, count);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < count; i++) {
+               if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
+                       if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
+                               return QL_STATUS_INVALID_PARAM;
+
+               if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
+                       continue;
+
+               op_mode = esw_cfg[i].op_mode;
+               qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
+               esw_cfg[i].op_mode = op_mode;
+               esw_cfg[i].pci_func = adapter->ahw->pci_func;
+
+               switch (esw_cfg[i].op_mode) {
+               case QLCNIC_PORT_DEFAULTS:
+                       qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
+                       break;
+               case QLCNIC_ADD_VLAN:
+                       qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+                       break;
+               case QLCNIC_DEL_VLAN:
+                       esw_cfg[i].vlan_id = 0;
+                       qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+                       break;
+               }
+       }
+
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
+               goto out;
+
+       for (i = 0; i < count; i++) {
+               pci_func = esw_cfg[i].pci_func;
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               npar = &adapter->npars[index];
+               switch (esw_cfg[i].op_mode) {
+               case QLCNIC_PORT_DEFAULTS:
+                       npar->promisc_mode = esw_cfg[i].promisc_mode;
+                       npar->mac_override = esw_cfg[i].mac_override;
+                       npar->offload_flags = esw_cfg[i].offload_flags;
+                       npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
+                       npar->discard_tagged = esw_cfg[i].discard_tagged;
+                       break;
+               case QLCNIC_ADD_VLAN:
+                       npar->pvid = esw_cfg[i].vlan_id;
+                       break;
+               case QLCNIC_DEL_VLAN:
+                       npar->pvid = 0;
+                       break;
+               }
+       }
+out:
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_esw_config(struct file *file, 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);
+       struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
+       u8 i, pci_func;
+
+       if (size != sizeof(esw_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       memset(&esw_cfg, 0,
+               sizeof(struct qlcnic_esw_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+       for (i = 0; i < adapter->ahw->act_pci_func; i++) {
+               pci_func = adapter->npars[i].pci_func;
+               esw_cfg[pci_func].pci_func = pci_func;
+               if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
+                       return QL_STATUS_INVALID_PARAM;
+       }
+       memcpy(buf, &esw_cfg, size);
+
+       return size;
+}
+
+static int
+validate_npar_config(struct qlcnic_adapter *adapter,
+                               struct qlcnic_npar_func_cfg *np_cfg, int count)
+{
+       u8 pci_func, i;
+
+       for (i = 0; i < count; i++) {
+               pci_func = np_cfg[i].pci_func;
+               if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0)
+                               return QL_STATUS_INVALID_PARAM;
+
+               if (!IS_VALID_BW(np_cfg[i].min_bw) ||
+                   !IS_VALID_BW(np_cfg[i].max_bw))
+                       return QL_STATUS_INVALID_PARAM;
+       }
+       return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_npar_config(struct file *file, 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);
+       struct qlcnic_info nic_info;
+       struct qlcnic_npar_func_cfg *np_cfg;
+       int i, count, rem, ret, index;
+       u8 pci_func;
+
+       count   = size / sizeof(struct qlcnic_npar_func_cfg);
+       rem     = size % sizeof(struct qlcnic_npar_func_cfg);
+       if (rem)
+               return QL_STATUS_INVALID_PARAM;
+
+       np_cfg = (struct qlcnic_npar_func_cfg *) buf;
+       ret = validate_npar_config(adapter, np_cfg, count);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < count ; i++) {
+               pci_func = np_cfg[i].pci_func;
+
+               memset(&nic_info, 0, sizeof(struct qlcnic_info));
+               ret = adapter->ahw->hw_ops->get_nic_info(adapter,
+                                               &nic_info, pci_func);
+               if (ret)
+                       return ret;
+               nic_info.pci_func = pci_func;
+               nic_info.min_tx_bw = np_cfg[i].min_bw;
+               nic_info.max_tx_bw = np_cfg[i].max_bw;
+               ret = adapter->ahw->hw_ops->set_nic_info(adapter, &nic_info);
+               if (ret)
+                       return ret;
+               index = qlcnic_is_valid_nic_func(adapter, pci_func);
+               adapter->npars[index].min_bw = nic_info.min_tx_bw;
+               adapter->npars[index].max_bw = nic_info.max_tx_bw;
+       }
+
+       return size;
+
+}
+static ssize_t
+qlcnic_sysfs_read_npar_config(struct file *file, 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);
+       struct qlcnic_info nic_info;
+       struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
+       int i, ret;
+
+       if (size != sizeof(np_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       memset(&nic_info, 0, sizeof(struct qlcnic_info));
+       memset(&np_cfg, 0, sizeof(struct qlcnic_npar_func_cfg) *
+                               QLCNIC_MAX_PCI_FUNC);
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+               if (qlcnic_is_valid_nic_func(adapter, i) < 0)
+                       continue;
+               ret = adapter->ahw->hw_ops->get_nic_info(adapter,
+                                               &nic_info, i);
+               if (ret)
+                       return ret;
+
+               np_cfg[i].pci_func = i;
+               np_cfg[i].op_mode = (u8)nic_info.op_mode;
+               np_cfg[i].port_num = nic_info.phys_port;
+               np_cfg[i].fw_capab = nic_info.capabilities;
+               np_cfg[i].min_bw = nic_info.min_tx_bw ;
+               np_cfg[i].max_bw = nic_info.max_tx_bw;
+               np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
+               np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
+       }
+       memcpy(buf, &np_cfg, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_get_port_stats(struct file *file, 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);
+       struct qlcnic_esw_statistics port_stats;
+       int ret;
+
+       if (QLCNIC_IS_83XX(adapter))
+               return QL_STATUS_UNSUPPORTED_CMD;
+
+       if (size != sizeof(struct qlcnic_esw_statistics))
+               return QL_STATUS_INVALID_PARAM;
+
+       if (offset >= QLCNIC_MAX_PCI_FUNC)
+               return QL_STATUS_INVALID_PARAM;
+
+       memset(&port_stats, 0, size);
+       ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+                                                               &port_stats.rx);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+                                                               &port_stats.tx);
+       if (ret)
+               return ret;
+
+       memcpy(buf, &port_stats, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_get_esw_stats(struct file *file, 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);
+       struct qlcnic_esw_statistics esw_stats;
+       int ret;
+
+       if (QLCNIC_IS_83XX(adapter))
+               return QL_STATUS_UNSUPPORTED_CMD;
+
+       if (size != sizeof(struct qlcnic_esw_statistics))
+               return QL_STATUS_INVALID_PARAM;
+
+       if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+               return QL_STATUS_INVALID_PARAM;
+
+       memset(&esw_stats, 0, size);
+       ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+                                                               &esw_stats.rx);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+                                                               &esw_stats.tx);
+       if (ret)
+               return ret;
+
+       memcpy(buf, &esw_stats, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_esw_stats(struct file *file, 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);
+       int ret;
+
+       if (QLCNIC_IS_83XX(adapter))
+               return QL_STATUS_UNSUPPORTED_CMD;
+
+       if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+               return QL_STATUS_INVALID_PARAM;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+                                               QLCNIC_QUERY_RX_COUNTER);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+                                               QLCNIC_QUERY_TX_COUNTER);
+       if (ret)
+               return ret;
+
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_port_stats(struct file *file, 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);
+       int ret;
+
+       if (QLCNIC_IS_83XX(adapter))
+               return QL_STATUS_UNSUPPORTED_CMD;
+
+       if (offset >= QLCNIC_MAX_PCI_FUNC)
+               return QL_STATUS_INVALID_PARAM;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+                                               QLCNIC_QUERY_RX_COUNTER);
+       if (ret)
+               return ret;
+
+       ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+                                               QLCNIC_QUERY_TX_COUNTER);
+       if (ret)
+               return ret;
+
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pci_config(struct file *file, 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);
+       struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
+       struct qlcnic_pci_info *pci_info;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       int i, ret;
+
+       if (size != sizeof(pci_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+       if (!pci_info)
+               return -ENOMEM;
+
+       ret = ahw->hw_ops->get_pci_info(adapter, pci_info);
+       if (ret) {
+               kfree(pci_info);
+               return ret;
+       }
+
+       memset(&pci_cfg, 0,
+               sizeof(struct qlcnic_pci_func_cfg) * QLCNIC_MAX_PCI_FUNC);
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+               pci_cfg[i].pci_func = pci_info[i].id;
+               pci_cfg[i].func_type = pci_info[i].type;
+               pci_cfg[i].port_num = pci_info[i].default_port;
+               pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
+               pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
+               memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
+       }
+       memcpy(buf, &pci_cfg, size);
+       kfree(pci_info);
+       return size;
+}
+
+static struct bin_attribute bin_attr_npar_config = {
+       .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_npar_config,
+       .write = qlcnic_sysfs_write_npar_config,
+};
+
+static struct bin_attribute bin_attr_pci_config = {
+       .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_pci_config,
+       .write = NULL,
+};
+
+static struct bin_attribute bin_attr_port_stats = {
+       .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_get_port_stats,
+       .write = qlcnic_sysfs_clear_port_stats,
+};
+
+static struct bin_attribute bin_attr_esw_stats = {
+       .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_get_esw_stats,
+       .write = qlcnic_sysfs_clear_esw_stats,
+};
+
+static struct bin_attribute bin_attr_esw_config = {
+       .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_esw_config,
+       .write = qlcnic_sysfs_write_esw_config,
+};
+
+static struct bin_attribute bin_attr_pm_config = {
+       .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_pm_config,
+       .write = qlcnic_sysfs_write_pm_config,
+};
+
+void
+qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+               if (device_create_file(dev, &dev_attr_bridged_mode))
+                       dev_warn(dev,
+                               "failed to create bridged_mode sysfs entry\n");
+}
+
+void
+qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+               device_remove_file(dev, &dev_attr_bridged_mode);
+}
+
+void
+qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       if (device_create_bin_file(dev, &bin_attr_port_stats))
+               dev_info(dev, "failed to create port stats sysfs entry");
+
+       if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC)
+               return;
+       if (device_create_file(dev, &dev_attr_diag_mode))
+               dev_info(dev, "failed to create diag_mode sysfs entry\n");
+       if (device_create_file(dev, &dev_attr_beacon))
+               dev_info(dev, "failed to create beacon sysfs entry");
+       if (device_create_file(dev, &dev_attr_max_rss))
+               dev_info(dev, "failed to create rss sysfs entry\n");
+       if (device_create_file(dev, &dev_attr_elb_mode))
+               dev_info(dev, "failed to create elb_mode sysfs entry\n");
+       if (device_create_bin_file(dev, &bin_attr_crb))
+               dev_info(dev, "failed to create crb sysfs entry\n");
+       if (device_create_bin_file(dev, &bin_attr_mem))
+               dev_info(dev, "failed to create mem sysfs entry\n");
+       if (adapter->ahw->fw_dump.tmpl_hdr) {
+               if (device_create_bin_file(dev, &bin_attr_fw_dump))
+                       dev_info(dev, "failed to create fw_dump sysfs entry");
+               if (device_create_file(dev, &dev_attr_fwdump_size))
+                       dev_info(dev,
+                               "failed to create fwdump_size sysfs entry");
+               if (device_create_file(dev, &dev_attr_fwdump_level))
+                       dev_info(dev,
+                               "failed to create fwdump_level sysfs entry");
+               if (device_create_file(dev, &dev_attr_fwdump_state))
+                       dev_info(dev,
+                               "failed to create fwdump_state sysfs entry");
+       }
+       if (device_create_bin_file(dev, &bin_attr_pci_config))
+               dev_info(dev, "failed to create pci config sysfs entry");
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+               return;
+       if (device_create_bin_file(dev, &bin_attr_esw_config))
+               dev_info(dev, "failed to create esw config sysfs entry");
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
+               return;
+       if (device_create_bin_file(dev, &bin_attr_npar_config))
+               dev_info(dev, "failed to create npar config sysfs entry");
+       if (device_create_bin_file(dev, &bin_attr_pm_config))
+               dev_info(dev, "failed to create pm config sysfs entry");
+       if (device_create_bin_file(dev, &bin_attr_esw_stats))
+               dev_info(dev, "failed to create eswitch stats sysfs entry");
+}
+
+void
+qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
+{
+       struct device *dev = &adapter->pdev->dev;
+
+       device_remove_bin_file(dev, &bin_attr_port_stats);
+
+       if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC)
+               return;
+       device_remove_file(dev, &dev_attr_diag_mode);
+       device_remove_file(dev, &dev_attr_beacon);
+       device_remove_file(dev, &dev_attr_max_rss);
+       device_remove_file(dev, &dev_attr_elb_mode);
+       device_remove_bin_file(dev, &bin_attr_crb);
+       device_remove_bin_file(dev, &bin_attr_mem);
+       if (adapter->ahw->fw_dump.tmpl_hdr) {
+               device_remove_bin_file(dev, &bin_attr_fw_dump);
+               device_remove_file(dev, &dev_attr_fwdump_size);
+               device_remove_file(dev, &dev_attr_fwdump_level);
+               device_remove_file(dev, &dev_attr_fwdump_state);
+       }
+       device_remove_bin_file(dev, &bin_attr_pci_config);
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+               return;
+       device_remove_bin_file(dev, &bin_attr_esw_config);
+       if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
+               return;
+       device_remove_bin_file(dev, &bin_attr_npar_config);
+       device_remove_bin_file(dev, &bin_attr_pm_config);
+       device_remove_bin_file(dev, &bin_attr_esw_stats);
+}