Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 14 Dec 2012 03:20:31 +0000 (19:20 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 14 Dec 2012 03:20:31 +0000 (19:20 -0800)
Pull first round of SCSI updates from James Bottomley:
 "This patch set includes two large new drivers: mpt3sas (for the next
  gen fusion SAS hardware) and csiostor a FCoE offload driver for the
  Chelsio converged network cards (this includes some net changes which
  I've OK'd with DaveM).

  The rest of the patch is driver updates (qla2xxx, lpfc, hptiop,
  be2iscsi) plus a few assorted updates and bug fixes.

  We also have a Power Management rework in the Upper Layer Drivers
  preparatory to doing ACPI zero power optical devices, but the actual
  enabler is still being worked on.

Signed-off-by: James Bottomley <JBottomley@Parallels.com>"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (72 commits)
  [SCSI] mpt3sas: add new driver supporting 12GB SAS
  [SCSI] scsi_transport_sas: add 12GB definitions for mpt3sas
  [SCSI] miscdevice: Adding support for MPT3SAS_MINOR(222)
  [SCSI] csiostor: remove unneeded memset()
  [SCSI] csiostor: Fix sparse warnings.
  [SCSI] qla2xxx: Display that driver is operating in legacy interrupt mode.
  [SCSI] qla2xxx: Dont clear drv active on iospace config failure.
  [SCSI] qla2xxx: Fix typo in qla2xxx driver.
  [SCSI] qla2xxx: Update ql2xextended_error_logging parameter description with new option.
  [SCSI] qla2xxx: Parameterize the link speed of hba rather than fcport.
  [SCSI] qla2xxx: Add 16Gb/s case to get port speed capability.
  [SCSI] qla2xxx: Move marking fcport online ahead of setting iiDMA speed.
  [SCSI] qla2xxx: Add acquiring of risc semaphore before doing ISP reset.
  [SCSI] qla2xxx: Ignore driver ack bit if corresponding presence bit is not set.
  [SCSI] qla2xxx: Fix typo in qla83xx_fw_dump function.
  [SCSI] qla2xxx: Add Gen3 PCIe speed 8GT/s to the log message.
  [SCSI] qla2xxx: Use correct Request-Q-Out register during bidirectional request processing
  [SCSI] qla2xxx: Move noisy Start scsi failed messages to verbose logging level.
  [SCSI] qla2xxx: Fix coccinelle warnings in qla2x00_relogin.
  [SCSI] qla2xxx: No fcport FC-4 type assignment in GA_NXT response.
  ...

105 files changed:
Documentation/scsi/hptiop.txt
MAINTAINERS
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/be2iscsi/be.h
drivers/scsi/be2iscsi/be_cmds.c
drivers/scsi/be2iscsi/be_cmds.h
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/be2iscsi/be_iscsi.h
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/be2iscsi/be_main.h
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/be2iscsi/be_mgmt.h
drivers/scsi/bnx2i/bnx2i.h
drivers/scsi/bnx2i/bnx2i_init.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/csiostor/Kconfig [new file with mode: 0644]
drivers/scsi/csiostor/Makefile [new file with mode: 0644]
drivers/scsi/csiostor/csio_attr.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_defs.h [new file with mode: 0644]
drivers/scsi/csiostor/csio_hw.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_hw.h [new file with mode: 0644]
drivers/scsi/csiostor/csio_init.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_init.h [new file with mode: 0644]
drivers/scsi/csiostor/csio_isr.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_lnode.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_lnode.h [new file with mode: 0644]
drivers/scsi/csiostor/csio_mb.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_mb.h [new file with mode: 0644]
drivers/scsi/csiostor/csio_rnode.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_rnode.h [new file with mode: 0644]
drivers/scsi/csiostor/csio_scsi.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_scsi.h [new file with mode: 0644]
drivers/scsi/csiostor/csio_wr.c [new file with mode: 0644]
drivers/scsi/csiostor/csio_wr.h [new file with mode: 0644]
drivers/scsi/csiostor/t4fw_api_stor.h [new file with mode: 0644]
drivers/scsi/hptiop.c
drivers/scsi/hptiop.h
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/mpt3sas/Kconfig [new file with mode: 0644]
drivers/scsi/mpt3sas/Makefile [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2_init.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2_ioc.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2_raid.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2_sas.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2_tool.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpi/mpi2_type.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_base.c [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_base.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_config.c [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_ctl.c [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_ctl.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_debug.h [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_scsih.c [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_transport.c [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c [new file with mode: 0644]
drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h [new file with mode: 0644]
drivers/scsi/mvsas/mv_94xx.h
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/osd/osd_uld.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_nx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/scsi_pm.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/sd.c
drivers/scsi/virtio_scsi.c
include/linux/miscdevice.h
include/scsi/scsi_device.h
include/scsi/scsi_transport_sas.h

index 9605179711f4db78f5f99c0d75296860c9c3e0e3..4a4f47e759cde1b852032d5bfb488023322df2b5 100644 (file)
@@ -37,7 +37,7 @@ For Intel IOP based adapters, the controller IOP is accessed via PCI BAR0:
             0x40    Inbound Queue Port
             0x44    Outbound Queue Port
 
-For Marvell IOP based adapters, the IOP is accessed via PCI BAR0 and BAR1:
+For Marvell not Frey IOP based adapters, the IOP is accessed via PCI BAR0 and BAR1:
 
      BAR0 offset    Register
          0x20400    Inbound Doorbell Register
@@ -55,9 +55,31 @@ For Marvell IOP based adapters, the IOP is accessed via PCI BAR0 and BAR1:
      0x40-0x1040    Inbound Queue
    0x1040-0x2040    Outbound Queue
 
+For Marvell Frey IOP based adapters, the IOP is accessed via PCI BAR0 and BAR1:
 
-I/O Request Workflow
-----------------------
+     BAR0 offset    Register
+             0x0    IOP configuration information.
+
+     BAR1 offset    Register
+          0x4000    Inbound List Base Address Low
+          0x4004    Inbound List Base Address High
+          0x4018    Inbound List Write Pointer
+          0x402C    Inbound List Configuration and Control
+          0x4050    Outbound List Base Address Low
+          0x4054    Outbound List Base Address High
+          0x4058    Outbound List Copy Pointer Shadow Base Address Low
+          0x405C    Outbound List Copy Pointer Shadow Base Address High
+          0x4088    Outbound List Interrupt Cause
+          0x408C    Outbound List Interrupt Enable
+         0x1020C    PCIe Function 0 Interrupt Enable
+         0x10400    PCIe Function 0 to CPU Message A
+         0x10420    CPU to PCIe Function 0 Message A
+         0x10480    CPU to PCIe Function 0 Doorbell
+         0x10484    CPU to PCIe Function 0 Doorbell Enable
+
+
+I/O Request Workflow of Not Marvell Frey
+------------------------------------------
 
 All queued requests are handled via inbound/outbound queue port.
 A request packet can be allocated in either IOP or host memory.
@@ -101,6 +123,45 @@ register 0. An outbound message with the same value indicates the completion
 of an inbound message.
 
 
+I/O Request Workflow of Marvell Frey
+--------------------------------------
+
+All queued requests are handled via inbound/outbound list.
+
+To send a request to the controller:
+
+    - Allocate a free request in host DMA coherent memory.
+
+      Requests allocated in host memory must be aligned on 32-bytes boundary.
+
+    - Fill the request with index of the request in the flag.
+
+      Fill a free inbound list unit with the physical address and the size of
+      the request.
+
+      Set up the inbound list write pointer with the index of previous unit,
+      round to 0 if the index reaches the supported count of requests.
+
+    - Post the inbound list writer pointer to IOP.
+
+    - The IOP process the request. When the request is completed, the flag of
+      the request with or-ed IOPMU_QUEUE_MASK_HOST_BITS will be put into a
+      free outbound list unit and the index of the outbound list unit will be
+      put into the copy pointer shadow register. An outbound interrupt will be
+      generated.
+
+    - The host read the outbound list copy pointer shadow register and compare
+      with previous saved read ponter N. If they are different, the host will
+      read the (N+1)th outbound list unit.
+
+      The host get the index of the request from the (N+1)th outbound list
+      unit and complete the request.
+
+Non-queued requests (reset communication/reset/flush etc) can be sent via PCIe
+Function 0 to CPU Message A register. The CPU to PCIe Function 0 Message register
+with the same value indicates the completion of message.
+
+
 User-level Interface
 ---------------------
 
@@ -112,7 +173,7 @@ The driver exposes following sysfs attributes:
 
 
 -----------------------------------------------------------------------------
-Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.
+Copyright (C) 2006-2012 HighPoint Technologies, Inc. All Rights Reserved.
 
   This file is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
index 42f07ea5bbc995eb710a981de36df4e69be2bc2c..63b140583e293b191a9801cbdf9ae0b6961ae9ee 100644 (file)
@@ -4655,13 +4655,16 @@ S:      Maintained
 F:     fs/logfs/
 
 LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
-M:     Eric Moore <Eric.Moore@lsi.com>
+M:     Nagalakshmi Nandigama <Nagalakshmi.Nandigama@lsi.com>
+M:     Sreekanth Reddy <Sreekanth.Reddy@lsi.com>
 M:     support@lsi.com
 L:     DL-MPTFusionLinux@lsi.com
 L:     linux-scsi@vger.kernel.org
 W:     http://www.lsilogic.com/support
 S:     Supported
 F:     drivers/message/fusion/
+F:     drivers/scsi/mpt2sas/
+F:     drivers/scsi/mpt3sas/
 
 LSILOGIC/SYMBIOS/NCR 53C8XX and 53C1010 PCI-SCSI drivers
 M:     Matthew Wilcox <matthew@wil.cx>
index 130dd9d5b493d6600a0e68194a1a4919a414151b..a27b4ae20f43486f57fef3cf3f9d08e93bcf0c6e 100644 (file)
@@ -3203,7 +3203,7 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
        memset(c, 0, sizeof(*c));
        c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
                               FW_CMD_REQUEST | FW_CMD_READ);
-       c->retval_len16 = htonl(FW_LEN16(*c));
+       c->cfvalid_to_len16 = htonl(FW_LEN16(*c));
        ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c);
        if (ret < 0)
                return ret;
@@ -3397,7 +3397,7 @@ static int adap_init0_config(struct adapter *adapter, int reset)
                htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
                      FW_CMD_REQUEST |
                      FW_CMD_READ);
-       caps_cmd.retval_len16 =
+       caps_cmd.cfvalid_to_len16 =
                htonl(FW_CAPS_CONFIG_CMD_CFVALID |
                      FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
                      FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) |
@@ -3422,7 +3422,7 @@ static int adap_init0_config(struct adapter *adapter, int reset)
                htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
                      FW_CMD_REQUEST |
                      FW_CMD_WRITE);
-       caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
+       caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
        ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
                         NULL);
        if (ret < 0)
@@ -3497,7 +3497,7 @@ static int adap_init0_no_config(struct adapter *adapter, int reset)
        memset(&caps_cmd, 0, sizeof(caps_cmd));
        caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
                                     FW_CMD_REQUEST | FW_CMD_READ);
-       caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
+       caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
        ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
                         &caps_cmd);
        if (ret < 0)
@@ -3929,7 +3929,7 @@ static int adap_init0(struct adapter *adap)
        memset(&caps_cmd, 0, sizeof(caps_cmd));
        caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
                                     FW_CMD_REQUEST | FW_CMD_READ);
-       caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
+       caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
        ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
                         &caps_cmd);
        if (ret < 0)
index 3ecc087d732d12ea3e61214235f1a99254f87924..fe9a2ea3588ba64384c154e18fc75e4372229a50 100644 (file)
@@ -508,7 +508,7 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
 {
        if (q->pend_cred >= 8) {
                wmb();
-               t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO |
+               t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO(1) |
                             QID(q->cntxt_id) | PIDX(q->pend_cred / 8));
                q->pend_cred &= 7;
        }
@@ -2082,10 +2082,10 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
                        goto fl_nomem;
 
                flsz = fl->size / 8 + s->stat_len / sizeof(struct tx_desc);
-               c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN |
+               c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN(1) |
                                            FW_IQ_CMD_FL0FETCHRO(1) |
                                            FW_IQ_CMD_FL0DATARO(1) |
-                                           FW_IQ_CMD_FL0PADEN);
+                                           FW_IQ_CMD_FL0PADEN(1));
                c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN(2) |
                                FW_IQ_CMD_FL0FBMAX(3));
                c.fl0size = htons(flsz);
index 45f2bea2e929b098ce2fa90be9987406c66c8d05..8d9c7547b07004778388171ef3b58bcd46b81d35 100644 (file)
@@ -648,12 +648,12 @@ static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
 
        if (!byte_cnt || byte_cnt > 4)
                return -EINVAL;
-       if (t4_read_reg(adapter, SF_OP) & BUSY)
+       if (t4_read_reg(adapter, SF_OP) & SF_BUSY)
                return -EBUSY;
        cont = cont ? SF_CONT : 0;
        lock = lock ? SF_LOCK : 0;
        t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1));
-       ret = t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5);
+       ret = t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5);
        if (!ret)
                *valp = t4_read_reg(adapter, SF_DATA);
        return ret;
@@ -676,14 +676,14 @@ static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
 {
        if (!byte_cnt || byte_cnt > 4)
                return -EINVAL;
-       if (t4_read_reg(adapter, SF_OP) & BUSY)
+       if (t4_read_reg(adapter, SF_OP) & SF_BUSY)
                return -EBUSY;
        cont = cont ? SF_CONT : 0;
        lock = lock ? SF_LOCK : 0;
        t4_write_reg(adapter, SF_DATA, val);
        t4_write_reg(adapter, SF_OP, lock |
                     cont | BYTECNT(byte_cnt - 1) | OP_WR);
-       return t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5);
+       return t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5);
 }
 
 /**
@@ -2252,14 +2252,14 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
                t4_write_reg(adap, EPIO_REG(DATA0), mask0);
                t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR);
                t4_read_reg(adap, EPIO_REG(OP));                /* flush */
-               if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY)
+               if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY)
                        return -ETIMEDOUT;
 
                /* write CRC */
                t4_write_reg(adap, EPIO_REG(DATA0), crc);
                t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR);
                t4_read_reg(adap, EPIO_REG(OP));                /* flush */
-               if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY)
+               if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY)
                        return -ETIMEDOUT;
        }
 #undef EPIO_REG
@@ -2405,7 +2405,7 @@ int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
 retry:
        memset(&c, 0, sizeof(c));
        INIT_CMD(c, HELLO, WRITE);
-       c.err_to_mbasyncnot = htonl(
+       c.err_to_clearinit = htonl(
                FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
                FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
                FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox :
@@ -2426,7 +2426,7 @@ retry:
                return ret;
        }
 
-       v = ntohl(c.err_to_mbasyncnot);
+       v = ntohl(c.err_to_clearinit);
        master_mbox = FW_HELLO_CMD_MBMASTER_GET(v);
        if (state) {
                if (v & FW_HELLO_CMD_ERR)
@@ -2774,7 +2774,7 @@ int t4_fw_config_file(struct adapter *adap, unsigned int mbox,
                htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
                      FW_CMD_REQUEST |
                      FW_CMD_READ);
-       caps_cmd.retval_len16 =
+       caps_cmd.cfvalid_to_len16 =
                htonl(FW_CAPS_CONFIG_CMD_CFVALID |
                      FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
                      FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) |
@@ -2797,7 +2797,7 @@ int t4_fw_config_file(struct adapter *adap, unsigned int mbox,
                htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
                      FW_CMD_REQUEST |
                      FW_CMD_WRITE);
-       caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
+       caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
        return t4_wr_mbox(adap, mbox, &caps_cmd, sizeof(caps_cmd), NULL);
 }
 
index eb71b8250b917ddd61740daf45f7b456f52aadae..b760808fd6d9831e1c56edf09fd5038dbf7f9f23 100644 (file)
@@ -658,6 +658,7 @@ struct ulptx_sgl {
        __be32 cmd_nsge;
 #define ULPTX_CMD(x) ((x) << 24)
 #define ULPTX_NSGE(x) ((x) << 0)
+#define ULPTX_MORE (1U << 23)
        __be32 len0;
        __be64 addr0;
        struct ulptx_sge_pair sge[0];
index a1a8b57200f607971f8f450495a8b7abe9478d5c..75393f5cff41877d18b3e04ed6294ae351107e94 100644 (file)
@@ -67,7 +67,7 @@
 #define  QID_MASK    0xffff8000U
 #define  QID_SHIFT   15
 #define  QID(x)      ((x) << QID_SHIFT)
-#define  DBPRIO      0x00004000U
+#define  DBPRIO(x)   ((x) << 14)
 #define  PIDX_MASK   0x00003fffU
 #define  PIDX_SHIFT  0
 #define  PIDX(x)     ((x) << PIDX_SHIFT)
 #define SGE_FL_BUFFER_SIZE1 0x1048
 #define SGE_FL_BUFFER_SIZE2 0x104c
 #define SGE_FL_BUFFER_SIZE3 0x1050
+#define SGE_FL_BUFFER_SIZE4 0x1054
+#define SGE_FL_BUFFER_SIZE5 0x1058
+#define SGE_FL_BUFFER_SIZE6 0x105c
+#define SGE_FL_BUFFER_SIZE7 0x1060
+#define SGE_FL_BUFFER_SIZE8 0x1064
+
 #define SGE_INGRESS_RX_THRESHOLD 0x10a0
 #define  THRESHOLD_0_MASK   0x3f000000U
 #define  THRESHOLD_0_SHIFT  24
 #define  EGRTHRESHOLD(x)     ((x) << EGRTHRESHOLDshift)
 #define  EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift)
 
+#define SGE_DBFIFO_STATUS 0x10a4
+#define  HP_INT_THRESH_SHIFT 28
+#define  HP_INT_THRESH_MASK  0xfU
+#define  HP_INT_THRESH(x)    ((x) << HP_INT_THRESH_SHIFT)
+#define  LP_INT_THRESH_SHIFT 12
+#define  LP_INT_THRESH_MASK  0xfU
+#define  LP_INT_THRESH(x)    ((x) << LP_INT_THRESH_SHIFT)
+
+#define SGE_DOORBELL_CONTROL 0x10a8
+#define  ENABLE_DROP        (1 << 13)
+
 #define SGE_TIMER_VALUE_0_AND_1 0x10b8
 #define  TIMERVALUE0_MASK   0xffff0000U
 #define  TIMERVALUE0_SHIFT  16
 #define A_SGE_CTXT_CMD 0x11fc
 #define A_SGE_DBQ_CTXT_BADDR 0x1084
 
+#define PCIE_PF_CFG 0x40
+#define  AIVEC(x)      ((x) << 4)
+#define  AIVEC_MASK    0x3ffU
+
 #define PCIE_PF_CLI 0x44
 #define PCIE_INT_CAUSE 0x3004
 #define  UNXSPLCPLERR  0x20000000U
 #define PCIE_MEM_ACCESS_OFFSET 0x306c
 
 #define PCIE_FW 0x30b8
+#define  PCIE_FW_ERR           0x80000000U
+#define  PCIE_FW_INIT          0x40000000U
+#define  PCIE_FW_HALT          0x20000000U
+#define  PCIE_FW_MASTER_VLD    0x00008000U
+#define  PCIE_FW_MASTER(x)     ((x) << 12)
+#define  PCIE_FW_MASTER_MASK   0x7
+#define  PCIE_FW_MASTER_GET(x) (((x) >> 12) & PCIE_FW_MASTER_MASK)
 
 #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908
 #define  RNPP 0x80000000U
 #define  MBOWNER(x)     ((x) << MBOWNER_SHIFT)
 #define  MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT)
 
+#define CIM_PF_HOST_INT_ENABLE 0x288
+#define  MBMSGRDYINTEN(x) ((x) << 19)
+
 #define CIM_PF_HOST_INT_CAUSE 0x28c
 #define  MBMSGRDYINT 0x00080000U
 
 
 #define SF_DATA 0x193f8
 #define SF_OP 0x193fc
-#define  BUSY          0x80000000U
+#define  SF_BUSY       0x80000000U
 #define  SF_LOCK       0x00000010U
 #define  SF_CONT       0x00000008U
 #define  BYTECNT_MASK  0x00000006U
 #define  I2CM       0x00000002U
 #define  CIM        0x00000001U
 
+#define PL_INT_ENABLE 0x19410
 #define PL_INT_MAP0 0x19414
 #define PL_RST 0x19428
 #define  PIORST     0x00000002U
index a6364632b490a7d1a7e57bbb086c74afcbe3181a..0abc864cdd3ae89a40fed822029a38e1e9b7f953 100644 (file)
@@ -68,6 +68,7 @@ struct fw_wr_hdr {
 };
 
 #define FW_WR_OP(x)     ((x) << 24)
+#define FW_WR_OP_GET(x)         (((x) >> 24) & 0xff)
 #define FW_WR_ATOMIC(x)         ((x) << 23)
 #define FW_WR_FLUSH(x)   ((x) << 22)
 #define FW_WR_COMPL(x)   ((x) << 21)
@@ -222,6 +223,7 @@ struct fw_cmd_hdr {
 #define FW_CMD_OP(x)           ((x) << 24)
 #define FW_CMD_OP_GET(x)        (((x) >> 24) & 0xff)
 #define FW_CMD_REQUEST          (1U << 23)
+#define FW_CMD_REQUEST_GET(x)   (((x) >> 23) & 0x1)
 #define FW_CMD_READ            (1U << 22)
 #define FW_CMD_WRITE           (1U << 21)
 #define FW_CMD_EXEC            (1U << 20)
@@ -229,6 +231,7 @@ struct fw_cmd_hdr {
 #define FW_CMD_RETVAL(x)       ((x) << 8)
 #define FW_CMD_RETVAL_GET(x)   (((x) >> 8) & 0xff)
 #define FW_CMD_LEN16(x)         ((x) << 0)
+#define FW_LEN16(fw_struct)    FW_CMD_LEN16(sizeof(fw_struct) / 16)
 
 enum fw_ldst_addrspc {
        FW_LDST_ADDRSPC_FIRMWARE  = 0x0001,
@@ -241,7 +244,8 @@ enum fw_ldst_addrspc {
        FW_LDST_ADDRSPC_TP_MIB    = 0x0012,
        FW_LDST_ADDRSPC_MDIO      = 0x0018,
        FW_LDST_ADDRSPC_MPS       = 0x0020,
-       FW_LDST_ADDRSPC_FUNC      = 0x0028
+       FW_LDST_ADDRSPC_FUNC      = 0x0028,
+       FW_LDST_ADDRSPC_FUNC_PCIE = 0x0029,
 };
 
 enum fw_ldst_mps_fid {
@@ -303,6 +307,16 @@ struct fw_ldst_cmd {
                        __be64 data0;
                        __be64 data1;
                } func;
+               struct fw_ldst_pcie {
+                       u8 ctrl_to_fn;
+                       u8 bnum;
+                       u8 r;
+                       u8 ext_r;
+                       u8 select_naccess;
+                       u8 pcie_fn;
+                       __be16 nset_pkd;
+                       __be32 data[12];
+               } pcie;
        } u;
 };
 
@@ -312,6 +326,9 @@ struct fw_ldst_cmd {
 #define FW_LDST_CMD_FID(x)     ((x) << 15)
 #define FW_LDST_CMD_CTL(x)     ((x) << 0)
 #define FW_LDST_CMD_RPLCPF(x)  ((x) << 0)
+#define FW_LDST_CMD_LC         (1U << 4)
+#define FW_LDST_CMD_NACCESS(x) ((x) << 0)
+#define FW_LDST_CMD_FN(x)      ((x) << 0)
 
 struct fw_reset_cmd {
        __be32 op_to_write;
@@ -333,7 +350,7 @@ enum fw_hellow_cmd {
 struct fw_hello_cmd {
        __be32 op_to_write;
        __be32 retval_len16;
-       __be32 err_to_mbasyncnot;
+       __be32 err_to_clearinit;
 #define FW_HELLO_CMD_ERR           (1U << 31)
 #define FW_HELLO_CMD_INIT          (1U << 30)
 #define FW_HELLO_CMD_MASTERDIS(x)   ((x) << 29)
@@ -343,6 +360,7 @@ struct fw_hello_cmd {
 #define FW_HELLO_CMD_MBMASTER(x)     ((x) << FW_HELLO_CMD_MBMASTER_SHIFT)
 #define FW_HELLO_CMD_MBMASTER_GET(x) \
        (((x) >> FW_HELLO_CMD_MBMASTER_SHIFT) & FW_HELLO_CMD_MBMASTER_MASK)
+#define FW_HELLO_CMD_MBASYNCNOTINT(x)  ((x) << 23)
 #define FW_HELLO_CMD_MBASYNCNOT(x)  ((x) << 20)
 #define FW_HELLO_CMD_STAGE(x)       ((x) << 17)
 #define FW_HELLO_CMD_CLEARINIT      (1U << 16)
@@ -428,6 +446,7 @@ enum fw_caps_config_iscsi {
 enum fw_caps_config_fcoe {
        FW_CAPS_CONFIG_FCOE_INITIATOR   = 0x00000001,
        FW_CAPS_CONFIG_FCOE_TARGET      = 0x00000002,
+       FW_CAPS_CONFIG_FCOE_CTRL_OFLD   = 0x00000004,
 };
 
 enum fw_memtype_cf {
@@ -440,7 +459,7 @@ enum fw_memtype_cf {
 
 struct fw_caps_config_cmd {
        __be32 op_to_write;
-       __be32 retval_len16;
+       __be32 cfvalid_to_len16;
        __be32 r2;
        __be32 hwmbitmap;
        __be16 nbmcaps;
@@ -701,8 +720,8 @@ struct fw_iq_cmd {
 #define FW_IQ_CMD_FL0FETCHRO(x) ((x) << 6)
 #define FW_IQ_CMD_FL0HOSTFCMODE(x) ((x) << 4)
 #define FW_IQ_CMD_FL0CPRIO(x) ((x) << 3)
-#define FW_IQ_CMD_FL0PADEN (1U << 2)
-#define FW_IQ_CMD_FL0PACKEN (1U << 1)
+#define FW_IQ_CMD_FL0PADEN(x) ((x) << 2)
+#define FW_IQ_CMD_FL0PACKEN(x) ((x) << 1)
 #define FW_IQ_CMD_FL0CONGEN (1U << 0)
 
 #define FW_IQ_CMD_FL0DCAEN(x) ((x) << 15)
@@ -1190,6 +1209,14 @@ enum fw_port_dcb_cfg_rc {
        FW_PORT_DCB_CFG_ERROR   = 0x1
 };
 
+enum fw_port_dcb_type {
+       FW_PORT_DCB_TYPE_PGID           = 0x00,
+       FW_PORT_DCB_TYPE_PGRATE         = 0x01,
+       FW_PORT_DCB_TYPE_PRIORATE       = 0x02,
+       FW_PORT_DCB_TYPE_PFC            = 0x03,
+       FW_PORT_DCB_TYPE_APP_ID         = 0x04,
+};
+
 struct fw_port_cmd {
        __be32 op_to_portid;
        __be32 action_to_len16;
@@ -1257,6 +1284,7 @@ struct fw_port_cmd {
 #define FW_PORT_CMD_TXIPG(x) ((x) << 19)
 
 #define FW_PORT_CMD_LSTATUS (1U << 31)
+#define FW_PORT_CMD_LSTATUS_GET(x) (((x) >> 31) & 0x1)
 #define FW_PORT_CMD_LSPEED(x) ((x) << 24)
 #define FW_PORT_CMD_LSPEED_GET(x) (((x) >> 24) & 0x3f)
 #define FW_PORT_CMD_TXPAUSE (1U << 23)
@@ -1305,6 +1333,9 @@ enum fw_port_module_type {
        FW_PORT_MOD_TYPE_TWINAX_PASSIVE,
        FW_PORT_MOD_TYPE_TWINAX_ACTIVE,
        FW_PORT_MOD_TYPE_LRM,
+       FW_PORT_MOD_TYPE_ERROR          = FW_PORT_CMD_MODTYPE_MASK - 3,
+       FW_PORT_MOD_TYPE_UNKNOWN        = FW_PORT_CMD_MODTYPE_MASK - 2,
+       FW_PORT_MOD_TYPE_NOTSUPPORTED   = FW_PORT_CMD_MODTYPE_MASK - 1,
 
        FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK
 };
index f16745f4b36bf2b2c30bbe8740029aa4327b5020..92170d50d9d8d0a1fa6b4ed1508de34d1855ae10 100644 (file)
@@ -536,7 +536,7 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
        if (fl->pend_cred >= FL_PER_EQ_UNIT) {
                wmb();
                t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
-                            DBPRIO |
+                            DBPRIO(1) |
                             QID(fl->cntxt_id) |
                             PIDX(fl->pend_cred / FL_PER_EQ_UNIT));
                fl->pend_cred %= FL_PER_EQ_UNIT;
@@ -952,7 +952,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
         * Warn if we write doorbells with the wrong priority and write
         * descriptors before telling HW.
         */
-       WARN_ON((QID(tq->cntxt_id) | PIDX(n)) & DBPRIO);
+       WARN_ON((QID(tq->cntxt_id) | PIDX(n)) & DBPRIO(1));
        wmb();
        t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
                     QID(tq->cntxt_id) | PIDX(n));
@@ -2126,8 +2126,8 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
                cmd.iqns_to_fl0congen =
                        cpu_to_be32(
                                FW_IQ_CMD_FL0HOSTFCMODE(SGE_HOSTFCMODE_NONE) |
-                               FW_IQ_CMD_FL0PACKEN |
-                               FW_IQ_CMD_FL0PADEN);
+                               FW_IQ_CMD_FL0PACKEN(1) |
+                               FW_IQ_CMD_FL0PADEN(1));
                cmd.fl0dcaen_to_fl0cidxfthresh =
                        cpu_to_be16(
                                FW_IQ_CMD_FL0FBMIN(SGE_FETCHBURSTMIN_64B) |
index 74bf1aa7af464811b1ed74480b104d193ca0c5dc..142f632e2a2e45c7377709989d5495382e74f5c9 100644 (file)
@@ -603,6 +603,7 @@ config SCSI_ARCMSR
 
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 source "drivers/scsi/mpt2sas/Kconfig"
+source "drivers/scsi/mpt3sas/Kconfig"
 source "drivers/scsi/ufs/Kconfig"
 
 config SCSI_HPTIOP
@@ -1812,6 +1813,7 @@ config SCSI_VIRTIO
           This is the virtual HBA driver for virtio.  If the kernel will
           be used in a virtual machine, say Y or M.
 
+source "drivers/scsi/csiostor/Kconfig"
 
 endif # SCSI_LOWLEVEL
 
index 888f73a4aae14ee62a3dcc089a6bcabdbeb8bd40..b607ba4f56304b1e9952e11c40f9285668d9f61e 100644 (file)
@@ -90,6 +90,7 @@ obj-$(CONFIG_SCSI_QLA_FC)     += qla2xxx/
 obj-$(CONFIG_SCSI_QLA_ISCSI)   += libiscsi.o qla4xxx/
 obj-$(CONFIG_SCSI_LPFC)                += lpfc/
 obj-$(CONFIG_SCSI_BFA_FC)      += bfa/
+obj-$(CONFIG_SCSI_CHELSIO_FCOE)        += csiostor/
 obj-$(CONFIG_SCSI_PAS16)       += pas16.o
 obj-$(CONFIG_SCSI_T128)                += t128.o
 obj-$(CONFIG_SCSI_DMX3191D)    += dmx3191d.o
@@ -106,6 +107,7 @@ obj-$(CONFIG_MEGARAID_LEGACY)       += megaraid.o
 obj-$(CONFIG_MEGARAID_NEWGEN)  += megaraid/
 obj-$(CONFIG_MEGARAID_SAS)     += megaraid/
 obj-$(CONFIG_SCSI_MPT2SAS)     += mpt2sas/
+obj-$(CONFIG_SCSI_MPT3SAS)     += mpt3sas/
 obj-$(CONFIG_SCSI_UFSHCD)      += ufs/
 obj-$(CONFIG_SCSI_ACARD)       += atp870u.o
 obj-$(CONFIG_SCSI_SUNESP)      += esp_scsi.o   sun_esp.o
index d79457ac8beff1628787ce8b9b4c632ed0b5e77d..681434e2dfe9b77a4da7487cdc9e9f8e2a293715 100644 (file)
@@ -132,11 +132,13 @@ struct inquiry_data {
  *              M O D U L E   G L O B A L S
  */
 
-static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
-static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
-static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
-static unsigned long aac_build_sgraw2(struct scsi_cmnd *scsicmd, struct aac_raw_io2 *rio2, int sg_max);
-static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int nseg_new);
+static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *sgmap);
+static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg);
+static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg);
+static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
+                               struct aac_raw_io2 *rio2, int sg_max);
+static int aac_convert_sgraw2(struct aac_raw_io2 *rio2,
+                               int pages, int nseg, int nseg_new);
 static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
 #ifdef AAC_DETAILED_STATUS_INFO
 static char *aac_get_status_string(u32 status);
@@ -971,6 +973,7 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
 {
        struct aac_dev *dev = fib->dev;
        u16 fibsize, command;
+       long ret;
 
        aac_fib_init(fib);
        if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) {
@@ -982,7 +985,10 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
                readcmd2->byteCount = cpu_to_le32(count<<9);
                readcmd2->cid = cpu_to_le16(scmd_id(cmd));
                readcmd2->flags = cpu_to_le16(RIO2_IO_TYPE_READ);
-               aac_build_sgraw2(cmd, readcmd2, dev->scsi_host_ptr->sg_tablesize);
+               ret = aac_build_sgraw2(cmd, readcmd2,
+                               dev->scsi_host_ptr->sg_tablesize);
+               if (ret < 0)
+                       return ret;
                command = ContainerRawIo2;
                fibsize = sizeof(struct aac_raw_io2) +
                        ((le32_to_cpu(readcmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
@@ -996,7 +1002,9 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
                readcmd->flags = cpu_to_le16(RIO_TYPE_READ);
                readcmd->bpTotal = 0;
                readcmd->bpComplete = 0;
-               aac_build_sgraw(cmd, &readcmd->sg);
+               ret = aac_build_sgraw(cmd, &readcmd->sg);
+               if (ret < 0)
+                       return ret;
                command = ContainerRawIo;
                fibsize = sizeof(struct aac_raw_io) +
                        ((le32_to_cpu(readcmd->sg.count)-1) * sizeof(struct sgentryraw));
@@ -1019,6 +1027,8 @@ static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
 {
        u16 fibsize;
        struct aac_read64 *readcmd;
+       long ret;
+
        aac_fib_init(fib);
        readcmd = (struct aac_read64 *) fib_data(fib);
        readcmd->command = cpu_to_le32(VM_CtHostRead64);
@@ -1028,7 +1038,9 @@ static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
        readcmd->pad   = 0;
        readcmd->flags = 0;
 
-       aac_build_sg64(cmd, &readcmd->sg);
+       ret = aac_build_sg64(cmd, &readcmd->sg);
+       if (ret < 0)
+               return ret;
        fibsize = sizeof(struct aac_read64) +
                ((le32_to_cpu(readcmd->sg.count) - 1) *
                 sizeof (struct sgentry64));
@@ -1050,6 +1062,8 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32
 {
        u16 fibsize;
        struct aac_read *readcmd;
+       long ret;
+
        aac_fib_init(fib);
        readcmd = (struct aac_read *) fib_data(fib);
        readcmd->command = cpu_to_le32(VM_CtBlockRead);
@@ -1057,7 +1071,9 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32
        readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
        readcmd->count = cpu_to_le32(count * 512);
 
-       aac_build_sg(cmd, &readcmd->sg);
+       ret = aac_build_sg(cmd, &readcmd->sg);
+       if (ret < 0)
+               return ret;
        fibsize = sizeof(struct aac_read) +
                        ((le32_to_cpu(readcmd->sg.count) - 1) *
                         sizeof (struct sgentry));
@@ -1079,6 +1095,7 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
 {
        struct aac_dev *dev = fib->dev;
        u16 fibsize, command;
+       long ret;
 
        aac_fib_init(fib);
        if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) {
@@ -1093,7 +1110,10 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
                                                   (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
                        cpu_to_le16(RIO2_IO_TYPE_WRITE|RIO2_IO_SUREWRITE) :
                        cpu_to_le16(RIO2_IO_TYPE_WRITE);
-               aac_build_sgraw2(cmd, writecmd2, dev->scsi_host_ptr->sg_tablesize);
+               ret = aac_build_sgraw2(cmd, writecmd2,
+                               dev->scsi_host_ptr->sg_tablesize);
+               if (ret < 0)
+                       return ret;
                command = ContainerRawIo2;
                fibsize = sizeof(struct aac_raw_io2) +
                        ((le32_to_cpu(writecmd2->sgeCnt)-1) * sizeof(struct sge_ieee1212));
@@ -1110,7 +1130,9 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
                        cpu_to_le16(RIO_TYPE_WRITE);
                writecmd->bpTotal = 0;
                writecmd->bpComplete = 0;
-               aac_build_sgraw(cmd, &writecmd->sg);
+               ret = aac_build_sgraw(cmd, &writecmd->sg);
+               if (ret < 0)
+                       return ret;
                command = ContainerRawIo;
                fibsize = sizeof(struct aac_raw_io) +
                        ((le32_to_cpu(writecmd->sg.count)-1) * sizeof (struct sgentryraw));
@@ -1133,6 +1155,8 @@ static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba,
 {
        u16 fibsize;
        struct aac_write64 *writecmd;
+       long ret;
+
        aac_fib_init(fib);
        writecmd = (struct aac_write64 *) fib_data(fib);
        writecmd->command = cpu_to_le32(VM_CtHostWrite64);
@@ -1142,7 +1166,9 @@ static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba,
        writecmd->pad   = 0;
        writecmd->flags = 0;
 
-       aac_build_sg64(cmd, &writecmd->sg);
+       ret = aac_build_sg64(cmd, &writecmd->sg);
+       if (ret < 0)
+               return ret;
        fibsize = sizeof(struct aac_write64) +
                ((le32_to_cpu(writecmd->sg.count) - 1) *
                 sizeof (struct sgentry64));
@@ -1164,6 +1190,8 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
 {
        u16 fibsize;
        struct aac_write *writecmd;
+       long ret;
+
        aac_fib_init(fib);
        writecmd = (struct aac_write *) fib_data(fib);
        writecmd->command = cpu_to_le32(VM_CtBlockWrite);
@@ -1173,7 +1201,9 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
        writecmd->sg.count = cpu_to_le32(1);
        /* ->stable is not used - it did mean which type of write */
 
-       aac_build_sg(cmd, &writecmd->sg);
+       ret = aac_build_sg(cmd, &writecmd->sg);
+       if (ret < 0)
+               return ret;
        fibsize = sizeof(struct aac_write) +
                ((le32_to_cpu(writecmd->sg.count) - 1) *
                 sizeof (struct sgentry));
@@ -1235,8 +1265,11 @@ static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
 {
        u16 fibsize;
        struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
+       long ret;
 
-       aac_build_sg64(cmd, (struct sgmap64*) &srbcmd->sg);
+       ret = aac_build_sg64(cmd, (struct sgmap64 *) &srbcmd->sg);
+       if (ret < 0)
+               return ret;
        srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
 
        memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
@@ -1263,8 +1296,11 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
 {
        u16 fibsize;
        struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
+       long ret;
 
-       aac_build_sg(cmd, (struct sgmap*)&srbcmd->sg);
+       ret = aac_build_sg(cmd, (struct sgmap *)&srbcmd->sg);
+       if (ret < 0)
+               return ret;
        srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
 
        memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
@@ -2870,7 +2906,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
        return -1;
 }
 
-static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
+static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg)
 {
        struct aac_dev *dev;
        unsigned long byte_count = 0;
@@ -2883,7 +2919,8 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
        psg->sg[0].count = 0;
 
        nseg = scsi_dma_map(scsicmd);
-       BUG_ON(nseg < 0);
+       if (nseg < 0)
+               return nseg;
        if (nseg) {
                struct scatterlist *sg;
                int i;
@@ -2912,7 +2949,7 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
 }
 
 
-static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg)
+static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg)
 {
        struct aac_dev *dev;
        unsigned long byte_count = 0;
@@ -2927,7 +2964,8 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
        psg->sg[0].count = 0;
 
        nseg = scsi_dma_map(scsicmd);
-       BUG_ON(nseg < 0);
+       if (nseg < 0)
+               return nseg;
        if (nseg) {
                struct scatterlist *sg;
                int i;
@@ -2957,7 +2995,7 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
        return byte_count;
 }
 
-static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
+static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg)
 {
        unsigned long byte_count = 0;
        int nseg;
@@ -2972,7 +3010,8 @@ static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw*
        psg->sg[0].flags = 0;
 
        nseg = scsi_dma_map(scsicmd);
-       BUG_ON(nseg < 0);
+       if (nseg < 0)
+               return nseg;
        if (nseg) {
                struct scatterlist *sg;
                int i;
@@ -3005,13 +3044,15 @@ static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw*
        return byte_count;
 }
 
-static unsigned long aac_build_sgraw2(struct scsi_cmnd *scsicmd, struct aac_raw_io2 *rio2, int sg_max)
+static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
+                               struct aac_raw_io2 *rio2, int sg_max)
 {
        unsigned long byte_count = 0;
        int nseg;
 
        nseg = scsi_dma_map(scsicmd);
-       BUG_ON(nseg < 0);
+       if (nseg < 0)
+               return nseg;
        if (nseg) {
                struct scatterlist *sg;
                int i, conformable = 0;
index 9e933a88a8bc5aaa95b8fc929ec51395a53495e1..742f5d7eb0f5988c8b07592eef1448685f5ab7a1 100644 (file)
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 29800
+# define AAC_DRIVER_BUILD 29801
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
index a50b6a9030e88acaabc85aae89d2fd1df1e4c146..f1733dfa3ae24489b44b3f6bee92568589c7ade1 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -28,7 +28,7 @@
 /* BladeEngine Generation numbers */
 #define BE_GEN2 2
 #define BE_GEN3 3
-
+#define BE_GEN4        4
 struct be_dma_mem {
        void *va;
        dma_addr_t dma;
@@ -84,9 +84,12 @@ static inline void queue_tail_inc(struct be_queue_info *q)
 /*ISCSI */
 
 struct be_eq_obj {
+       bool todo_mcc_cq;
+       bool todo_cq;
        struct be_queue_info q;
        struct beiscsi_hba *phba;
        struct be_queue_info *cq;
+       struct work_struct work_cqs; /* Work Item */
        struct blk_iopoll       iopoll;
 };
 
index 07d2cb126d934eca69956a6269ab3543a3333dac..5c87768c109c0fa9a8fc0dda6f8bcb6c357ca083 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -56,7 +56,7 @@ int beiscsi_pci_soft_reset(struct beiscsi_hba *phba)
        writel(pconline0, (void *)pci_online0_offset);
        writel(pconline1, (void *)pci_online1_offset);
 
-       sreset = BE2_SET_RESET;
+       sreset |= BE2_SET_RESET;
        writel(sreset, (void *)pci_reset_offset);
 
        i = 0;
@@ -133,6 +133,87 @@ unsigned int alloc_mcc_tag(struct beiscsi_hba *phba)
        return tag;
 }
 
+/*
+ * beiscsi_mccq_compl()- Wait for completion of MBX
+ * @phba: Driver private structure
+ * @tag: Tag for the MBX Command
+ * @wrb: the WRB used for the MBX Command
+ * @cmd_hdr: IOCTL Hdr for the MBX Cmd
+ *
+ * Waits for MBX completion with the passed TAG.
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero
+ **/
+int beiscsi_mccq_compl(struct beiscsi_hba *phba,
+               uint32_t tag, struct be_mcc_wrb **wrb,
+               void *cmd_hdr)
+{
+       int rc = 0;
+       uint32_t mcc_tag_response;
+       uint16_t status = 0, addl_status = 0, wrb_num = 0;
+       struct be_mcc_wrb *temp_wrb;
+       struct be_cmd_req_hdr *ioctl_hdr;
+       struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+
+       if (beiscsi_error(phba))
+               return -EIO;
+
+       /* wait for the mccq completion */
+       rc = wait_event_interruptible_timeout(
+                               phba->ctrl.mcc_wait[tag],
+                               phba->ctrl.mcc_numtag[tag],
+                               msecs_to_jiffies(
+                               BEISCSI_HOST_MBX_TIMEOUT));
+
+       if (rc <= 0) {
+               beiscsi_log(phba, KERN_ERR,
+                           BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
+                           BEISCSI_LOG_CONFIG,
+                           "BC_%d : MBX Cmd Completion timed out\n");
+               rc = -EAGAIN;
+               goto release_mcc_tag;
+       } else
+               rc = 0;
+
+       mcc_tag_response = phba->ctrl.mcc_numtag[tag];
+       status = (mcc_tag_response & CQE_STATUS_MASK);
+       addl_status = ((mcc_tag_response & CQE_STATUS_ADDL_MASK) >>
+                       CQE_STATUS_ADDL_SHIFT);
+
+       if (cmd_hdr) {
+               ioctl_hdr = (struct be_cmd_req_hdr *)cmd_hdr;
+       } else {
+               wrb_num = (mcc_tag_response & CQE_STATUS_WRB_MASK) >>
+                          CQE_STATUS_WRB_SHIFT;
+               temp_wrb = (struct be_mcc_wrb *)queue_get_wrb(mccq, wrb_num);
+               ioctl_hdr = embedded_payload(temp_wrb);
+
+               if (wrb)
+                       *wrb = temp_wrb;
+       }
+
+       if (status || addl_status) {
+               beiscsi_log(phba, KERN_ERR,
+                           BEISCSI_LOG_INIT | BEISCSI_LOG_EH |
+                           BEISCSI_LOG_CONFIG,
+                           "BC_%d : MBX Cmd Failed for "
+                           "Subsys : %d Opcode : %d with "
+                           "Status : %d and Extd_Status : %d\n",
+                           ioctl_hdr->subsystem,
+                           ioctl_hdr->opcode,
+                           status, addl_status);
+               rc = -EAGAIN;
+       }
+
+release_mcc_tag:
+       /* Release the MCC entry */
+       free_mcc_tag(&phba->ctrl, tag);
+
+       return rc;
+}
+
 void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag)
 {
        spin_lock(&ctrl->mbox_lock);
@@ -168,11 +249,24 @@ static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
        compl->flags = 0;
 }
 
+/*
+ * be_mcc_compl_process()- Check the MBX comapletion status
+ * @ctrl: Function specific MBX data structure
+ * @compl: Completion status of MBX Command
+ *
+ * Check for the MBX completion status when BMBX method used
+ *
+ * return
+ * Success: Zero
+ * Failure: Non-Zero
+ **/
 static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
                                struct be_mcc_compl *compl)
 {
        u16 compl_status, extd_status;
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
        struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
+       struct be_cmd_req_hdr *hdr = embedded_payload(wrb);
 
        be_dws_le_to_cpu(compl, 4);
 
@@ -184,7 +278,10 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
 
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BC_%d : error in cmd completion: status(compl/extd)=%d/%d\n",
+                           "BC_%d : error in cmd completion: "
+                           "Subsystem : %d Opcode : %d "
+                           "status(compl/extd)=%d/%d\n",
+                           hdr->subsystem, hdr->opcode,
                            compl_status, extd_status);
 
                return -EBUSY;
@@ -314,11 +411,24 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba)
        return status;
 }
 
-/* Wait till no more pending mcc requests are present */
+/*
+ * be_mcc_wait_compl()- Wait for MBX completion
+ * @phba: driver private structure
+ *
+ * Wait till no more pending mcc requests are present
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero
+ *
+ **/
 static int be_mcc_wait_compl(struct beiscsi_hba *phba)
 {
        int i, status;
        for (i = 0; i < mcc_timeout; i++) {
+               if (beiscsi_error(phba))
+                       return -EIO;
+
                status = beiscsi_process_mcc(phba);
                if (status)
                        return status;
@@ -330,51 +440,83 @@ static int be_mcc_wait_compl(struct beiscsi_hba *phba)
        if (i == mcc_timeout) {
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BC_%d : mccq poll timed out\n");
-
+                           "BC_%d : FW Timed Out\n");
+               phba->fw_timeout = true;
+               beiscsi_ue_detect(phba);
                return -EBUSY;
        }
        return 0;
 }
 
-/* Notify MCC requests and wait for completion */
+/*
+ * be_mcc_notify_wait()- Notify and wait for Compl
+ * @phba: driver private structure
+ *
+ * Notify MCC requests and wait for completion
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero
+ **/
 int be_mcc_notify_wait(struct beiscsi_hba *phba)
 {
        be_mcc_notify(phba);
        return be_mcc_wait_compl(phba);
 }
 
+/*
+ * be_mbox_db_ready_wait()- Check ready status
+ * @ctrl: Function specific MBX data structure
+ *
+ * Check for the ready status of FW to send BMBX
+ * commands to adapter.
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero
+ **/
 static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
 {
-#define long_delay 2000
        void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
-       int cnt = 0, wait = 5;  /* in usecs */
+       struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
+       int wait = 0;
        u32 ready;
 
        do {
+
+               if (beiscsi_error(phba))
+                       return -EIO;
+
                ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
                if (ready)
                        break;
 
-               if (cnt > 12000000) {
-                       struct beiscsi_hba *phba = pci_get_drvdata(ctrl->pdev);
+               if (wait > BEISCSI_HOST_MBX_TIMEOUT) {
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                                   "BC_%d : mbox_db poll timed out\n");
-
+                                   "BC_%d : FW Timed Out\n");
+                       phba->fw_timeout = true;
+                       beiscsi_ue_detect(phba);
                        return -EBUSY;
                }
 
-               if (cnt > 50) {
-                       wait = long_delay;
-                       mdelay(long_delay / 1000);
-               } else
-                       udelay(wait);
-               cnt += wait;
+               mdelay(1);
+               wait++;
        } while (true);
        return 0;
 }
 
+/*
+ * be_mbox_notify: Notify adapter of new BMBX command
+ * @ctrl: Function specific MBX data structure
+ *
+ * Ring doorbell to inform adapter of a BMBX command
+ * to process
+ *
+ * return
+ * Success: 0
+ * Failure: Non-Zero
+ **/
 int be_mbox_notify(struct be_ctrl_info *ctrl)
 {
        int status;
@@ -391,13 +533,9 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
        iowrite32(val, db);
 
        status = be_mbox_db_ready_wait(ctrl);
-       if (status != 0) {
-               beiscsi_log(phba, KERN_ERR,
-                           BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BC_%d : be_mbox_db_ready_wait failed\n");
-
+       if (status)
                return status;
-       }
+
        val = 0;
        val &= ~MPU_MAILBOX_DB_RDY_MASK;
        val &= ~MPU_MAILBOX_DB_HI_MASK;
@@ -405,13 +543,9 @@ int be_mbox_notify(struct be_ctrl_info *ctrl)
        iowrite32(val, db);
 
        status = be_mbox_db_ready_wait(ctrl);
-       if (status != 0) {
-               beiscsi_log(phba, KERN_ERR,
-                           BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BC_%d : be_mbox_db_ready_wait failed\n");
-
+       if (status)
                return status;
-       }
+
        if (be_mcc_compl_is_new(compl)) {
                status = be_mcc_compl_process(ctrl, &mbox->compl);
                be_mcc_compl_use(compl);
@@ -499,7 +633,7 @@ void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
        req_hdr->opcode = opcode;
        req_hdr->subsystem = subsystem;
        req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
-       req_hdr->timeout = 120;
+       req_hdr->timeout = BEISCSI_FW_MBX_TIMEOUT;
 }
 
 static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
@@ -649,18 +783,34 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
                        OPCODE_COMMON_CQ_CREATE, sizeof(*req));
 
        req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+       if (chip_skh_r(ctrl->pdev)) {
+               req->hdr.version = MBX_CMD_VER2;
+               req->page_size = 1;
+               AMAP_SET_BITS(struct amap_cq_context_v2, coalescwm,
+                             ctxt, coalesce_wm);
+               AMAP_SET_BITS(struct amap_cq_context_v2, nodelay,
+                             ctxt, no_delay);
+               AMAP_SET_BITS(struct amap_cq_context_v2, count, ctxt,
+                             __ilog2_u32(cq->len / 256));
+               AMAP_SET_BITS(struct amap_cq_context_v2, valid, ctxt, 1);
+               AMAP_SET_BITS(struct amap_cq_context_v2, eventable, ctxt, 1);
+               AMAP_SET_BITS(struct amap_cq_context_v2, eqid, ctxt, eq->id);
+               AMAP_SET_BITS(struct amap_cq_context_v2, armed, ctxt, 1);
+       } else {
+               AMAP_SET_BITS(struct amap_cq_context, coalescwm,
+                             ctxt, coalesce_wm);
+               AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay);
+               AMAP_SET_BITS(struct amap_cq_context, count, ctxt,
+                             __ilog2_u32(cq->len / 256));
+               AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1);
+               AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts);
+               AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
+               AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
+               AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
+               AMAP_SET_BITS(struct amap_cq_context, func, ctxt,
+                             PCI_FUNC(ctrl->pdev->devfn));
+       }
 
-       AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm);
-       AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay);
-       AMAP_SET_BITS(struct amap_cq_context, count, ctxt,
-                     __ilog2_u32(cq->len / 256));
-       AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1);
-       AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts);
-       AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
-       AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
-       AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
-       AMAP_SET_BITS(struct amap_cq_context, func, ctxt,
-                     PCI_FUNC(ctrl->pdev->devfn));
        be_dws_cpu_to_le(ctxt, sizeof(req->context));
 
        be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
index 2c8f98df12875c478c3e5e0872623b6476f0106b..23397d51ac54f5f9550f15b3b4571ed8342ee762 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -57,6 +57,16 @@ struct be_mcc_wrb {
 #define CQE_STATUS_COMPL_SHIFT 0       /* bits 0 - 15 */
 #define CQE_STATUS_EXTD_MASK 0xFFFF
 #define CQE_STATUS_EXTD_SHIFT 16               /* bits 0 - 15 */
+#define CQE_STATUS_ADDL_MASK   0xFF00
+#define CQE_STATUS_MASK        0xFF
+#define CQE_STATUS_ADDL_SHIFT  0x08
+#define CQE_STATUS_WRB_MASK    0xFF0000
+#define CQE_STATUS_WRB_SHIFT   16
+#define BEISCSI_HOST_MBX_TIMEOUT (110 * 1000)
+#define BEISCSI_FW_MBX_TIMEOUT 100
+
+/* MBOX Command VER */
+#define MBX_CMD_VER2   0x02
 
 struct be_mcc_compl {
        u32 status;             /* dword 0 */
@@ -183,7 +193,8 @@ struct be_cmd_req_hdr {
        u8 domain;              /* dword 0 */
        u32 timeout;            /* dword 1 */
        u32 request_length;     /* dword 2 */
-       u32 rsvd0;              /* dword 3 */
+       u8 version;             /* dword 3 */
+       u8 rsvd0[3];            /* dword 3 */
 };
 
 struct be_cmd_resp_hdr {
@@ -483,10 +494,28 @@ struct amap_cq_context {
        u8 rsvd5[32];           /* dword 3 */
 } __packed;
 
+struct amap_cq_context_v2 {
+       u8 rsvd0[12];   /* dword 0 */
+       u8 coalescwm[2];    /* dword 0 */
+       u8 nodelay;     /* dword 0 */
+       u8 rsvd1[12];   /* dword 0 */
+       u8 count[2];    /* dword 0 */
+       u8 valid;       /* dword 0 */
+       u8 rsvd2;       /* dword 0 */
+       u8 eventable;   /* dword 0 */
+       u8 eqid[16];    /* dword 1 */
+       u8 rsvd3[15];   /* dword 1 */
+       u8 armed;       /* dword 1 */
+       u8 cqecount[16];/* dword 2 */
+       u8 rsvd4[16];   /* dword 2 */
+       u8 rsvd5[32];   /* dword 3 */
+};
+
 struct be_cmd_req_cq_create {
        struct be_cmd_req_hdr hdr;
        u16 num_pages;
-       u16 rsvd0;
+       u8 page_size;
+       u8 rsvd0;
        u8 context[sizeof(struct amap_cq_context) / 8];
        struct phys_addr pages[4];
 } __packed;
@@ -663,6 +692,9 @@ unsigned int be_cmd_get_initname(struct beiscsi_hba *phba);
 unsigned int be_cmd_get_port_speed(struct beiscsi_hba *phba);
 
 void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag);
+
+int beiscsi_mccq_compl(struct beiscsi_hba *phba,
+                       uint32_t tag, struct be_mcc_wrb **wrb, void *cmd_va);
 /*ISCSI Functuions */
 int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
 
@@ -804,6 +836,59 @@ struct amap_sol_cqe_ring {
        u8 valid;               /* dword 3 */
 } __packed;
 
+struct amap_sol_cqe_v2 {
+       u8 hw_sts[8];   /* dword 0 */
+       u8 i_sts[8];    /* dword 0 */
+       u8 wrb_index[16];   /* dword 0 */
+       u8 i_exp_cmd_sn[32];    /* dword 1 */
+       u8 code[6]; /* dword 2 */
+       u8 cmd_cmpl;    /* dword 2 */
+       u8 rsvd0;   /* dword 2 */
+       u8 i_cmd_wnd[8];    /* dword 2 */
+       u8 cid[13]; /* dword 2 */
+       u8 u;   /* dword 2 */
+       u8 o;   /* dword 2 */
+       u8 s;   /* dword 2 */
+       u8 i_res_cnt[31];   /* dword 3 */
+       u8 valid;   /* dword 3 */
+} __packed;
+
+struct common_sol_cqe {
+       u32 exp_cmdsn;
+       u32 res_cnt;
+       u16 wrb_index;
+       u16 cid;
+       u8 hw_sts;
+       u8 cmd_wnd;
+       u8 res_flag; /* the s feild of structure */
+       u8 i_resp; /* for skh if cmd_complete is set then i_sts is response */
+       u8 i_flags; /* for skh or the u and o feilds */
+       u8 i_sts; /* for skh if cmd_complete is not-set then i_sts is status */
+};
+
+/*** iSCSI ack/driver message completions ***/
+struct amap_it_dmsg_cqe {
+       u8 ack_num[32]; /* DWORD 0 */
+       u8 pdu_bytes_rcvd[32];  /* DWORD 1 */
+       u8 code[6]; /* DWORD 2 */
+       u8 cid[10]; /* DWORD 2 */
+       u8 wrb_idx[8];  /* DWORD 2 */
+       u8 rsvd0[8];    /* DWORD 2*/
+       u8 rsvd1[31];   /* DWORD 3*/
+       u8 valid;   /* DWORD 3 */
+} __packed;
+
+struct amap_it_dmsg_cqe_v2 {
+       u8 ack_num[32]; /* DWORD 0 */
+       u8 pdu_bytes_rcvd[32];  /* DWORD 1 */
+       u8 code[6]; /* DWORD 2 */
+       u8 rsvd0[10];   /* DWORD 2 */
+       u8 wrb_idx[16]; /* DWORD 2 */
+       u8 rsvd1[16];   /* DWORD 3 */
+       u8 cid[13]; /* DWORD 3 */
+       u8 rsvd2[2];    /* DWORD 3 */
+       u8 valid;   /* DWORD 3 */
+} __packed;
 
 
 /**
@@ -992,8 +1077,6 @@ struct be_cmd_get_all_if_id_req {
 #define CONNECTION_UPLOAD_ABORT_WITH_SEQ 4     /* Abortive upload with reset,
                                                 * sequence number by driver  */
 
-/* Returns byte size of given field with a structure. */
-
 /* Returns the number of items in the field array. */
 #define BE_NUMBER_OF_FIELD(_type_, _field_)    \
        (FIELD_SIZEOF(_type_, _field_)/sizeof((((_type_ *)0)->_field_[0])))\
index aedb0d9a9dae652d753455df07c2aee1a4d9e867..214d691adb53ab21d39ae7425df6f9150c1eb0d5 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -531,9 +531,9 @@ static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
                break;
        case ISCSI_NET_PARAM_IPV4_BOOTPROTO:
                if (!if_info.dhcp_state)
-                       len = sprintf(buf, "static");
+                       len = sprintf(buf, "static\n");
                else
-                       len = sprintf(buf, "dhcp");
+                       len = sprintf(buf, "dhcp\n");
                break;
        case ISCSI_NET_PARAM_IPV4_SUBNET:
                len = sprintf(buf, "%pI4\n", &if_info.ip_addr.subnet_mask);
@@ -541,7 +541,7 @@ static int be2iscsi_get_if_param(struct beiscsi_hba *phba,
        case ISCSI_NET_PARAM_VLAN_ENABLED:
                len = sprintf(buf, "%s\n",
                             (if_info.vlan_priority == BEISCSI_VLAN_DISABLE)
-                            ? "Disabled" : "Enabled");
+                            ? "Disabled\n" : "Enabled\n");
                break;
        case ISCSI_NET_PARAM_VLAN_ID:
                if (if_info.vlan_priority == BEISCSI_VLAN_DISABLE)
@@ -586,7 +586,7 @@ int be2iscsi_iface_get_param(struct iscsi_iface *iface,
                len = be2iscsi_get_if_param(phba, iface, param, buf);
                break;
        case ISCSI_NET_PARAM_IFACE_ENABLE:
-               len = sprintf(buf, "enabled");
+               len = sprintf(buf, "enabled\n");
                break;
        case ISCSI_NET_PARAM_IPV4_GW:
                memset(&gateway, 0, sizeof(gateway));
@@ -690,11 +690,9 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
 static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba)
 {
        int rc;
-       unsigned int tag, wrb_num;
-       unsigned short status, extd_status;
+       unsigned int tag;
        struct be_mcc_wrb *wrb;
        struct be_cmd_hba_name *resp;
-       struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
 
        tag = be_cmd_get_initname(phba);
        if (!tag) {
@@ -702,26 +700,16 @@ static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba)
                            "BS_%d : Getting Initiator Name Failed\n");
 
                return -EBUSY;
-       } else
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                               phba->ctrl.mcc_numtag[tag]);
-
-       wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-       extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-       status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+       }
 
-       if (status || extd_status) {
+       rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+       if (rc) {
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BS_%d : MailBox Command Failed with "
-                           "status = %d extd_status = %d\n",
-                           status, extd_status);
-
-               free_mcc_tag(&phba->ctrl, tag);
-               return -EAGAIN;
+                           "BS_%d : Initiator Name MBX Failed\n");
+               return rc;
        }
-       wrb = queue_get_wrb(mccq, wrb_num);
-       free_mcc_tag(&phba->ctrl, tag);
+
        resp = embedded_payload(wrb);
        rc = sprintf(buf, "%s\n", resp->initiator_name);
        return rc;
@@ -731,7 +719,6 @@ static int beiscsi_get_initname(char *buf, struct beiscsi_hba *phba)
  * beiscsi_get_port_state - Get the Port State
  * @shost : pointer to scsi_host structure
  *
- * returns number of bytes
  */
 static void beiscsi_get_port_state(struct Scsi_Host *shost)
 {
@@ -750,13 +737,12 @@ static void beiscsi_get_port_state(struct Scsi_Host *shost)
  */
 static int beiscsi_get_port_speed(struct Scsi_Host *shost)
 {
-       unsigned int tag, wrb_num;
-       unsigned short status, extd_status;
+       int rc;
+       unsigned int tag;
        struct be_mcc_wrb *wrb;
        struct be_cmd_ntwk_link_status_resp *resp;
        struct beiscsi_hba *phba = iscsi_host_priv(shost);
        struct iscsi_cls_host *ihost = shost->shost_data;
-       struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
 
        tag = be_cmd_get_port_speed(phba);
        if (!tag) {
@@ -764,26 +750,14 @@ static int beiscsi_get_port_speed(struct Scsi_Host *shost)
                            "BS_%d : Getting Port Speed Failed\n");
 
                 return -EBUSY;
-        } else
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                               phba->ctrl.mcc_numtag[tag]);
-
-       wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-       extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-       status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
-
-       if (status || extd_status) {
+       }
+       rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+       if (rc) {
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BS_%d : MailBox Command Failed with "
-                           "status = %d extd_status = %d\n",
-                           status, extd_status);
-
-               free_mcc_tag(&phba->ctrl, tag);
-               return -EAGAIN;
+                           "BS_%d : Port Speed MBX Failed\n");
+               return rc;
        }
-       wrb = queue_get_wrb(mccq, wrb_num);
-       free_mcc_tag(&phba->ctrl, tag);
        resp = embedded_payload(wrb);
 
        switch (resp->mac_speed) {
@@ -937,6 +911,14 @@ static void  beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn,
                      session->initial_r2t_en);
        AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params,
                      session->imm_data_en);
+       AMAP_SET_BITS(struct amap_beiscsi_offload_params,
+                     data_seq_inorder, params,
+                     session->dataseq_inorder_en);
+       AMAP_SET_BITS(struct amap_beiscsi_offload_params,
+                     pdu_seq_inorder, params,
+                     session->pdu_inorder_en);
+       AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_r2t, params,
+                     session->max_r2t);
        AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params,
                      (conn->exp_statsn - 1));
 }
@@ -1027,12 +1009,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
 {
        struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
        struct beiscsi_hba *phba = beiscsi_ep->phba;
-       struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
        struct be_mcc_wrb *wrb;
        struct tcp_connect_and_offload_out *ptcpcnct_out;
-       unsigned short status, extd_status;
        struct be_dma_mem nonemb_cmd;
-       unsigned int tag, wrb_num;
+       unsigned int tag;
        int ret = -ENOMEM;
 
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
@@ -1084,35 +1064,26 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
                pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                                    nonemb_cmd.va, nonemb_cmd.dma);
                return -EAGAIN;
-       } else {
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                        phba->ctrl.mcc_numtag[tag]);
        }
-       wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-       extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-       status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
-       if (status || extd_status) {
+
+       ret = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+       if (ret) {
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BS_%d : mgmt_open_connection Failed"
-                           " status = %d extd_status = %d\n",
-                           status, extd_status);
+                           "BS_%d : mgmt_open_connection Failed");
 
-               free_mcc_tag(&phba->ctrl, tag);
                pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                            nonemb_cmd.va, nonemb_cmd.dma);
                goto free_ep;
-       } else {
-               wrb = queue_get_wrb(mccq, wrb_num);
-               free_mcc_tag(&phba->ctrl, tag);
-
-               ptcpcnct_out = embedded_payload(wrb);
-               beiscsi_ep = ep->dd_data;
-               beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
-               beiscsi_ep->cid_vld = 1;
-               beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
-                           "BS_%d : mgmt_open_connection Success\n");
        }
+
+       ptcpcnct_out = embedded_payload(wrb);
+       beiscsi_ep = ep->dd_data;
+       beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle;
+       beiscsi_ep->cid_vld = 1;
+       beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+                   "BS_%d : mgmt_open_connection Success\n");
+
        pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                            nonemb_cmd.va, nonemb_cmd.dma);
        return 0;
@@ -1150,8 +1121,8 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
 
        if (phba->state != BE_ADAPTER_UP) {
                ret = -EBUSY;
-               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
-                           "BS_%d : The Adapter state is Not UP\n");
+               beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
+                           "BS_%d : The Adapter Port state is Down!!!\n");
                return ERR_PTR(ret);
        }
 
@@ -1216,11 +1187,9 @@ static int beiscsi_close_conn(struct  beiscsi_endpoint *beiscsi_ep, int flag)
                            beiscsi_ep->ep_cid);
 
                ret = -EAGAIN;
-       } else {
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                        phba->ctrl.mcc_numtag[tag]);
-               free_mcc_tag(&phba->ctrl, tag);
        }
+
+       ret = beiscsi_mccq_compl(phba, tag, NULL, NULL);
        return ret;
 }
 
@@ -1281,12 +1250,9 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
                            "BS_%d : mgmt_invalidate_connection Failed for cid=%d\n",
                            beiscsi_ep->ep_cid);
-       } else {
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                        phba->ctrl.mcc_numtag[tag]);
-               free_mcc_tag(&phba->ctrl, tag);
        }
 
+       beiscsi_mccq_compl(phba, tag, NULL, NULL);
        beiscsi_close_conn(beiscsi_ep, tcp_upload_flag);
        beiscsi_free_ep(beiscsi_ep);
        beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
index 8b826fc06bccd1355c81a6dc633d806e8a5d9601..38eab7232159dd7ec412e798a3a521cc8bab862f 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
index ff73f9500b01c43c3bdbbd210052fd651a8f3487..48d37dded8f16fbd64290aa599b187d54b9baef3 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -47,8 +47,6 @@
 static unsigned int be_iopoll_budget = 10;
 static unsigned int be_max_phys_size = 64;
 static unsigned int enable_msix = 1;
-static unsigned int gcrashmode = 0;
-static unsigned int num_hba = 0;
 
 MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
 MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
@@ -153,11 +151,54 @@ BEISCSI_RW_ATTR(log_enable, 0x00,
                "\t\t\t\tIO Path Events         : 0x10\n"
                "\t\t\t\tConfiguration Path     : 0x20\n");
 
+DEVICE_ATTR(beiscsi_drvr_ver, S_IRUGO, beiscsi_drvr_ver_disp, NULL);
+DEVICE_ATTR(beiscsi_adapter_family, S_IRUGO, beiscsi_adap_family_disp, NULL);
 struct device_attribute *beiscsi_attrs[] = {
        &dev_attr_beiscsi_log_enable,
+       &dev_attr_beiscsi_drvr_ver,
+       &dev_attr_beiscsi_adapter_family,
        NULL,
 };
 
+static char const *cqe_desc[] = {
+       "RESERVED_DESC",
+       "SOL_CMD_COMPLETE",
+       "SOL_CMD_KILLED_DATA_DIGEST_ERR",
+       "CXN_KILLED_PDU_SIZE_EXCEEDS_DSL",
+       "CXN_KILLED_BURST_LEN_MISMATCH",
+       "CXN_KILLED_AHS_RCVD",
+       "CXN_KILLED_HDR_DIGEST_ERR",
+       "CXN_KILLED_UNKNOWN_HDR",
+       "CXN_KILLED_STALE_ITT_TTT_RCVD",
+       "CXN_KILLED_INVALID_ITT_TTT_RCVD",
+       "CXN_KILLED_RST_RCVD",
+       "CXN_KILLED_TIMED_OUT",
+       "CXN_KILLED_RST_SENT",
+       "CXN_KILLED_FIN_RCVD",
+       "CXN_KILLED_BAD_UNSOL_PDU_RCVD",
+       "CXN_KILLED_BAD_WRB_INDEX_ERROR",
+       "CXN_KILLED_OVER_RUN_RESIDUAL",
+       "CXN_KILLED_UNDER_RUN_RESIDUAL",
+       "CMD_KILLED_INVALID_STATSN_RCVD",
+       "CMD_KILLED_INVALID_R2T_RCVD",
+       "CMD_CXN_KILLED_LUN_INVALID",
+       "CMD_CXN_KILLED_ICD_INVALID",
+       "CMD_CXN_KILLED_ITT_INVALID",
+       "CMD_CXN_KILLED_SEQ_OUTOFORDER",
+       "CMD_CXN_KILLED_INVALID_DATASN_RCVD",
+       "CXN_INVALIDATE_NOTIFY",
+       "CXN_INVALIDATE_INDEX_NOTIFY",
+       "CMD_INVALIDATED_NOTIFY",
+       "UNSOL_HDR_NOTIFY",
+       "UNSOL_DATA_NOTIFY",
+       "UNSOL_DATA_DIGEST_ERROR_NOTIFY",
+       "DRIVERMSG_NOTIFY",
+       "CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN",
+       "SOL_CMD_KILLED_DIF_ERR",
+       "CXN_KILLED_SYN_RCVD",
+       "CXN_KILLED_IMM_DATA_RCVD"
+};
+
 static int beiscsi_slave_configure(struct scsi_device *sdev)
 {
        blk_queue_max_segment_size(sdev->request_queue, 65536);
@@ -226,11 +267,9 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
                                    nonemb_cmd.va, nonemb_cmd.dma);
 
                return FAILED;
-       } else {
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                        phba->ctrl.mcc_numtag[tag]);
-               free_mcc_tag(&phba->ctrl, tag);
        }
+
+       beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
        pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                            nonemb_cmd.va, nonemb_cmd.dma);
        return iscsi_eh_abort(sc);
@@ -301,11 +340,9 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
                pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                                    nonemb_cmd.va, nonemb_cmd.dma);
                return FAILED;
-       } else {
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                        phba->ctrl.mcc_numtag[tag]);
-               free_mcc_tag(&phba->ctrl, tag);
        }
+
+       beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
        pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                            nonemb_cmd.va, nonemb_cmd.dma);
        return iscsi_eh_device_reset(sc);
@@ -482,6 +519,7 @@ static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = {
        { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
        { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
        { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) },
+       { PCI_DEVICE(ELX_VENDOR_ID, OC_SKH_ID1) },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
@@ -730,7 +768,7 @@ static irqreturn_t be_isr_mcc(int irq, void *dev_id)
                     resource_id) / 32] &
                     EQE_RESID_MASK) >> 16) == mcc->id) {
                        spin_lock_irqsave(&phba->isr_lock, flags);
-                       phba->todo_mcc_cq = 1;
+                       pbe_eq->todo_mcc_cq = true;
                        spin_unlock_irqrestore(&phba->isr_lock, flags);
                }
                AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
@@ -738,8 +776,8 @@ static irqreturn_t be_isr_mcc(int irq, void *dev_id)
                eqe = queue_tail_node(eq);
                num_eq_processed++;
        }
-       if (phba->todo_mcc_cq)
-               queue_work(phba->wq, &phba->work_cqs);
+       if (pbe_eq->todo_mcc_cq)
+               queue_work(phba->wq, &pbe_eq->work_cqs);
        if (num_eq_processed)
                hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1);
 
@@ -779,29 +817,26 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
                        eqe = queue_tail_node(eq);
                        num_eq_processed++;
                }
-               if (num_eq_processed)
-                       hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
-
-               return IRQ_HANDLED;
        } else {
                while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
                                                & EQE_VALID_MASK) {
                        spin_lock_irqsave(&phba->isr_lock, flags);
-                       phba->todo_cq = 1;
+                       pbe_eq->todo_cq = true;
                        spin_unlock_irqrestore(&phba->isr_lock, flags);
                        AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
                        queue_tail_inc(eq);
                        eqe = queue_tail_node(eq);
                        num_eq_processed++;
                }
-               if (phba->todo_cq)
-                       queue_work(phba->wq, &phba->work_cqs);
 
-               if (num_eq_processed)
-                       hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1);
-
-               return IRQ_HANDLED;
+               if (pbe_eq->todo_cq)
+                       queue_work(phba->wq, &pbe_eq->work_cqs);
        }
+
+       if (num_eq_processed)
+               hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1);
+
+       return IRQ_HANDLED;
 }
 
 /**
@@ -849,7 +884,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
                             resource_id) / 32] &
                             EQE_RESID_MASK) >> 16) == mcc->id) {
                                spin_lock_irqsave(&phba->isr_lock, flags);
-                               phba->todo_mcc_cq = 1;
+                               pbe_eq->todo_mcc_cq = true;
                                spin_unlock_irqrestore(&phba->isr_lock, flags);
                                num_mcceq_processed++;
                        } else {
@@ -862,8 +897,8 @@ static irqreturn_t be_isr(int irq, void *dev_id)
                        eqe = queue_tail_node(eq);
                }
                if (num_ioeq_processed || num_mcceq_processed) {
-                       if (phba->todo_mcc_cq)
-                               queue_work(phba->wq, &phba->work_cqs);
+                       if (pbe_eq->todo_mcc_cq)
+                               queue_work(phba->wq, &pbe_eq->work_cqs);
 
                        if ((num_mcceq_processed) && (!num_ioeq_processed))
                                hwi_ring_eq_db(phba, eq->id, 0,
@@ -886,11 +921,11 @@ static irqreturn_t be_isr(int irq, void *dev_id)
                             resource_id) / 32] &
                             EQE_RESID_MASK) >> 16) != cq->id) {
                                spin_lock_irqsave(&phba->isr_lock, flags);
-                               phba->todo_mcc_cq = 1;
+                               pbe_eq->todo_mcc_cq = true;
                                spin_unlock_irqrestore(&phba->isr_lock, flags);
                        } else {
                                spin_lock_irqsave(&phba->isr_lock, flags);
-                               phba->todo_cq = 1;
+                               pbe_eq->todo_cq = true;
                                spin_unlock_irqrestore(&phba->isr_lock, flags);
                        }
                        AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
@@ -898,8 +933,8 @@ static irqreturn_t be_isr(int irq, void *dev_id)
                        eqe = queue_tail_node(eq);
                        num_ioeq_processed++;
                }
-               if (phba->todo_cq || phba->todo_mcc_cq)
-                       queue_work(phba->wq, &phba->work_cqs);
+               if (pbe_eq->todo_cq || pbe_eq->todo_mcc_cq)
+                       queue_work(phba->wq, &pbe_eq->work_cqs);
 
                if (num_ioeq_processed) {
                        hwi_ring_eq_db(phba, eq->id, 0,
@@ -1211,7 +1246,8 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
 
 static void
 be_complete_io(struct beiscsi_conn *beiscsi_conn,
-              struct iscsi_task *task, struct sol_cqe *psol)
+               struct iscsi_task *task,
+               struct common_sol_cqe *csol_cqe)
 {
        struct beiscsi_io_task *io_task = task->dd_data;
        struct be_status_bhs *sts_bhs =
@@ -1221,20 +1257,14 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
        u32 resid = 0, exp_cmdsn, max_cmdsn;
        u8 rsp, status, flags;
 
-       exp_cmdsn = (psol->
-                       dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
-                       & SOL_EXP_CMD_SN_MASK);
-       max_cmdsn = ((psol->
-                       dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
-                       & SOL_EXP_CMD_SN_MASK) +
-                       ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
-                               / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
-       rsp = ((psol->dw[offsetof(struct amap_sol_cqe, i_resp) / 32]
-                                               & SOL_RESP_MASK) >> 16);
-       status = ((psol->dw[offsetof(struct amap_sol_cqe, i_sts) / 32]
-                                               & SOL_STS_MASK) >> 8);
-       flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
-                                       & SOL_FLAGS_MASK) >> 24) | 0x80;
+       exp_cmdsn = csol_cqe->exp_cmdsn;
+       max_cmdsn = (csol_cqe->exp_cmdsn +
+                    csol_cqe->cmd_wnd - 1);
+       rsp = csol_cqe->i_resp;
+       status = csol_cqe->i_sts;
+       flags = csol_cqe->i_flags;
+       resid = csol_cqe->res_cnt;
+
        if (!task->sc) {
                if (io_task->scsi_cmnd)
                        scsi_dma_unmap(io_task->scsi_cmnd);
@@ -1249,9 +1279,6 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
 
        /* bidi not initially supported */
        if (flags & (ISCSI_FLAG_CMD_UNDERFLOW | ISCSI_FLAG_CMD_OVERFLOW)) {
-               resid = (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) /
-                               32] & SOL_RES_CNT_MASK);
-
                if (!status && (flags & ISCSI_FLAG_CMD_OVERFLOW))
                        task->sc->result = DID_ERROR << 16;
 
@@ -1273,13 +1300,8 @@ be_complete_io(struct beiscsi_conn *beiscsi_conn,
                       min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE));
        }
 
-       if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) {
-               if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
-                                                       & SOL_RES_CNT_MASK)
-                        conn->rxdata_octets += (psol->
-                            dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
-                            & SOL_RES_CNT_MASK);
-       }
+       if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ)
+               conn->rxdata_octets += resid;
 unmap:
        scsi_dma_unmap(io_task->scsi_cmnd);
        iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn);
@@ -1287,7 +1309,8 @@ unmap:
 
 static void
 be_complete_logout(struct beiscsi_conn *beiscsi_conn,
-                  struct iscsi_task *task, struct sol_cqe *psol)
+                   struct iscsi_task *task,
+                   struct common_sol_cqe *csol_cqe)
 {
        struct iscsi_logout_rsp *hdr;
        struct beiscsi_io_task *io_task = task->dd_data;
@@ -1297,18 +1320,11 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
        hdr->opcode = ISCSI_OP_LOGOUT_RSP;
        hdr->t2wait = 5;
        hdr->t2retain = 0;
-       hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
-                                       & SOL_FLAGS_MASK) >> 24) | 0x80;
-       hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
-                                       32] & SOL_RESP_MASK);
-       hdr->exp_cmdsn = cpu_to_be32(psol->
-                       dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
-                                       & SOL_EXP_CMD_SN_MASK);
-       hdr->max_cmdsn = be32_to_cpu((psol->
-                        dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
-                                       & SOL_EXP_CMD_SN_MASK) +
-                       ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
-                                       / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+       hdr->flags = csol_cqe->i_flags;
+       hdr->response = csol_cqe->i_resp;
+       hdr->exp_cmdsn = csol_cqe->exp_cmdsn;
+       hdr->max_cmdsn = (csol_cqe->exp_cmdsn + csol_cqe->cmd_wnd - 1);
+
        hdr->dlength[0] = 0;
        hdr->dlength[1] = 0;
        hdr->dlength[2] = 0;
@@ -1319,7 +1335,8 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
 
 static void
 be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
-               struct iscsi_task *task, struct sol_cqe *psol)
+                struct iscsi_task *task,
+                struct common_sol_cqe *csol_cqe)
 {
        struct iscsi_tm_rsp *hdr;
        struct iscsi_conn *conn = beiscsi_conn->conn;
@@ -1327,16 +1344,12 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
 
        hdr = (struct iscsi_tm_rsp *)task->hdr;
        hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP;
-       hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
-                                       & SOL_FLAGS_MASK) >> 24) | 0x80;
-       hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
-                                       32] & SOL_RESP_MASK);
-       hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe,
-                                   i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
-       hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe,
-                       i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) +
-                       ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
-                       / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+       hdr->flags = csol_cqe->i_flags;
+       hdr->response = csol_cqe->i_resp;
+       hdr->exp_cmdsn = csol_cqe->exp_cmdsn;
+       hdr->max_cmdsn = (csol_cqe->exp_cmdsn +
+                         csol_cqe->cmd_wnd - 1);
+
        hdr->itt = io_task->libiscsi_itt;
        __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
 }
@@ -1352,15 +1365,24 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
        struct beiscsi_io_task *io_task;
        struct iscsi_conn *conn = beiscsi_conn->conn;
        struct iscsi_session *session = conn->session;
+       uint16_t wrb_index, cid;
 
        phwi_ctrlr = phba->phwi_ctrlr;
-       pwrb_context = &phwi_ctrlr->wrb_context[((psol->
-                               dw[offsetof(struct amap_sol_cqe, cid) / 32] &
-                               SOL_CID_MASK) >> 6) -
-                               phba->fw_config.iscsi_cid_start];
-       pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
-                               dw[offsetof(struct amap_sol_cqe, wrb_index) /
-                               32] & SOL_WRB_INDEX_MASK) >> 16)];
+       if (chip_skh_r(phba->pcidev)) {
+               wrb_index = AMAP_GET_BITS(struct amap_it_dmsg_cqe_v2,
+                                         wrb_idx, psol);
+               cid = AMAP_GET_BITS(struct amap_it_dmsg_cqe_v2,
+                                   cid, psol);
+       } else {
+               wrb_index = AMAP_GET_BITS(struct amap_it_dmsg_cqe,
+                                         wrb_idx, psol);
+               cid = AMAP_GET_BITS(struct amap_it_dmsg_cqe,
+                                   cid, psol);
+       }
+
+       pwrb_context = &phwi_ctrlr->wrb_context[
+                       cid - phba->fw_config.iscsi_cid_start];
+       pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index];
        task = pwrb_handle->pio_handle;
 
        io_task = task->dd_data;
@@ -1374,26 +1396,78 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
 
 static void
 be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn,
-                      struct iscsi_task *task, struct sol_cqe *psol)
+                       struct iscsi_task *task,
+                       struct common_sol_cqe *csol_cqe)
 {
        struct iscsi_nopin *hdr;
        struct iscsi_conn *conn = beiscsi_conn->conn;
        struct beiscsi_io_task *io_task = task->dd_data;
 
        hdr = (struct iscsi_nopin *)task->hdr;
-       hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
-                       & SOL_FLAGS_MASK) >> 24) | 0x80;
-       hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe,
-                                    i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
-       hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe,
-                       i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) +
-                       ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
-                       / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+       hdr->flags = csol_cqe->i_flags;
+       hdr->exp_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn);
+       hdr->max_cmdsn = be32_to_cpu(hdr->exp_cmdsn +
+                        csol_cqe->cmd_wnd - 1);
+
        hdr->opcode = ISCSI_OP_NOOP_IN;
        hdr->itt = io_task->libiscsi_itt;
        __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
 }
 
+static void adapter_get_sol_cqe(struct beiscsi_hba *phba,
+               struct sol_cqe *psol,
+               struct common_sol_cqe *csol_cqe)
+{
+       if (chip_skh_r(phba->pcidev)) {
+               csol_cqe->exp_cmdsn = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                                   i_exp_cmd_sn, psol);
+               csol_cqe->res_cnt = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                                 i_res_cnt, psol);
+               csol_cqe->wrb_index = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                                   wrb_index, psol);
+               csol_cqe->cid = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                             cid, psol);
+               csol_cqe->hw_sts = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                                hw_sts, psol);
+               csol_cqe->cmd_wnd = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                 i_cmd_wnd, psol);
+               if (AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                 cmd_cmpl, psol))
+                       csol_cqe->i_sts = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                                       i_sts, psol);
+               else
+                       csol_cqe->i_resp = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                                        i_sts, psol);
+               if (AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                 u, psol))
+                       csol_cqe->i_flags = ISCSI_FLAG_CMD_UNDERFLOW;
+
+               if (AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                 o, psol))
+                       csol_cqe->i_flags |= ISCSI_FLAG_CMD_OVERFLOW;
+       } else {
+               csol_cqe->exp_cmdsn = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                   i_exp_cmd_sn, psol);
+               csol_cqe->res_cnt = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                 i_res_cnt, psol);
+               csol_cqe->cmd_wnd = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                 i_cmd_wnd, psol);
+               csol_cqe->wrb_index = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                   wrb_index, psol);
+               csol_cqe->cid = AMAP_GET_BITS(struct amap_sol_cqe,
+                                             cid, psol);
+               csol_cqe->hw_sts = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                hw_sts, psol);
+               csol_cqe->i_resp = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                i_resp, psol);
+               csol_cqe->i_sts = AMAP_GET_BITS(struct amap_sol_cqe,
+                                               i_sts, psol);
+               csol_cqe->i_flags = AMAP_GET_BITS(struct amap_sol_cqe,
+                                                 i_flags, psol);
+       }
+}
+
+
 static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
                             struct beiscsi_hba *phba, struct sol_cqe *psol)
 {
@@ -1405,19 +1479,22 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
        unsigned int type;
        struct iscsi_conn *conn = beiscsi_conn->conn;
        struct iscsi_session *session = conn->session;
+       struct common_sol_cqe csol_cqe = {0};
 
        phwi_ctrlr = phba->phwi_ctrlr;
-       pwrb_context = &phwi_ctrlr->wrb_context[((psol->dw[offsetof
-                               (struct amap_sol_cqe, cid) / 32]
-                               & SOL_CID_MASK) >> 6) -
-                               phba->fw_config.iscsi_cid_start];
-       pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
-                               dw[offsetof(struct amap_sol_cqe, wrb_index) /
-                               32] & SOL_WRB_INDEX_MASK) >> 16)];
+
+       /* Copy the elements to a common structure */
+       adapter_get_sol_cqe(phba, psol, &csol_cqe);
+
+       pwrb_context = &phwi_ctrlr->wrb_context[
+                       csol_cqe.cid - phba->fw_config.iscsi_cid_start];
+
+       pwrb_handle = pwrb_context->pwrb_handle_basestd[
+                     csol_cqe.wrb_index];
+
        task = pwrb_handle->pio_handle;
        pwrb = pwrb_handle->pwrb;
-       type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] &
-                                WRB_TYPE_MASK) >> 28;
+       type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type;
 
        spin_lock_bh(&session->lock);
        switch (type) {
@@ -1425,17 +1502,16 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
        case HWH_TYPE_IO_RD:
                if ((task->hdr->opcode & ISCSI_OPCODE_MASK) ==
                     ISCSI_OP_NOOP_OUT)
-                       be_complete_nopin_resp(beiscsi_conn, task, psol);
+                       be_complete_nopin_resp(beiscsi_conn, task, &csol_cqe);
                else
-                       be_complete_io(beiscsi_conn, task, psol);
+                       be_complete_io(beiscsi_conn, task, &csol_cqe);
                break;
 
        case HWH_TYPE_LOGOUT:
                if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
-                       be_complete_logout(beiscsi_conn, task, psol);
+                       be_complete_logout(beiscsi_conn, task, &csol_cqe);
                else
-                       be_complete_tmf(beiscsi_conn, task, psol);
-
+                       be_complete_tmf(beiscsi_conn, task, &csol_cqe);
                break;
 
        case HWH_TYPE_LOGIN:
@@ -1446,7 +1522,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
                break;
 
        case HWH_TYPE_NOP:
-               be_complete_nopin_resp(beiscsi_conn, task, psol);
+               be_complete_nopin_resp(beiscsi_conn, task, &csol_cqe);
                break;
 
        default:
@@ -1454,10 +1530,8 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
                            "BM_%d : In hwi_complete_cmd, unknown type = %d"
                            "wrb_index 0x%x CID 0x%x\n", type,
-                           ((psol->dw[offsetof(struct amap_iscsi_wrb,
-                           type) / 32] & SOL_WRB_INDEX_MASK) >> 16),
-                           ((psol->dw[offsetof(struct amap_sol_cqe,
-                           cid) / 32] & SOL_CID_MASK) >> 6));
+                           csol_cqe.wrb_index,
+                           csol_cqe.cid);
                break;
        }
 
@@ -1485,13 +1559,26 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
        struct list_head *pbusy_list;
        struct async_pdu_handle *pasync_handle = NULL;
        unsigned char is_header = 0;
+       unsigned int index, dpl;
+
+       if (chip_skh_r(phba->pcidev)) {
+               dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2,
+                                   dpl, pdpdu_cqe);
+               index = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe_v2,
+                                     index, pdpdu_cqe);
+       } else {
+               dpl = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
+                                   dpl, pdpdu_cqe);
+               index = AMAP_GET_BITS(struct amap_i_t_dpdu_cqe,
+                                     index, pdpdu_cqe);
+       }
 
        phys_addr.u.a32.address_lo =
-           pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_lo) / 32] -
-           ((pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32]
-                                               & PDUCQE_DPL_MASK) >> 16);
+               (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+                                       db_addr_lo) / 32] - dpl);
        phys_addr.u.a32.address_hi =
-           pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_hi) / 32];
+               pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+                                      db_addr_hi) / 32];
 
        phys_addr.u.a64.address =
                        *((unsigned long long *)(&phys_addr.u.a64.address));
@@ -1501,14 +1588,12 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
        case UNSOL_HDR_NOTIFY:
                is_header = 1;
 
-               pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1,
-                       (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
-                       index) / 32] & PDUCQE_INDEX_MASK));
+                pbusy_list = hwi_get_async_busy_list(pasync_ctx,
+                                                     is_header, index);
                break;
        case UNSOL_DATA_NOTIFY:
-               pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe->
-                                       dw[offsetof(struct amap_i_t_dpdu_cqe,
-                                       index) / 32] & PDUCQE_INDEX_MASK));
+                pbusy_list = hwi_get_async_busy_list(pasync_ctx,
+                                                     is_header, index);
                break;
        default:
                pbusy_list = NULL;
@@ -1531,12 +1616,9 @@ hwi_get_async_handle(struct beiscsi_hba *phba,
        pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid -
                                             phba->fw_config.iscsi_cid_start;
        pasync_handle->is_header = is_header;
-       pasync_handle->buffer_len = ((pdpdu_cqe->
-                       dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32]
-                       & PDUCQE_DPL_MASK) >> 16);
+       pasync_handle->buffer_len = dpl;
+       *pcq_index = index;
 
-       *pcq_index = (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
-                       index) / 32] & PDUCQE_INDEX_MASK);
        return pasync_handle;
 }
 
@@ -1914,6 +1996,13 @@ static void  beiscsi_process_mcc_isr(struct beiscsi_hba *phba)
 
 }
 
+/**
+ * beiscsi_process_cq()- Process the Completion Queue
+ * @pbe_eq: Event Q on which the Completion has come
+ *
+ * return
+ *     Number of Completion Entries processed.
+ **/
 static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
 {
        struct be_queue_info *cq;
@@ -1935,12 +2024,24 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
               CQE_VALID_MASK) {
                be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
 
-               cid = ((sol->dw[offsetof(struct amap_sol_cqe, cid)/32] &
-                     CQE_CID_MASK) >> 6);
-               code = (sol->dw[offsetof(struct amap_sol_cqe, code)/32] &
-                      CQE_CODE_MASK);
-               ep = phba->ep_array[cid - phba->fw_config.iscsi_cid_start];
+                code = (sol->dw[offsetof(struct amap_sol_cqe, code) /
+                        32] & CQE_CODE_MASK);
+
+                /* Get the CID */
+               if (chip_skh_r(phba->pcidev)) {
+                       if ((code == DRIVERMSG_NOTIFY) ||
+                           (code == UNSOL_HDR_NOTIFY) ||
+                           (code == UNSOL_DATA_NOTIFY))
+                               cid = AMAP_GET_BITS(
+                                                   struct amap_i_t_dpdu_cqe_v2,
+                                                   cid, sol);
+                        else
+                                cid = AMAP_GET_BITS(struct amap_sol_cqe_v2,
+                                                    cid, sol);
+                  } else
+                        cid = AMAP_GET_BITS(struct amap_sol_cqe, cid, sol);
 
+               ep = phba->ep_array[cid - phba->fw_config.iscsi_cid_start];
                beiscsi_ep = ep->dd_data;
                beiscsi_conn = beiscsi_ep->conn;
 
@@ -1958,7 +2059,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                case DRIVERMSG_NOTIFY:
                        beiscsi_log(phba, KERN_INFO,
                                    BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                                   "BM_%d : Received DRIVERMSG_NOTIFY\n");
+                                   "BM_%d : Received %s[%d] on CID : %d\n",
+                                   cqe_desc[code], code, cid);
 
                        dmsg = (struct dmsg_cqe *)sol;
                        hwi_complete_drvr_msgs(beiscsi_conn, phba, sol);
@@ -1966,7 +2068,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                case UNSOL_HDR_NOTIFY:
                        beiscsi_log(phba, KERN_INFO,
                                    BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                                   "BM_%d : Received UNSOL_HDR_ NOTIFY\n");
+                                   "BM_%d : Received %s[%d] on CID : %d\n",
+                                   cqe_desc[code], code, cid);
 
                        hwi_process_default_pdu_ring(beiscsi_conn, phba,
                                             (struct i_t_dpdu_cqe *)sol);
@@ -1974,7 +2077,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                case UNSOL_DATA_NOTIFY:
                        beiscsi_log(phba, KERN_INFO,
                                    BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
-                                   "BM_%d : Received UNSOL_DATA_NOTIFY\n");
+                                   "BM_%d : Received %s[%d] on CID : %d\n",
+                                   cqe_desc[code], code, cid);
 
                        hwi_process_default_pdu_ring(beiscsi_conn, phba,
                                             (struct i_t_dpdu_cqe *)sol);
@@ -1984,8 +2088,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                case CXN_INVALIDATE_NOTIFY:
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                                   "BM_%d : Ignoring CQ Error notification for"
-                                   " cmd/cxn invalidate\n");
+                                   "BM_%d : Ignoring %s[%d] on CID : %d\n",
+                                   cqe_desc[code], code, cid);
                        break;
                case SOL_CMD_KILLED_DATA_DIGEST_ERR:
                case CMD_KILLED_INVALID_STATSN_RCVD:
@@ -1997,14 +2101,14 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                case CMD_CXN_KILLED_INVALID_DATASN_RCVD:
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
-                                   "BM_%d : CQ Error notification for cmd.. "
-                                   "code %d cid 0x%x\n", code, cid);
+                                   "BM_%d : Cmd Notification %s[%d] on CID : %d\n",
+                                   cqe_desc[code], code,  cid);
                        break;
                case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                                   "BM_%d : Digest error on def pdu ring,"
-                                   " dropping..\n");
+                                   "BM_%d :  Dropping %s[%d] on DPDU ring on CID : %d\n",
+                                   cqe_desc[code], code, cid);
                        hwi_flush_default_pdu_buffer(phba, beiscsi_conn,
                                             (struct i_t_dpdu_cqe *) sol);
                        break;
@@ -2017,6 +2121,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                case CXN_KILLED_INVALID_ITT_TTT_RCVD:
                case CXN_KILLED_TIMED_OUT:
                case CXN_KILLED_FIN_RCVD:
+               case CXN_KILLED_RST_SENT:
+               case CXN_KILLED_RST_RCVD:
                case CXN_KILLED_BAD_UNSOL_PDU_RCVD:
                case CXN_KILLED_BAD_WRB_INDEX_ERROR:
                case CXN_KILLED_OVER_RUN_RESIDUAL:
@@ -2024,19 +2130,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN:
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                                   "BM_%d : CQ Error %d, reset CID 0x%x...\n",
-                                   code, cid);
-                       if (beiscsi_conn)
-                               iscsi_conn_failure(beiscsi_conn->conn,
-                                                  ISCSI_ERR_CONN_FAILED);
-                       break;
-               case CXN_KILLED_RST_SENT:
-               case CXN_KILLED_RST_RCVD:
-                       beiscsi_log(phba, KERN_ERR,
-                                   BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                                   "BM_%d : CQ Error %d, reset"
-                                   "received/sent on CID 0x%x...\n",
-                                   code, cid);
+                                   "BM_%d : Event %s[%d] received on CID : %d\n",
+                                   cqe_desc[code], code, cid);
                        if (beiscsi_conn)
                                iscsi_conn_failure(beiscsi_conn->conn,
                                                   ISCSI_ERR_CONN_FAILED);
@@ -2044,8 +2139,8 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
                default:
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                                   "BM_%d : CQ Error Invalid code= %d "
-                                   "received on CID 0x%x...\n",
+                                   "BM_%d : Invalid CQE Event Received Code : %d"
+                                   "CID 0x%x...\n",
                                    code, cid);
                        break;
                }
@@ -2068,30 +2163,30 @@ void beiscsi_process_all_cqs(struct work_struct *work)
        unsigned long flags;
        struct hwi_controller *phwi_ctrlr;
        struct hwi_context_memory *phwi_context;
-       struct be_eq_obj *pbe_eq;
-       struct beiscsi_hba *phba =
-           container_of(work, struct beiscsi_hba, work_cqs);
+       struct beiscsi_hba *phba;
+       struct be_eq_obj *pbe_eq =
+           container_of(work, struct be_eq_obj, work_cqs);
 
+       phba = pbe_eq->phba;
        phwi_ctrlr = phba->phwi_ctrlr;
        phwi_context = phwi_ctrlr->phwi_ctxt;
-       if (phba->msix_enabled)
-               pbe_eq = &phwi_context->be_eq[phba->num_cpus];
-       else
-               pbe_eq = &phwi_context->be_eq[0];
 
-       if (phba->todo_mcc_cq) {
+       if (pbe_eq->todo_mcc_cq) {
                spin_lock_irqsave(&phba->isr_lock, flags);
-               phba->todo_mcc_cq = 0;
+               pbe_eq->todo_mcc_cq = false;
                spin_unlock_irqrestore(&phba->isr_lock, flags);
                beiscsi_process_mcc_isr(phba);
        }
 
-       if (phba->todo_cq) {
+       if (pbe_eq->todo_cq) {
                spin_lock_irqsave(&phba->isr_lock, flags);
-               phba->todo_cq = 0;
+               pbe_eq->todo_cq = false;
                spin_unlock_irqrestore(&phba->isr_lock, flags);
                beiscsi_process_cq(pbe_eq);
        }
+
+       /* rearm EQ for further interrupts */
+       hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
 }
 
 static int be_iopoll(struct blk_iopoll *iop, int budget)
@@ -2114,6 +2209,101 @@ static int be_iopoll(struct blk_iopoll *iop, int budget)
        return ret;
 }
 
+static void
+hwi_write_sgl_v2(struct iscsi_wrb *pwrb, struct scatterlist *sg,
+                 unsigned int num_sg, struct beiscsi_io_task *io_task)
+{
+       struct iscsi_sge *psgl;
+       unsigned int sg_len, index;
+       unsigned int sge_len = 0;
+       unsigned long long addr;
+       struct scatterlist *l_sg;
+       unsigned int offset;
+
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, iscsi_bhs_addr_lo, pwrb,
+                     io_task->bhs_pa.u.a32.address_lo);
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, iscsi_bhs_addr_hi, pwrb,
+                     io_task->bhs_pa.u.a32.address_hi);
+
+       l_sg = sg;
+       for (index = 0; (index < num_sg) && (index < 2); index++,
+                       sg = sg_next(sg)) {
+               if (index == 0) {
+                       sg_len = sg_dma_len(sg);
+                       addr = (u64) sg_dma_address(sg);
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                     sge0_addr_lo, pwrb,
+                                     lower_32_bits(addr));
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                     sge0_addr_hi, pwrb,
+                                     upper_32_bits(addr));
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                     sge0_len, pwrb,
+                                     sg_len);
+                       sge_len = sg_len;
+               } else {
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_r2t_offset,
+                                     pwrb, sge_len);
+                       sg_len = sg_dma_len(sg);
+                       addr = (u64) sg_dma_address(sg);
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                     sge1_addr_lo, pwrb,
+                                     lower_32_bits(addr));
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                     sge1_addr_hi, pwrb,
+                                     upper_32_bits(addr));
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                     sge1_len, pwrb,
+                                     sg_len);
+               }
+       }
+       psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag;
+       memset(psgl, 0, sizeof(*psgl) * BE2_SGE);
+
+       AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len - 2);
+
+       AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+                     io_task->bhs_pa.u.a32.address_hi);
+       AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+                     io_task->bhs_pa.u.a32.address_lo);
+
+       if (num_sg == 1) {
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge0_last, pwrb,
+                             1);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_last, pwrb,
+                             0);
+       } else if (num_sg == 2) {
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge0_last, pwrb,
+                             0);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_last, pwrb,
+                             1);
+       } else {
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge0_last, pwrb,
+                             0);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sge1_last, pwrb,
+                             0);
+       }
+
+       sg = l_sg;
+       psgl++;
+       psgl++;
+       offset = 0;
+       for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) {
+               sg_len = sg_dma_len(sg);
+               addr = (u64) sg_dma_address(sg);
+               AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+                             lower_32_bits(addr));
+               AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+                             upper_32_bits(addr));
+               AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, sg_len);
+               AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, offset);
+               AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0);
+               offset += sg_len;
+       }
+       psgl--;
+       AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
+}
+
 static void
 hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
              unsigned int num_sg, struct beiscsi_io_task *io_task)
@@ -2202,13 +2392,18 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
        AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
 }
 
+/**
+ * hwi_write_buffer()- Populate the WRB with task info
+ * @pwrb: ptr to the WRB entry
+ * @task: iscsi task which is to be executed
+ **/
 static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
 {
        struct iscsi_sge *psgl;
-       unsigned long long addr;
        struct beiscsi_io_task *io_task = task->dd_data;
        struct beiscsi_conn *beiscsi_conn = io_task->conn;
        struct beiscsi_hba *phba = beiscsi_conn->phba;
+       uint8_t dsp_value = 0;
 
        io_task->bhs_len = sizeof(struct be_nonio_bhs) - 2;
        AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb,
@@ -2217,26 +2412,38 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
                                io_task->bhs_pa.u.a32.address_hi);
 
        if (task->data) {
-               if (task->data_count) {
-                       AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
-                       addr = (u64) pci_map_single(phba->pcidev,
-                                                   task->data,
-                                                   task->data_count, 1);
-               } else {
-                       AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
-                       addr = 0;
-               }
+
+               /* Check for the data_count */
+               dsp_value = (task->data_count) ? 1 : 0;
+
+               if (chip_skh_r(phba->pcidev))
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, dsp,
+                                     pwrb, dsp_value);
+               else
+                       AMAP_SET_BITS(struct amap_iscsi_wrb, dsp,
+                                     pwrb, dsp_value);
+
+               /* Map addr only if there is data_count */
+               if (dsp_value) {
+                       io_task->mtask_addr = pci_map_single(phba->pcidev,
+                                                            task->data,
+                                                            task->data_count,
+                                                            PCI_DMA_TODEVICE);
+                       io_task->mtask_data_count = task->data_count;
+               } else
+                       io_task->mtask_addr = 0;
+
                AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
-                                               ((u32)(addr & 0xFFFFFFFF)));
+                             lower_32_bits(io_task->mtask_addr));
                AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
-                                               ((u32)(addr >> 32)));
+                             upper_32_bits(io_task->mtask_addr));
                AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
                                                task->data_count);
 
                AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 1);
        } else {
                AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
-               addr = 0;
+               io_task->mtask_addr = 0;
        }
 
        psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag;
@@ -2259,9 +2466,9 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
                psgl++;
                if (task->data) {
                        AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
-                                               ((u32)(addr & 0xFFFFFFFF)));
+                                     lower_32_bits(io_task->mtask_addr));
                        AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
-                                               ((u32)(addr >> 32)));
+                                     upper_32_bits(io_task->mtask_addr));
                }
                AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106);
        }
@@ -2843,7 +3050,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba,
        }
        return 0;
 create_eq_error:
-       for (i = 0; i < (phba->num_cpus + 1); i++) {
+       for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) {
                eq = &phwi_context->be_eq[i].q;
                mem = &eq->dma_mem;
                if (mem->va)
@@ -3268,15 +3475,31 @@ err:
        return -ENOMEM;
 }
 
-static int find_num_cpus(void)
+/**
+ * find_num_cpus()- Get the CPU online count
+ * @phba: ptr to priv structure
+ *
+ * CPU count is used for creating EQ.
+ **/
+static void find_num_cpus(struct beiscsi_hba *phba)
 {
        int  num_cpus = 0;
 
        num_cpus = num_online_cpus();
-       if (num_cpus >= MAX_CPUS)
-               num_cpus = MAX_CPUS - 1;
 
-       return num_cpus;
+       switch (phba->generation) {
+       case BE_GEN2:
+       case BE_GEN3:
+               phba->num_cpus = (num_cpus > BEISCSI_MAX_NUM_CPUS) ?
+                                 BEISCSI_MAX_NUM_CPUS : num_cpus;
+               break;
+       case BE_GEN4:
+               phba->num_cpus = (num_cpus > OC_SKH_MAX_NUM_CPUS) ?
+                                 OC_SKH_MAX_NUM_CPUS : num_cpus;
+               break;
+       default:
+               phba->num_cpus = 1;
+       }
 }
 
 static int hwi_init_port(struct beiscsi_hba *phba)
@@ -3644,12 +3867,9 @@ static void hwi_disable_intr(struct beiscsi_hba *phba)
 static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
 {
        struct be_cmd_get_session_resp *session_resp;
-       struct be_mcc_wrb *wrb;
        struct be_dma_mem nonemb_cmd;
-       unsigned int tag, wrb_num;
-       unsigned short status, extd_status;
+       unsigned int tag;
        unsigned int s_handle;
-       struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
        int ret = -ENOMEM;
 
        /* Get the session handle of the boot target */
@@ -3682,25 +3902,16 @@ static int beiscsi_get_boot_info(struct beiscsi_hba *phba)
                            " Failed\n");
 
                goto boot_freemem;
-       } else
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                        phba->ctrl.mcc_numtag[tag]);
+       }
 
-       wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-       extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-       status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
-       if (status || extd_status) {
+       ret = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd.va);
+       if (ret) {
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
-                           "BM_%d : beiscsi_get_session_info Failed"
-                           " status = %d extd_status = %d\n",
-                           status, extd_status);
-
-               free_mcc_tag(&phba->ctrl, tag);
+                           "BM_%d : beiscsi_get_session_info Failed");
                goto boot_freemem;
        }
-       wrb = queue_get_wrb(mccq, wrb_num);
-       free_mcc_tag(&phba->ctrl, tag);
+
        session_resp = nonemb_cmd.va ;
 
        memcpy(&phba->boot_sess, &session_resp->session_info,
@@ -3853,6 +4064,11 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba)
        kfree(phba->ep_array);
 }
 
+/**
+ * beiscsi_cleanup_task()- Free driver resources of the task
+ * @task: ptr to the iscsi task
+ *
+ **/
 static void beiscsi_cleanup_task(struct iscsi_task *task)
 {
        struct beiscsi_io_task *io_task = task->dd_data;
@@ -3900,6 +4116,13 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
                                spin_unlock(&phba->mgmt_sgl_lock);
                                io_task->psgl_handle = NULL;
                        }
+                       if (io_task->mtask_addr) {
+                               pci_unmap_single(phba->pcidev,
+                                                io_task->mtask_addr,
+                                                io_task->mtask_data_count,
+                                                PCI_DMA_TODEVICE);
+                               io_task->mtask_addr = 0;
+                       }
                }
        }
 }
@@ -3909,8 +4132,6 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
                           struct beiscsi_offload_params *params)
 {
        struct wrb_handle *pwrb_handle;
-       struct iscsi_target_context_update_wrb *pwrb = NULL;
-       struct be_mem_descriptor *mem_descr;
        struct beiscsi_hba *phba = beiscsi_conn->phba;
        struct iscsi_task *task = beiscsi_conn->task;
        struct iscsi_session *session = task->conn->session;
@@ -3927,67 +4148,16 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
 
        pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid -
                                       phba->fw_config.iscsi_cid_start));
-       pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb;
-       memset(pwrb, 0, sizeof(*pwrb));
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
-                     max_burst_length, pwrb, params->dw[offsetof
-                     (struct amap_beiscsi_offload_params,
-                     max_burst_length) / 32]);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
-                     max_send_data_segment_length, pwrb,
-                     params->dw[offsetof(struct amap_beiscsi_offload_params,
-                     max_send_data_segment_length) / 32]);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
-                     first_burst_length,
-                     pwrb,
-                     params->dw[offsetof(struct amap_beiscsi_offload_params,
-                     first_burst_length) / 32]);
-
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb,
-                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
-                     erl) / 32] & OFFLD_PARAMS_ERL));
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb,
-                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
-                     dde) / 32] & OFFLD_PARAMS_DDE) >> 2);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb,
-                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
-                     hde) / 32] & OFFLD_PARAMS_HDE) >> 3);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb,
-                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
-                     ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb,
-                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
-                      imd) / 32] & OFFLD_PARAMS_IMD) >> 5);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn,
-                     pwrb,
-                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
-                     exp_statsn) / 32] + 1));
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb,
-                     0x7);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx,
-                     pwrb, pwrb_handle->wrb_index);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb,
-                     pwrb, pwrb_handle->nxt_wrb_index);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
-                       session_state, pwrb, 0);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack,
-                     pwrb, 1);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq,
-                     pwrb, 0);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb,
-                     0);
 
-       mem_descr = phba->init_mem;
-       mem_descr += ISCSI_MEM_GLOBAL_HEADER;
-
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
-                       pad_buffer_addr_hi, pwrb,
-                     mem_descr->mem_array[0].bus_address.u.a32.address_hi);
-       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
-                       pad_buffer_addr_lo, pwrb,
-                     mem_descr->mem_array[0].bus_address.u.a32.address_lo);
+       /* Check for the adapter family */
+       if (chip_skh_r(phba->pcidev))
+               beiscsi_offload_cxn_v2(params, pwrb_handle);
+       else
+               beiscsi_offload_cxn_v0(params, pwrb_handle,
+                                      phba->init_mem);
 
-       be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb));
+       be_dws_le_to_cpu(pwrb_handle->pwrb,
+                        sizeof(struct iscsi_target_context_update_wrb));
 
        doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
        doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK)
@@ -4044,13 +4214,25 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
                spin_lock(&phba->io_sgl_lock);
                io_task->psgl_handle = alloc_io_sgl_handle(phba);
                spin_unlock(&phba->io_sgl_lock);
-               if (!io_task->psgl_handle)
+               if (!io_task->psgl_handle) {
+                       beiscsi_log(phba, KERN_ERR,
+                                   BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
+                                   "BM_%d : Alloc of IO_SGL_ICD Failed"
+                                   "for the CID : %d\n",
+                                   beiscsi_conn->beiscsi_conn_cid);
                        goto free_hndls;
+               }
                io_task->pwrb_handle = alloc_wrb_handle(phba,
                                        beiscsi_conn->beiscsi_conn_cid -
                                        phba->fw_config.iscsi_cid_start);
-               if (!io_task->pwrb_handle)
+               if (!io_task->pwrb_handle) {
+                       beiscsi_log(phba, KERN_ERR,
+                                   BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
+                                   "BM_%d : Alloc of WRB_HANDLE Failed"
+                                   "for the CID : %d\n",
+                                   beiscsi_conn->beiscsi_conn_cid);
                        goto free_io_hndls;
+               }
        } else {
                io_task->scsi_cmnd = NULL;
                if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
@@ -4059,8 +4241,16 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
                                io_task->psgl_handle = (struct sgl_handle *)
                                                alloc_mgmt_sgl_handle(phba);
                                spin_unlock(&phba->mgmt_sgl_lock);
-                               if (!io_task->psgl_handle)
+                               if (!io_task->psgl_handle) {
+                                       beiscsi_log(phba, KERN_ERR,
+                                                   BEISCSI_LOG_IO |
+                                                   BEISCSI_LOG_CONFIG,
+                                                   "BM_%d : Alloc of MGMT_SGL_ICD Failed"
+                                                   "for the CID : %d\n",
+                                                   beiscsi_conn->
+                                                   beiscsi_conn_cid);
                                        goto free_hndls;
+                               }
 
                                beiscsi_conn->login_in_progress = 1;
                                beiscsi_conn->plogin_sgl_handle =
@@ -4069,8 +4259,16 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
                                        alloc_wrb_handle(phba,
                                        beiscsi_conn->beiscsi_conn_cid -
                                        phba->fw_config.iscsi_cid_start);
-                               if (!io_task->pwrb_handle)
-                                       goto free_io_hndls;
+                               if (!io_task->pwrb_handle) {
+                                       beiscsi_log(phba, KERN_ERR,
+                                                   BEISCSI_LOG_IO |
+                                                   BEISCSI_LOG_CONFIG,
+                                                   "BM_%d : Alloc of WRB_HANDLE Failed"
+                                                   "for the CID : %d\n",
+                                                   beiscsi_conn->
+                                                   beiscsi_conn_cid);
+                                       goto free_mgmt_hndls;
+                               }
                                beiscsi_conn->plogin_wrb_handle =
                                                        io_task->pwrb_handle;
 
@@ -4085,14 +4283,28 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
                        spin_lock(&phba->mgmt_sgl_lock);
                        io_task->psgl_handle = alloc_mgmt_sgl_handle(phba);
                        spin_unlock(&phba->mgmt_sgl_lock);
-                       if (!io_task->psgl_handle)
+                       if (!io_task->psgl_handle) {
+                               beiscsi_log(phba, KERN_ERR,
+                                           BEISCSI_LOG_IO |
+                                           BEISCSI_LOG_CONFIG,
+                                           "BM_%d : Alloc of MGMT_SGL_ICD Failed"
+                                           "for the CID : %d\n",
+                                           beiscsi_conn->
+                                           beiscsi_conn_cid);
                                goto free_hndls;
+                       }
                        io_task->pwrb_handle =
                                        alloc_wrb_handle(phba,
                                        beiscsi_conn->beiscsi_conn_cid -
                                        phba->fw_config.iscsi_cid_start);
-                       if (!io_task->pwrb_handle)
+                       if (!io_task->pwrb_handle) {
+                               beiscsi_log(phba, KERN_ERR,
+                                           BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
+                                           "BM_%d : Alloc of WRB_HANDLE Failed"
+                                           "for the CID : %d\n",
+                                           beiscsi_conn->beiscsi_conn_cid);
                                goto free_mgmt_hndls;
+                       }
 
                }
        }
@@ -4124,11 +4336,64 @@ free_hndls:
        pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
                      io_task->bhs_pa.u.a64.address);
        io_task->cmd_bhs = NULL;
-       beiscsi_log(phba, KERN_ERR,
-                   BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
-                   "BM_%d : Alloc of SGL_ICD Failed\n");
        return -ENOMEM;
 }
+int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg,
+                      unsigned int num_sg, unsigned int xferlen,
+                      unsigned int writedir)
+{
+
+       struct beiscsi_io_task *io_task = task->dd_data;
+       struct iscsi_conn *conn = task->conn;
+       struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+       struct beiscsi_hba *phba = beiscsi_conn->phba;
+       struct iscsi_wrb *pwrb = NULL;
+       unsigned int doorbell = 0;
+
+       pwrb = io_task->pwrb_handle->pwrb;
+       memset(pwrb, 0, sizeof(*pwrb));
+
+       io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0;
+       io_task->bhs_len = sizeof(struct be_cmd_bhs);
+
+       if (writedir) {
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, type, pwrb,
+                             INI_WR_CMD);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, dsp, pwrb, 1);
+       } else {
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, type, pwrb,
+                             INI_RD_CMD);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, dsp, pwrb, 0);
+       }
+
+       io_task->wrb_type = AMAP_GET_BITS(struct amap_iscsi_wrb_v2,
+                                         type, pwrb);
+
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, lun, pwrb,
+                     cpu_to_be16(*(unsigned short *)
+                     &io_task->cmd_bhs->iscsi_hdr.lun));
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb, xferlen);
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, wrb_idx, pwrb,
+                     io_task->pwrb_handle->wrb_index);
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb,
+                     be32_to_cpu(task->cmdsn));
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sgl_idx, pwrb,
+                     io_task->psgl_handle->sgl_index);
+
+       hwi_write_sgl_v2(pwrb, sg, num_sg, io_task);
+       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb,
+                     io_task->pwrb_handle->nxt_wrb_index);
+
+       be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
+
+       doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
+       doorbell |= (io_task->pwrb_handle->wrb_index &
+                    DB_DEF_PDU_WRB_INDEX_MASK) <<
+                    DB_DEF_PDU_WRB_INDEX_SHIFT;
+       doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
+       iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
+       return 0;
+}
 
 static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
                          unsigned int num_sg, unsigned int xferlen,
@@ -4156,6 +4421,9 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
                AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
        }
 
+       io_task->wrb_type = AMAP_GET_BITS(struct amap_iscsi_wrb,
+                                         type, pwrb);
+
        AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb,
                      cpu_to_be16(*(unsigned short *)
                                  &io_task->cmd_bhs->iscsi_hdr.lun));
@@ -4191,55 +4459,75 @@ static int beiscsi_mtask(struct iscsi_task *task)
        struct iscsi_wrb *pwrb = NULL;
        unsigned int doorbell = 0;
        unsigned int cid;
+       unsigned int pwrb_typeoffset = 0;
 
        cid = beiscsi_conn->beiscsi_conn_cid;
        pwrb = io_task->pwrb_handle->pwrb;
        memset(pwrb, 0, sizeof(*pwrb));
-       AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
-                     be32_to_cpu(task->cmdsn));
-       AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
-                     io_task->pwrb_handle->wrb_index);
-       AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
-                     io_task->psgl_handle->sgl_index);
+
+       if (chip_skh_r(phba->pcidev)) {
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb,
+                             be32_to_cpu(task->cmdsn));
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, wrb_idx, pwrb,
+                             io_task->pwrb_handle->wrb_index);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, sgl_idx, pwrb,
+                             io_task->psgl_handle->sgl_index);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb,
+                             task->data_count);
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb,
+                             io_task->pwrb_handle->nxt_wrb_index);
+               pwrb_typeoffset = SKH_WRB_TYPE_OFFSET;
+       } else {
+               AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
+                             be32_to_cpu(task->cmdsn));
+               AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
+                             io_task->pwrb_handle->wrb_index);
+               AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
+                             io_task->psgl_handle->sgl_index);
+               AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb,
+                             task->data_count);
+               AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
+                             io_task->pwrb_handle->nxt_wrb_index);
+               pwrb_typeoffset = BE_WRB_TYPE_OFFSET;
+       }
+
 
        switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
        case ISCSI_OP_LOGIN:
-               AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
-                             TGT_DM_CMD);
-               AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
                AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1);
+               ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset);
                hwi_write_buffer(pwrb, task);
                break;
        case ISCSI_OP_NOOP_OUT:
                if (task->hdr->ttt != ISCSI_RESERVED_TAG) {
-                       AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
-                                     TGT_DM_CMD);
-                       AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt,
-                                     pwrb, 0);
-                       AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1);
+                       ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset);
+                       if (chip_skh_r(phba->pcidev))
+                               AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                             dmsg, pwrb, 1);
+                       else
+                               AMAP_SET_BITS(struct amap_iscsi_wrb,
+                                             dmsg, pwrb, 1);
                } else {
-                       AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
-                                     INI_RD_CMD);
-                       AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+                       ADAPTER_SET_WRB_TYPE(pwrb, INI_RD_CMD, pwrb_typeoffset);
+                       if (chip_skh_r(phba->pcidev))
+                               AMAP_SET_BITS(struct amap_iscsi_wrb_v2,
+                                             dmsg, pwrb, 0);
+                       else
+                               AMAP_SET_BITS(struct amap_iscsi_wrb,
+                                             dmsg, pwrb, 0);
                }
                hwi_write_buffer(pwrb, task);
                break;
        case ISCSI_OP_TEXT:
-               AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
-                             TGT_DM_CMD);
-               AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+               ADAPTER_SET_WRB_TYPE(pwrb, TGT_DM_CMD, pwrb_typeoffset);
                hwi_write_buffer(pwrb, task);
                break;
        case ISCSI_OP_SCSI_TMFUNC:
-               AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
-                             INI_TMF_CMD);
-               AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+               ADAPTER_SET_WRB_TYPE(pwrb, INI_TMF_CMD, pwrb_typeoffset);
                hwi_write_buffer(pwrb, task);
                break;
        case ISCSI_OP_LOGOUT:
-               AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
-               AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
-                             HWH_TYPE_LOGOUT);
+               ADAPTER_SET_WRB_TYPE(pwrb, HWH_TYPE_LOGOUT, pwrb_typeoffset);
                hwi_write_buffer(pwrb, task);
                break;
 
@@ -4251,11 +4539,10 @@ static int beiscsi_mtask(struct iscsi_task *task)
                return -EINVAL;
        }
 
-       AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb,
-                     task->data_count);
-       AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
-                     io_task->pwrb_handle->nxt_wrb_index);
-       be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
+       /* Set the task type */
+       io_task->wrb_type = (chip_skh_r(phba->pcidev)) ?
+               AMAP_GET_BITS(struct amap_iscsi_wrb_v2, type, pwrb) :
+               AMAP_GET_BITS(struct amap_iscsi_wrb, type, pwrb);
 
        doorbell |= cid & DB_WRB_POST_CID_MASK;
        doorbell |= (io_task->pwrb_handle->wrb_index &
@@ -4269,10 +4556,13 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
 {
        struct beiscsi_io_task *io_task = task->dd_data;
        struct scsi_cmnd *sc = task->sc;
+       struct beiscsi_hba *phba = NULL;
        struct scatterlist *sg;
        int num_sg;
        unsigned int  writedir = 0, xferlen = 0;
 
+       phba = ((struct beiscsi_conn *)task->conn->dd_data)->phba;
+
        if (!sc)
                return beiscsi_mtask(task);
 
@@ -4295,7 +4585,7 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
         else
                writedir = 0;
 
-       return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
+        return phba->iotask_fn(task, sg, num_sg, xferlen, writedir);
 }
 
 /**
@@ -4326,20 +4616,24 @@ static int beiscsi_bsg_request(struct bsg_job *job)
                        beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
                                    "BM_%d : Failed to allocate memory for "
                                    "beiscsi_bsg_request\n");
-                       return -EIO;
+                       return -ENOMEM;
                }
                tag = mgmt_vendor_specific_fw_cmd(&phba->ctrl, phba, job,
                                                  &nonemb_cmd);
                if (!tag) {
                        beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
-                                   "BM_%d : be_cmd_get_mac_addr Failed\n");
+                                   "BM_%d : MBX Tag Allocation Failed\n");
 
                        pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
                                            nonemb_cmd.va, nonemb_cmd.dma);
                        return -EAGAIN;
-               } else
-                       wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                                phba->ctrl.mcc_numtag[tag]);
+               }
+
+               rc = wait_event_interruptible_timeout(
+                                       phba->ctrl.mcc_wait[tag],
+                                       phba->ctrl.mcc_numtag[tag],
+                                       msecs_to_jiffies(
+                                       BEISCSI_HOST_MBX_TIMEOUT));
                extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
                status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
                free_mcc_tag(&phba->ctrl, tag);
@@ -4356,11 +4650,13 @@ static int beiscsi_bsg_request(struct bsg_job *job)
                                    nonemb_cmd.va, nonemb_cmd.dma);
                if (status || extd_status) {
                        beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
-                                   "BM_%d : be_cmd_get_mac_addr Failed"
+                                   "BM_%d : MBX Cmd Failed"
                                    " status = %d extd_status = %d\n",
                                    status, extd_status);
 
                        return -EIO;
+               } else {
+                       rc = 0;
                }
                break;
 
@@ -4380,14 +4676,18 @@ void beiscsi_hba_attrs_init(struct beiscsi_hba *phba)
        beiscsi_log_enable_init(phba, beiscsi_log_enable);
 }
 
+/*
+ * beiscsi_quiesce()- Cleanup Driver resources
+ * @phba: Instance Priv structure
+ *
+ * Free the OS and HW resources held by the driver
+ **/
 static void beiscsi_quiesce(struct beiscsi_hba *phba)
 {
        struct hwi_controller *phwi_ctrlr;
        struct hwi_context_memory *phwi_context;
        struct be_eq_obj *pbe_eq;
        unsigned int i, msix_vec;
-       u8 *real_offset = 0;
-       u32 value = 0;
 
        phwi_ctrlr = phba->phwi_ctrlr;
        phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -4411,19 +4711,14 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba)
 
        beiscsi_clean_port(phba);
        beiscsi_free_mem(phba);
-       real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
 
-       value = readl((void *)real_offset);
-
-       if (value & 0x00010000) {
-               value &= 0xfffeffff;
-               writel(value, (void *)real_offset);
-       }
        beiscsi_unmap_pci_function(phba);
        pci_free_consistent(phba->pcidev,
                            phba->ctrl.mbox_mem_alloced.size,
                            phba->ctrl.mbox_mem_alloced.va,
                            phba->ctrl.mbox_mem_alloced.dma);
+
+       cancel_delayed_work_sync(&phba->beiscsi_hw_check_task);
 }
 
 static void beiscsi_remove(struct pci_dev *pcidev)
@@ -4476,6 +4771,25 @@ static void beiscsi_msix_enable(struct beiscsi_hba *phba)
        return;
 }
 
+/*
+ * beiscsi_hw_health_check()- Check adapter health
+ * @work: work item to check HW health
+ *
+ * Check if adapter in an unrecoverable state or not.
+ **/
+static void
+beiscsi_hw_health_check(struct work_struct *work)
+{
+       struct beiscsi_hba *phba =
+               container_of(work, struct beiscsi_hba,
+                            beiscsi_hw_check_task.work);
+
+       beiscsi_ue_detect(phba);
+
+       schedule_delayed_work(&phba->beiscsi_hw_check_task,
+                             msecs_to_jiffies(1000));
+}
+
 static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                                const struct pci_device_id *id)
 {
@@ -4483,9 +4797,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
        struct hwi_controller *phwi_ctrlr;
        struct hwi_context_memory *phwi_context;
        struct be_eq_obj *pbe_eq;
-       int ret, num_cpus, i;
-       u8 *real_offset = 0;
-       u32 value = 0;
+       int ret, i;
 
        ret = beiscsi_enable_pci(pcidev);
        if (ret < 0) {
@@ -4504,25 +4816,33 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
        /* Initialize Driver configuration Paramters */
        beiscsi_hba_attrs_init(phba);
 
+       phba->fw_timeout = false;
+
+
        switch (pcidev->device) {
        case BE_DEVICE_ID1:
        case OC_DEVICE_ID1:
        case OC_DEVICE_ID2:
                phba->generation = BE_GEN2;
+               phba->iotask_fn = beiscsi_iotask;
                break;
        case BE_DEVICE_ID2:
        case OC_DEVICE_ID3:
                phba->generation = BE_GEN3;
+               phba->iotask_fn = beiscsi_iotask;
                break;
+       case OC_SKH_ID1:
+               phba->generation = BE_GEN4;
+               phba->iotask_fn = beiscsi_iotask_v2;
        default:
                phba->generation = 0;
        }
 
        if (enable_msix)
-               num_cpus = find_num_cpus();
+               find_num_cpus(phba);
        else
-               num_cpus = 1;
-       phba->num_cpus = num_cpus;
+               phba->num_cpus = 1;
+
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
                    "BM_%d : num_cpus = %d\n",
                    phba->num_cpus);
@@ -4540,31 +4860,18 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                goto hba_free;
        }
 
-       if (!num_hba) {
-               real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
-               value = readl((void *)real_offset);
-               if (value & 0x00010000) {
-                       gcrashmode++;
-                       beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                                   "BM_%d : Loading Driver in crashdump mode\n");
-                       ret = beiscsi_cmd_reset_function(phba);
-                       if (ret) {
-                               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                                           "BM_%d : Reset Failed. Aborting Crashdump\n");
-                               goto hba_free;
-                       }
-                       ret = be_chk_reset_complete(phba);
-                       if (ret) {
-                               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                                           "BM_%d : Failed to get out of reset."
-                                           "Aborting Crashdump\n");
-                               goto hba_free;
-                       }
-               } else {
-                       value |= 0x00010000;
-                       writel(value, (void *)real_offset);
-                       num_hba++;
-               }
+       ret = beiscsi_cmd_reset_function(phba);
+       if (ret) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                           "BM_%d : Reset Failed. Aborting Crashdump\n");
+               goto hba_free;
+       }
+       ret = be_chk_reset_complete(phba);
+       if (ret) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                           "BM_%d : Failed to get out of reset."
+                           "Aborting Crashdump\n");
+               goto hba_free;
        }
 
        spin_lock_init(&phba->io_sgl_lock);
@@ -4596,7 +4903,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
 
        phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0;
 
-       snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u",
+       snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_%02x_wq",
                 phba->shost->host_no);
        phba->wq = alloc_workqueue(phba->wq_name, WQ_MEM_RECLAIM, 1);
        if (!phba->wq) {
@@ -4606,10 +4913,12 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                goto free_twq;
        }
 
-       INIT_WORK(&phba->work_cqs, beiscsi_process_all_cqs);
+       INIT_DELAYED_WORK(&phba->beiscsi_hw_check_task,
+                         beiscsi_hw_health_check);
 
        phwi_ctrlr = phba->phwi_ctrlr;
        phwi_context = phwi_ctrlr->phwi_ctxt;
+
        if (blk_iopoll_enabled) {
                for (i = 0; i < phba->num_cpus; i++) {
                        pbe_eq = &phwi_context->be_eq[i];
@@ -4617,7 +4926,25 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                                        be_iopoll);
                        blk_iopoll_enable(&pbe_eq->iopoll);
                }
+
+               i = (phba->msix_enabled) ? i : 0;
+               /* Work item for MCC handling */
+               pbe_eq = &phwi_context->be_eq[i];
+               INIT_WORK(&pbe_eq->work_cqs, beiscsi_process_all_cqs);
+       } else {
+               if (phba->msix_enabled) {
+                       for (i = 0; i <= phba->num_cpus; i++) {
+                               pbe_eq = &phwi_context->be_eq[i];
+                               INIT_WORK(&pbe_eq->work_cqs,
+                                         beiscsi_process_all_cqs);
+                       }
+               } else {
+                               pbe_eq = &phwi_context->be_eq[0];
+                               INIT_WORK(&pbe_eq->work_cqs,
+                                         beiscsi_process_all_cqs);
+                       }
        }
+
        ret = beiscsi_init_irqs(phba);
        if (ret < 0) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -4637,6 +4964,9 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                            "iSCSI boot info.\n");
 
        beiscsi_create_def_ifaces(phba);
+       schedule_delayed_work(&phba->beiscsi_hw_check_task,
+                             msecs_to_jiffies(1000));
+
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
                    "\n\n\n BM_%d : SUCCESS - DRIVER LOADED\n\n\n");
        return 0;
@@ -4652,15 +4982,6 @@ free_twq:
        beiscsi_clean_port(phba);
        beiscsi_free_mem(phba);
 free_port:
-       real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE;
-
-       value = readl((void *)real_offset);
-
-       if (value & 0x00010000) {
-               value &= 0xfffeffff;
-               writel(value, (void *)real_offset);
-       }
-
        pci_free_consistent(phba->pcidev,
                            phba->ctrl.mbox_mem_alloced.size,
                            phba->ctrl.mbox_mem_alloced.va,
index b8912263ef4e739de691727269a5c58761dfba3a..5946577d79d6579f6f4fa4ff8c8eaf156caf9ac5 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
 
 #include "be.h"
 #define DRV_NAME               "be2iscsi"
-#define BUILD_STR              "4.4.58.0"
+#define BUILD_STR              "10.0.272.0"
 #define BE_NAME                        "Emulex OneConnect" \
                                "Open-iSCSI Driver version" BUILD_STR
 #define DRV_DESC               BE_NAME " " "Driver"
 
 #define BE_VENDOR_ID           0x19A2
+#define ELX_VENDOR_ID          0x10DF
 /* DEVICE ID's for BE2 */
 #define BE_DEVICE_ID1          0x212
 #define OC_DEVICE_ID1          0x702
@@ -51,6 +52,9 @@
 #define BE_DEVICE_ID2          0x222
 #define OC_DEVICE_ID3          0x712
 
+/* DEVICE ID for SKH */
+#define OC_SKH_ID1             0x722
+
 #define BE2_IO_DEPTH           1024
 #define BE2_MAX_SESSIONS       256
 #define BE2_CMDS_PER_CXN       128
 #define BE2_DEFPDU_HDR_SZ      64
 #define BE2_DEFPDU_DATA_SZ     8192
 
-#define MAX_CPUS               31
+#define MAX_CPUS               64
+#define BEISCSI_MAX_NUM_CPUS   7
+#define OC_SKH_MAX_NUM_CPUS    63
+
+
 #define BEISCSI_SGLIST_ELEMENTS        30
 
 #define BEISCSI_CMD_PER_LUN    128     /* scsi_host->cmd_per_lun */
@@ -257,6 +265,7 @@ struct invalidate_command_table {
        unsigned short cid;
 } __packed;
 
+#define chip_skh_r(pdev)       (pdev->device == OC_SKH_ID1)
 struct beiscsi_hba {
        struct hba_parameters params;
        struct hwi_controller *phwi_ctrlr;
@@ -270,12 +279,11 @@ struct beiscsi_hba {
        struct be_bus_address pci_pa;   /* CSR */
        /* PCI representation of our HBA */
        struct pci_dev *pcidev;
-       unsigned int state;
        unsigned short asic_revision;
        unsigned int num_cpus;
        unsigned int nxt_cqid;
-       struct msix_entry msix_entries[MAX_CPUS + 1];
-       char *msi_name[MAX_CPUS + 1];
+       struct msix_entry msix_entries[MAX_CPUS];
+       char *msi_name[MAX_CPUS];
        bool msix_enabled;
        struct be_mem_descriptor *init_mem;
 
@@ -325,12 +333,14 @@ struct beiscsi_hba {
                spinlock_t cid_lock;
        } fw_config;
 
+       unsigned int state;
+       bool fw_timeout;
+       bool ue_detected;
+       struct delayed_work beiscsi_hw_check_task;
+
        u8 mac_address[ETH_ALEN];
-       unsigned short todo_cq;
-       unsigned short todo_mcc_cq;
        char wq_name[20];
        struct workqueue_struct *wq;    /* The actuak work queue */
-       struct work_struct work_cqs;    /* The work being queued */
        struct be_ctrl_info ctrl;
        unsigned int generation;
        unsigned int interface_handle;
@@ -338,7 +348,10 @@ struct beiscsi_hba {
        struct invalidate_command_table inv_tbl[128];
 
        unsigned int attr_log_enable;
-
+       int (*iotask_fn)(struct iscsi_task *,
+                       struct scatterlist *sg,
+                       uint32_t num_sg, uint32_t xferlen,
+                       uint32_t writedir);
 };
 
 struct beiscsi_session {
@@ -410,6 +423,9 @@ struct beiscsi_io_task {
        struct be_cmd_bhs *cmd_bhs;
        struct be_bus_address bhs_pa;
        unsigned short bhs_len;
+       dma_addr_t mtask_addr;
+       uint32_t mtask_data_count;
+       uint8_t wrb_type;
 };
 
 struct be_nonio_bhs {
@@ -457,6 +473,9 @@ struct beiscsi_offload_params {
 #define OFFLD_PARAMS_HDE       0x00000008
 #define OFFLD_PARAMS_IR2T      0x00000010
 #define OFFLD_PARAMS_IMD       0x00000020
+#define OFFLD_PARAMS_DATA_SEQ_INORDER   0x00000040
+#define OFFLD_PARAMS_PDU_SEQ_INORDER    0x00000080
+#define OFFLD_PARAMS_MAX_R2T 0x00FFFF00
 
 /**
  * Pseudo amap definition in which each bit of the actual structure is defined
@@ -471,7 +490,10 @@ struct amap_beiscsi_offload_params {
        u8 hde[1];
        u8 ir2t[1];
        u8 imd[1];
-       u8 pad[26];
+       u8 data_seq_inorder[1];
+       u8 pdu_seq_inorder[1];
+       u8 max_r2t[16];
+       u8 pad[8];
        u8 exp_statsn[32];
 };
 
@@ -569,6 +591,20 @@ struct amap_i_t_dpdu_cqe {
        u8 valid;
 } __packed;
 
+struct amap_i_t_dpdu_cqe_v2 {
+       u8 db_addr_hi[32];  /* DWORD 0 */
+       u8 db_addr_lo[32];  /* DWORD 1 */
+       u8 code[6]; /* DWORD 2 */
+       u8 num_cons; /* DWORD 2*/
+       u8 rsvd0[8]; /* DWORD 2 */
+       u8 dpl[17]; /* DWORD 2 */
+       u8 index[16]; /* DWORD 3 */
+       u8 cid[13]; /* DWORD 3 */
+       u8 rsvd1; /* DWORD 3 */
+       u8 final; /* DWORD 3 */
+       u8 valid; /* DWORD 3 */
+} __packed;
+
 #define CQE_VALID_MASK 0x80000000
 #define CQE_CODE_MASK  0x0000003F
 #define CQE_CID_MASK   0x0000FFC0
@@ -617,6 +653,11 @@ struct iscsi_wrb {
 } __packed;
 
 #define WRB_TYPE_MASK 0xF0000000
+#define SKH_WRB_TYPE_OFFSET 27
+#define BE_WRB_TYPE_OFFSET  28
+
+#define ADAPTER_SET_WRB_TYPE(pwrb, wrb_type, type_offset) \
+               (pwrb->dw[0] |= (wrb_type << type_offset))
 
 /**
  * Pseudo amap definition in which each bit of the actual structure is defined
@@ -663,12 +704,57 @@ struct amap_iscsi_wrb {
 
 } __packed;
 
+struct amap_iscsi_wrb_v2 {
+       u8 r2t_exp_dtl[25]; /* DWORD 0 */
+       u8 rsvd0[2];    /* DWORD 0*/
+       u8 type[5];     /* DWORD 0 */
+       u8 ptr2nextwrb[8];  /* DWORD 1 */
+       u8 wrb_idx[8];      /* DWORD 1 */
+       u8 lun[16];     /* DWORD 1 */
+       u8 sgl_idx[16]; /* DWORD 2 */
+       u8 ref_sgl_icd_idx[16]; /* DWORD 2 */
+       u8 exp_data_sn[32]; /* DWORD 3 */
+       u8 iscsi_bhs_addr_hi[32];   /* DWORD 4 */
+       u8 iscsi_bhs_addr_lo[32];   /* DWORD 5 */
+       u8 cq_id[16];   /* DWORD 6 */
+       u8 rsvd1[16];   /* DWORD 6 */
+       u8 cmdsn_itt[32];   /* DWORD 7 */
+       u8 sge0_addr_hi[32];    /* DWORD 8 */
+       u8 sge0_addr_lo[32];    /* DWORD 9 */
+       u8 sge0_offset[24]; /* DWORD 10 */
+       u8 rsvd2[7];    /* DWORD 10 */
+       u8 sge0_last;   /* DWORD 10 */
+       u8 sge0_len[17];    /* DWORD 11 */
+       u8 rsvd3[7];    /* DWORD 11 */
+       u8 diff_enbl;   /* DWORD 11 */
+       u8 u_run;       /* DWORD 11 */
+       u8 o_run;       /* DWORD 11 */
+       u8 invalid;     /* DWORD 11 */
+       u8 dsp;         /* DWORD 11 */
+       u8 dmsg;        /* DWORD 11 */
+       u8 rsvd4;       /* DWORD 11 */
+       u8 lt;          /* DWORD 11 */
+       u8 sge1_addr_hi[32];    /* DWORD 12 */
+       u8 sge1_addr_lo[32];    /* DWORD 13 */
+       u8 sge1_r2t_offset[24]; /* DWORD 14 */
+       u8 rsvd5[7];    /* DWORD 14 */
+       u8 sge1_last;   /* DWORD 14 */
+       u8 sge1_len[17];    /* DWORD 15 */
+       u8 rsvd6[15];   /* DWORD 15 */
+} __packed;
+
+
 struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid);
 void
 free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
 
 void beiscsi_process_all_cqs(struct work_struct *work);
 
+static inline bool beiscsi_error(struct beiscsi_hba *phba)
+{
+       return phba->ue_detected || phba->fw_timeout;
+}
+
 struct pdu_nop_out {
        u32 dw[12];
 };
@@ -728,6 +814,7 @@ struct iscsi_target_context_update_wrb {
  * Pseudo amap definition in which each bit of the actual structure is defined
  * as a byte: used to calculate offset/shift/mask of each field
  */
+#define BE_TGT_CTX_UPDT_CMD 0x07
 struct amap_iscsi_target_context_update_wrb {
        u8 lun[14];             /* DWORD 0 */
        u8 lt;                  /* DWORD 0 */
@@ -773,6 +860,47 @@ struct amap_iscsi_target_context_update_wrb {
 
 } __packed;
 
+#define BEISCSI_MAX_RECV_DATASEG_LEN    (64 * 1024)
+#define BEISCSI_MAX_CXNS    1
+struct amap_iscsi_target_context_update_wrb_v2 {
+       u8 max_burst_length[24];    /* DWORD 0 */
+       u8 rsvd0[3];    /* DWORD 0 */
+       u8 type[5];     /* DWORD 0 */
+       u8 ptr2nextwrb[8];  /* DWORD 1 */
+       u8 wrb_idx[8];      /* DWORD 1 */
+       u8 rsvd1[16];       /* DWORD 1 */
+       u8 max_send_data_segment_length[24];    /* DWORD 2 */
+       u8 rsvd2[8];    /* DWORD 2 */
+       u8 first_burst_length[24]; /* DWORD 3 */
+       u8 rsvd3[8]; /* DOWRD 3 */
+       u8 max_r2t[16]; /* DWORD 4 */
+       u8 rsvd4[10];   /* DWORD 4 */
+       u8 hde;         /* DWORD 4 */
+       u8 dde;         /* DWORD 4 */
+       u8 erl[2];      /* DWORD 4 */
+       u8 imd;         /* DWORD 4 */
+       u8 ir2t;        /* DWORD 4 */
+       u8 stat_sn[32];     /* DWORD 5 */
+       u8 rsvd5[32];   /* DWORD 6 */
+       u8 rsvd6[32];   /* DWORD 7 */
+       u8 max_recv_dataseg_len[24];    /* DWORD 8 */
+       u8 rsvd7[8]; /* DWORD 8 */
+       u8 rsvd8[32];   /* DWORD 9 */
+       u8 rsvd9[32];   /* DWORD 10 */
+       u8 max_cxns[16]; /* DWORD 11 */
+       u8 rsvd10[11]; /* DWORD  11*/
+       u8 invld; /* DWORD 11 */
+       u8 rsvd11;/* DWORD 11*/
+       u8 dmsg; /* DWORD 11 */
+       u8 data_seq_inorder; /* DWORD 11 */
+       u8 pdu_seq_inorder; /* DWORD 11 */
+       u8 rsvd12[32]; /*DWORD 12 */
+       u8 rsvd13[32]; /* DWORD 13 */
+       u8 rsvd14[32]; /* DWORD 14 */
+       u8 rsvd15[32]; /* DWORD 15 */
+} __packed;
+
+
 struct be_ring {
        u32 pages;              /* queue size in pages */
        u32 id;                 /* queue id assigned by beklib */
@@ -837,7 +965,7 @@ struct hwi_context_memory {
        u16 max_eqd;            /* in usecs */
        u16 cur_eqd;            /* in usecs */
        struct be_eq_obj be_eq[MAX_CPUS];
-       struct be_queue_info be_cq[MAX_CPUS];
+       struct be_queue_info be_cq[MAX_CPUS - 1];
 
        struct be_queue_info be_def_hdrq;
        struct be_queue_info be_def_dataq;
index aab5dd359e2c2cbd5a945becbbcb44dd5638d727..a6c2fe4b4d652a39fe4c13bfede7560a5fdad675 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
 #include <scsi/scsi_bsg_iscsi.h>
 #include "be_mgmt.h"
 #include "be_iscsi.h"
+#include "be_main.h"
+
+/* UE Status Low CSR */
+static const char * const desc_ue_status_low[] = {
+       "CEV",
+       "CTX",
+       "DBUF",
+       "ERX",
+       "Host",
+       "MPU",
+       "NDMA",
+       "PTC ",
+       "RDMA ",
+       "RXF ",
+       "RXIPS ",
+       "RXULP0 ",
+       "RXULP1 ",
+       "RXULP2 ",
+       "TIM ",
+       "TPOST ",
+       "TPRE ",
+       "TXIPS ",
+       "TXULP0 ",
+       "TXULP1 ",
+       "UC ",
+       "WDMA ",
+       "TXULP2 ",
+       "HOST1 ",
+       "P0_OB_LINK ",
+       "P1_OB_LINK ",
+       "HOST_GPIO ",
+       "MBOX ",
+       "AXGMAC0",
+       "AXGMAC1",
+       "JTAG",
+       "MPU_INTPEND"
+};
+
+/* UE Status High CSR */
+static const char * const desc_ue_status_hi[] = {
+       "LPCMEMHOST",
+       "MGMT_MAC",
+       "PCS0ONLINE",
+       "MPU_IRAM",
+       "PCS1ONLINE",
+       "PCTL0",
+       "PCTL1",
+       "PMEM",
+       "RR",
+       "TXPB",
+       "RXPP",
+       "XAUI",
+       "TXP",
+       "ARM",
+       "IPC",
+       "HOST2",
+       "HOST3",
+       "HOST4",
+       "HOST5",
+       "HOST6",
+       "HOST7",
+       "HOST8",
+       "HOST9",
+       "NETC",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown"
+};
+
+/*
+ * beiscsi_ue_detec()- Detect Unrecoverable Error on adapter
+ * @phba: Driver priv structure
+ *
+ * Read registers linked to UE and check for the UE status
+ **/
+void beiscsi_ue_detect(struct beiscsi_hba *phba)
+{
+       uint32_t ue_hi = 0, ue_lo = 0;
+       uint32_t ue_mask_hi = 0, ue_mask_lo = 0;
+       uint8_t i = 0;
+
+       if (phba->ue_detected)
+               return;
+
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_LOW, &ue_lo);
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_MASK_LOW,
+                             &ue_mask_lo);
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_HIGH,
+                             &ue_hi);
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_MASK_HI,
+                             &ue_mask_hi);
+
+       ue_lo = (ue_lo & ~ue_mask_lo);
+       ue_hi = (ue_hi & ~ue_mask_hi);
+
+
+       if (ue_lo || ue_hi) {
+               phba->ue_detected = true;
+               beiscsi_log(phba, KERN_ERR,
+                           BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+                           "BG_%d : Error detected on the adapter\n");
+       }
+
+       if (ue_lo) {
+               for (i = 0; ue_lo; ue_lo >>= 1, i++) {
+                       if (ue_lo & 1)
+                               beiscsi_log(phba, KERN_ERR,
+                                           BEISCSI_LOG_CONFIG,
+                                           "BG_%d : UE_LOW %s bit set\n",
+                                           desc_ue_status_low[i]);
+               }
+       }
+
+       if (ue_hi) {
+               for (i = 0; ue_hi; ue_hi >>= 1, i++) {
+                       if (ue_hi & 1)
+                               beiscsi_log(phba, KERN_ERR,
+                                           BEISCSI_LOG_CONFIG,
+                                           "BG_%d : UE_HIGH %s bit set\n",
+                                           desc_ue_status_hi[i]);
+               }
+       }
+}
 
 /**
  * mgmt_reopen_session()- Reopen a session based on reopen_type
@@ -575,13 +707,20 @@ unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba)
        return status;
 }
 
+/*
+ * mgmt_exec_nonemb_cmd()- Execute Non Embedded MBX Cmd
+ * @phba: Driver priv structure
+ * @nonemb_cmd: Address of the MBX command issued
+ * @resp_buf: Buffer to copy the MBX cmd response
+ * @resp_buf_len: respone lenght to be copied
+ *
+ **/
 static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
                                struct be_dma_mem *nonemb_cmd, void *resp_buf,
                                int resp_buf_len)
 {
        struct be_ctrl_info *ctrl = &phba->ctrl;
        struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
-       unsigned short status, extd_status;
        struct be_sge *sge;
        unsigned int tag;
        int rc = 0;
@@ -599,31 +738,25 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba,
 
        be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1);
        sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
-       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+       sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd->dma));
        sge->len = cpu_to_le32(nonemb_cmd->size);
 
        be_mcc_notify(phba);
        spin_unlock(&ctrl->mbox_lock);
 
-       wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                phba->ctrl.mcc_numtag[tag]);
-
-       extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-       status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
-       if (status || extd_status) {
+       rc = beiscsi_mccq_compl(phba, tag, NULL, nonemb_cmd->va);
+       if (rc) {
                beiscsi_log(phba, KERN_ERR,
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BG_%d : mgmt_exec_nonemb_cmd Failed status = %d"
-                           "extd_status = %d\n", status, extd_status);
+                           "BG_%d : mgmt_exec_nonemb_cmd Failed status\n");
+
                rc = -EIO;
-               goto free_tag;
+               goto free_cmd;
        }
 
        if (resp_buf)
                memcpy(resp_buf, nonemb_cmd->va, resp_buf_len);
 
-free_tag:
-       free_mcc_tag(&phba->ctrl, tag);
 free_cmd:
        pci_free_consistent(ctrl->pdev, nonemb_cmd->size,
                            nonemb_cmd->va, nonemb_cmd->dma);
@@ -1009,10 +1142,9 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
 {
        struct be_cmd_get_boot_target_resp *boot_resp;
        struct be_mcc_wrb *wrb;
-       unsigned int tag, wrb_num;
+       unsigned int tag;
        uint8_t boot_retry = 3;
-       unsigned short status, extd_status;
-       struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
+       int rc;
 
        do {
                /* Get the Boot Target Session Handle and Count*/
@@ -1022,24 +1154,16 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
                                    BEISCSI_LOG_CONFIG | BEISCSI_LOG_INIT,
                                    "BG_%d : Getting Boot Target Info Failed\n");
                        return -EAGAIN;
-               } else
-                       wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                                phba->ctrl.mcc_numtag[tag]);
-
-               wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-               extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-               status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
-               if (status || extd_status) {
+               }
+
+               rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+               if (rc) {
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
-                                   "BG_%d : mgmt_get_boot_target Failed"
-                                   " status = %d extd_status = %d\n",
-                                   status, extd_status);
-                       free_mcc_tag(&phba->ctrl, tag);
+                                   "BG_%d : MBX CMD get_boot_target Failed\n");
                        return -EBUSY;
                }
-               wrb = queue_get_wrb(mccq, wrb_num);
-               free_mcc_tag(&phba->ctrl, tag);
+
                boot_resp = embedded_payload(wrb);
 
                /* Check if the there are any Boot targets configured */
@@ -1064,24 +1188,15 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
                                    BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
                                    "BG_%d : mgmt_reopen_session Failed\n");
                        return -EAGAIN;
-               } else
-                       wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                                phba->ctrl.mcc_numtag[tag]);
-
-               wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-               extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-               status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
-               if (status || extd_status) {
+               }
+
+               rc = beiscsi_mccq_compl(phba, tag, NULL, NULL);
+               if (rc) {
                        beiscsi_log(phba, KERN_ERR,
                                    BEISCSI_LOG_INIT | BEISCSI_LOG_CONFIG,
-                                   "BG_%d : mgmt_reopen_session Failed"
-                                   " status = %d extd_status = %d\n",
-                                   status, extd_status);
-                       free_mcc_tag(&phba->ctrl, tag);
-                       return -EBUSY;
+                                   "BG_%d : mgmt_reopen_session Failed");
+                       return rc;
                }
-               free_mcc_tag(&phba->ctrl, tag);
-
        } while (--boot_retry);
 
        /* Couldn't log into the boot target */
@@ -1106,8 +1221,9 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
 int mgmt_set_vlan(struct beiscsi_hba *phba,
                   uint16_t vlan_tag)
 {
-       unsigned int tag, wrb_num;
-       unsigned short status, extd_status;
+       int rc;
+       unsigned int tag;
+       struct be_mcc_wrb *wrb = NULL;
 
        tag = be_cmd_set_vlan(phba, vlan_tag);
        if (!tag) {
@@ -1115,24 +1231,208 @@ int mgmt_set_vlan(struct beiscsi_hba *phba,
                            (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
                            "BG_%d : VLAN Setting Failed\n");
                return -EBUSY;
-       } else
-               wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-                                        phba->ctrl.mcc_numtag[tag]);
-
-       wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16;
-       extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
-       status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+       }
 
-       if (status || extd_status) {
+       rc = beiscsi_mccq_compl(phba, tag, &wrb, NULL);
+       if (rc) {
                beiscsi_log(phba, KERN_ERR,
                            (BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX),
-                           "BS_%d : status : %d extd_status : %d\n",
-                           status, extd_status);
+                           "BS_%d : VLAN MBX Cmd Failed\n");
+               return rc;
+       }
+       return rc;
+}
 
-               free_mcc_tag(&phba->ctrl, tag);
-               return -EAGAIN;
+/**
+ * beiscsi_drvr_ver_disp()- Display the driver Name and Version
+ * @dev: ptr to device not used.
+ * @attr: device attribute, not used.
+ * @buf: contains formatted text driver name and version
+ *
+ * return
+ * size of the formatted string
+ **/
+ssize_t
+beiscsi_drvr_ver_disp(struct device *dev, struct device_attribute *attr,
+                      char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, BE_NAME "\n");
+}
+
+/**
+ * beiscsi_adap_family_disp()- Display adapter family.
+ * @dev: ptr to device to get priv structure
+ * @attr: device attribute, not used.
+ * @buf: contains formatted text driver name and version
+ *
+ * return
+ * size of the formatted string
+ **/
+ssize_t
+beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       uint16_t dev_id = 0;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct beiscsi_hba *phba = iscsi_host_priv(shost);
+
+       dev_id = phba->pcidev->device;
+       switch (dev_id) {
+       case BE_DEVICE_ID1:
+       case OC_DEVICE_ID1:
+       case OC_DEVICE_ID2:
+               return snprintf(buf, PAGE_SIZE, "BE2 Adapter Family\n");
+               break;
+       case BE_DEVICE_ID2:
+       case OC_DEVICE_ID3:
+               return snprintf(buf, PAGE_SIZE, "BE3-R Adapter Family\n");
+               break;
+       case OC_SKH_ID1:
+               return snprintf(buf, PAGE_SIZE, "Skyhawk-R Adapter Family\n");
+               break;
+       default:
+               return snprintf(buf, PAGE_SIZE,
+                               "Unkown Adapter Family: 0x%x\n", dev_id);
+               break;
        }
+}
 
-       free_mcc_tag(&phba->ctrl, tag);
-       return 0;
+
+void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
+                            struct wrb_handle *pwrb_handle,
+                            struct be_mem_descriptor *mem_descr)
+{
+       struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
+
+       memset(pwrb, 0, sizeof(*pwrb));
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+                     max_send_data_segment_length, pwrb,
+                     params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     max_send_data_segment_length) / 32]);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb,
+                     BE_TGT_CTX_UPDT_CMD);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+                     first_burst_length,
+                     pwrb,
+                     params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     first_burst_length) / 32]);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     erl) / 32] & OFFLD_PARAMS_ERL));
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                      dde) / 32] & OFFLD_PARAMS_DDE) >> 2);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     hde) / 32] & OFFLD_PARAMS_HDE) >> 3);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     imd) / 32] & OFFLD_PARAMS_IMD) >> 5);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn,
+                     pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     exp_statsn) / 32] + 1));
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx,
+                     pwrb, pwrb_handle->wrb_index);
+
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+                     max_burst_length, pwrb, params->dw[offsetof
+                     (struct amap_beiscsi_offload_params,
+                     max_burst_length) / 32]);
+
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb,
+                     pwrb, pwrb_handle->nxt_wrb_index);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+                     session_state, pwrb, 0);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack,
+                     pwrb, 1);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq,
+                     pwrb, 0);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb,
+                     0);
+
+       mem_descr += ISCSI_MEM_GLOBAL_HEADER;
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+                     pad_buffer_addr_hi, pwrb,
+                     mem_descr->mem_array[0].bus_address.u.a32.address_hi);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+                     pad_buffer_addr_lo, pwrb,
+                     mem_descr->mem_array[0].bus_address.u.a32.address_lo);
+}
+
+void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
+                            struct wrb_handle *pwrb_handle)
+{
+       struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
+
+       memset(pwrb, 0, sizeof(*pwrb));
+
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+                     max_burst_length, pwrb, params->dw[offsetof
+                     (struct amap_beiscsi_offload_params,
+                     max_burst_length) / 32]);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     max_burst_length, pwrb, params->dw[offsetof
+                     (struct amap_beiscsi_offload_params,
+                     max_burst_length) / 32]);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     type, pwrb,
+                     BE_TGT_CTX_UPDT_CMD);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     ptr2nextwrb,
+                     pwrb, pwrb_handle->nxt_wrb_index);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx,
+                     pwrb, pwrb_handle->wrb_index);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     max_send_data_segment_length, pwrb,
+                     params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     max_send_data_segment_length) / 32]);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     first_burst_length, pwrb,
+                     params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     first_burst_length) / 32]);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     max_recv_dataseg_len, pwrb, BEISCSI_MAX_RECV_DATASEG_LEN);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     max_cxns, pwrb, BEISCSI_MAX_CXNS);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, erl, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     erl) / 32] & OFFLD_PARAMS_ERL));
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, dde, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     dde) / 32] & OFFLD_PARAMS_DDE) >> 2);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, hde, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     hde) / 32] & OFFLD_PARAMS_HDE) >> 3);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     ir2t, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, imd, pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     imd) / 32] & OFFLD_PARAMS_IMD) >> 5);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     data_seq_inorder,
+                     pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     data_seq_inorder) / 32] &
+                     OFFLD_PARAMS_DATA_SEQ_INORDER) >> 6);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+                     pdu_seq_inorder,
+                     pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     pdu_seq_inorder) / 32] &
+                     OFFLD_PARAMS_PDU_SEQ_INORDER) >> 7);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, max_r2t,
+                     pwrb,
+                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     max_r2t) / 32] &
+                     OFFLD_PARAMS_MAX_R2T) >> 8);
+       AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, stat_sn,
+                     pwrb,
+                    (params->dw[offsetof(struct amap_beiscsi_offload_params,
+                     exp_statsn) / 32] + 1));
 }
index c50cef6fec0db3921908638411d9749bb879cdf2..2e4968add799f7e91ab53e38edd21cd5e74eaa44 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2012 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
 #define IP_V6_LEN      16
 #define IP_V4_LEN      4
 
+/* UE Status and Mask register */
+#define PCICFG_UE_STATUS_LOW            0xA0
+#define PCICFG_UE_STATUS_HIGH           0xA4
+#define PCICFG_UE_STATUS_MASK_LOW       0xA8
+#define PCICFG_UE_STATUS_MASK_HI        0xAC
+
 /**
  * Pseudo amap definition in which each bit of the actual structure is defined
  * as a byte: used to calculate offset/shift/mask of each field
@@ -301,4 +307,19 @@ int be_mgmt_get_boot_shandle(struct beiscsi_hba *phba,
 unsigned int mgmt_get_all_if_id(struct beiscsi_hba *phba);
 
 int mgmt_set_vlan(struct beiscsi_hba *phba, uint16_t vlan_tag);
+
+ssize_t beiscsi_drvr_ver_disp(struct device *dev,
+                              struct device_attribute *attr, char *buf);
+
+ssize_t beiscsi_adap_family_disp(struct device *dev,
+                                 struct device_attribute *attr, char *buf);
+
+void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
+                            struct wrb_handle *pwrb_handle,
+                            struct be_mem_descriptor *mem_descr);
+
+void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
+                            struct wrb_handle *pwrb_handle);
+void beiscsi_ue_detect(struct beiscsi_hba *phba);
+
 #endif
index 3f9e7061258e4352c3ba84d11c244491ae5ead6f..b44d04e41b0d72d8bfd775241ee7ee58df29f21f 100644 (file)
@@ -800,7 +800,7 @@ extern struct device_attribute *bnx2i_dev_attributes[];
 /*
  * Function Prototypes
  */
-extern void bnx2i_identify_device(struct bnx2i_hba *hba);
+extern void bnx2i_identify_device(struct bnx2i_hba *hba, struct cnic_dev *dev);
 
 extern void bnx2i_ulp_init(struct cnic_dev *dev);
 extern void bnx2i_ulp_exit(struct cnic_dev *dev);
index b17637aab9a792a959558ef79184800f9f0280a2..ee009e4ad097949785c677b9b343f3eeb8abbc7a 100644 (file)
@@ -79,42 +79,33 @@ static struct notifier_block bnx2i_cpu_notifier = {
 /**
  * bnx2i_identify_device - identifies NetXtreme II device type
  * @hba:               Adapter structure pointer
+ * @cnic:              Corresponding cnic device
  *
  * This function identifies the NX2 device type and sets appropriate
  *     queue mailbox register access method, 5709 requires driver to
  *     access MBOX regs using *bin* mode
  */
-void bnx2i_identify_device(struct bnx2i_hba *hba)
+void bnx2i_identify_device(struct bnx2i_hba *hba, struct cnic_dev *dev)
 {
        hba->cnic_dev_type = 0;
-       if ((hba->pci_did == PCI_DEVICE_ID_NX2_5706) ||
-           (hba->pci_did == PCI_DEVICE_ID_NX2_5706S))
-               set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type);
-       else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5708) ||
-           (hba->pci_did == PCI_DEVICE_ID_NX2_5708S))
-               set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type);
-       else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5709) ||
-           (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) {
-               set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
-               hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
-       } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710    ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57711    ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57711E   ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57712    ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57712E   ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57800    ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57800_MF ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57800_VF ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57810    ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57810_MF ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57810_VF ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57840    ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57840_MF ||
-                  hba->pci_did == PCI_DEVICE_ID_NX2_57840_VF)
+       if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+               if (hba->pci_did == PCI_DEVICE_ID_NX2_5706 ||
+                   hba->pci_did == PCI_DEVICE_ID_NX2_5706S) {
+                       set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type);
+               } else if (hba->pci_did == PCI_DEVICE_ID_NX2_5708 ||
+                   hba->pci_did == PCI_DEVICE_ID_NX2_5708S) {
+                       set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type);
+               } else if (hba->pci_did == PCI_DEVICE_ID_NX2_5709 ||
+                   hba->pci_did == PCI_DEVICE_ID_NX2_5709S) {
+                       set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
+                       hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
+               }
+       } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
                set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
-       else
+       } else {
                printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n",
                                  hba->pci_did);
+       }
 }
 
 
index 3b34c13e2f0217cddd881be065cfc05bc2baa46b..0056e47bd56ecf05c2f9fa3ac9c0e0636471172b 100644 (file)
@@ -808,7 +808,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
        hba->pci_func = PCI_FUNC(hba->pcidev->devfn);
        hba->pci_devno = PCI_SLOT(hba->pcidev->devfn);
 
-       bnx2i_identify_device(hba);
+       bnx2i_identify_device(hba, cnic);
        bnx2i_setup_host_queue_size(hba, shost);
 
        hba->reg_base = pci_resource_start(hba->pcidev, 0);
diff --git a/drivers/scsi/csiostor/Kconfig b/drivers/scsi/csiostor/Kconfig
new file mode 100644 (file)
index 0000000..4d03b03
--- /dev/null
@@ -0,0 +1,19 @@
+config SCSI_CHELSIO_FCOE
+       tristate "Chelsio Communications FCoE support"
+       depends on PCI && SCSI
+       select SCSI_FC_ATTRS
+       select FW_LOADER
+       help
+         This driver supports FCoE Offload functionality over
+         Chelsio T4-based 10Gb Converged Network Adapters.
+
+         For general information about Chelsio and our products, visit
+         our website at <http://www.chelsio.com>.
+
+         For customer support, please visit our customer support page at
+         <http://www.chelsio.com/support.html>.
+
+         Please send feedback to <linux-bugs@chelsio.com>.
+
+         To compile this driver as a module choose M here; the module
+         will be called csiostor.
diff --git a/drivers/scsi/csiostor/Makefile b/drivers/scsi/csiostor/Makefile
new file mode 100644 (file)
index 0000000..b581966
--- /dev/null
@@ -0,0 +1,11 @@
+#
+## Chelsio FCoE driver
+#
+##
+
+ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
+
+obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor.o
+
+csiostor-objs := csio_attr.o csio_init.o csio_lnode.o csio_scsi.o \
+               csio_hw.o csio_isr.o csio_mb.o csio_rnode.o csio_wr.o
diff --git a/drivers/scsi/csiostor/csio_attr.c b/drivers/scsi/csiostor/csio_attr.c
new file mode 100644 (file)
index 0000000..065a87a
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <linux/jiffies.h>
+#include <scsi/fc/fc_fs.h>
+
+#include "csio_init.h"
+
+static void
+csio_vport_set_state(struct csio_lnode *ln);
+
+/*
+ * csio_reg_rnode - Register a remote port with FC transport.
+ * @rn: Rnode representing remote port.
+ *
+ * Call fc_remote_port_add() to register this remote port with FC transport.
+ * If remote port is Initiator OR Target OR both, change the role appropriately.
+ *
+ */
+void
+csio_reg_rnode(struct csio_rnode *rn)
+{
+       struct csio_lnode *ln           = csio_rnode_to_lnode(rn);
+       struct Scsi_Host *shost         = csio_ln_to_shost(ln);
+       struct fc_rport_identifiers ids;
+       struct fc_rport  *rport;
+       struct csio_service_parms *sp;
+
+       ids.node_name   = wwn_to_u64(csio_rn_wwnn(rn));
+       ids.port_name   = wwn_to_u64(csio_rn_wwpn(rn));
+       ids.port_id     = rn->nport_id;
+       ids.roles       = FC_RPORT_ROLE_UNKNOWN;
+
+       if (rn->role & CSIO_RNFR_INITIATOR || rn->role & CSIO_RNFR_TARGET) {
+               rport = rn->rport;
+               CSIO_ASSERT(rport != NULL);
+               goto update_role;
+       }
+
+       rn->rport = fc_remote_port_add(shost, 0, &ids);
+       if (!rn->rport) {
+               csio_ln_err(ln, "Failed to register rport = 0x%x.\n",
+                                       rn->nport_id);
+               return;
+       }
+
+       ln->num_reg_rnodes++;
+       rport = rn->rport;
+       spin_lock_irq(shost->host_lock);
+       *((struct csio_rnode **)rport->dd_data) = rn;
+       spin_unlock_irq(shost->host_lock);
+
+       sp = &rn->rn_sparm;
+       rport->maxframe_size = ntohs(sp->csp.sp_bb_data);
+       if (ntohs(sp->clsp[2].cp_class) & FC_CPC_VALID)
+               rport->supported_classes = FC_COS_CLASS3;
+       else
+               rport->supported_classes = FC_COS_UNSPECIFIED;
+update_role:
+       if (rn->role & CSIO_RNFR_INITIATOR)
+               ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+       if (rn->role & CSIO_RNFR_TARGET)
+               ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
+
+       if (ids.roles != FC_RPORT_ROLE_UNKNOWN)
+               fc_remote_port_rolechg(rport, ids.roles);
+
+       rn->scsi_id = rport->scsi_target_id;
+
+       csio_ln_dbg(ln, "Remote port x%x role 0x%x registered\n",
+               rn->nport_id, ids.roles);
+}
+
+/*
+ * csio_unreg_rnode - Unregister a remote port with FC transport.
+ * @rn: Rnode representing remote port.
+ *
+ * Call fc_remote_port_delete() to unregister this remote port with FC
+ * transport.
+ *
+ */
+void
+csio_unreg_rnode(struct csio_rnode *rn)
+{
+       struct csio_lnode *ln = csio_rnode_to_lnode(rn);
+       struct fc_rport *rport = rn->rport;
+
+       rn->role &= ~(CSIO_RNFR_INITIATOR | CSIO_RNFR_TARGET);
+       fc_remote_port_delete(rport);
+       ln->num_reg_rnodes--;
+
+       csio_ln_dbg(ln, "Remote port x%x un-registered\n", rn->nport_id);
+}
+
+/*
+ * csio_lnode_async_event - Async events from local port.
+ * @ln: lnode representing local port.
+ *
+ * Async events from local node that FC transport/SCSI ML
+ * should be made aware of (Eg: RSCN).
+ */
+void
+csio_lnode_async_event(struct csio_lnode *ln, enum csio_ln_fc_evt fc_evt)
+{
+       switch (fc_evt) {
+       case CSIO_LN_FC_RSCN:
+               /* Get payload of rscn from ln */
+               /* For each RSCN entry */
+                       /*
+                        * fc_host_post_event(shost,
+                        *                    fc_get_event_number(),
+                        *                    FCH_EVT_RSCN,
+                        *                    rscn_entry);
+                        */
+               break;
+       case CSIO_LN_FC_LINKUP:
+               /* send fc_host_post_event */
+               /* set vport state */
+               if (csio_is_npiv_ln(ln))
+                       csio_vport_set_state(ln);
+
+               break;
+       case CSIO_LN_FC_LINKDOWN:
+               /* send fc_host_post_event */
+               /* set vport state */
+               if (csio_is_npiv_ln(ln))
+                       csio_vport_set_state(ln);
+
+               break;
+       case CSIO_LN_FC_ATTRIB_UPDATE:
+               csio_fchost_attr_init(ln);
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * csio_fchost_attr_init - Initialize FC transport attributes
+ * @ln: Lnode.
+ *
+ */
+void
+csio_fchost_attr_init(struct csio_lnode *ln)
+{
+       struct Scsi_Host  *shost = csio_ln_to_shost(ln);
+
+       fc_host_node_name(shost) = wwn_to_u64(csio_ln_wwnn(ln));
+       fc_host_port_name(shost) = wwn_to_u64(csio_ln_wwpn(ln));
+
+       fc_host_supported_classes(shost) = FC_COS_CLASS3;
+       fc_host_max_npiv_vports(shost) =
+                       (csio_lnode_to_hw(ln))->fres_info.max_vnps;
+       fc_host_supported_speeds(shost) = FC_PORTSPEED_10GBIT |
+               FC_PORTSPEED_1GBIT;
+
+       fc_host_maxframe_size(shost) = ntohs(ln->ln_sparm.csp.sp_bb_data);
+       memset(fc_host_supported_fc4s(shost), 0,
+               sizeof(fc_host_supported_fc4s(shost)));
+       fc_host_supported_fc4s(shost)[7] = 1;
+
+       memset(fc_host_active_fc4s(shost), 0,
+               sizeof(fc_host_active_fc4s(shost)));
+       fc_host_active_fc4s(shost)[7] = 1;
+}
+
+/*
+ * csio_get_host_port_id - sysfs entries for nport_id is
+ * populated/cached from this function
+ */
+static void
+csio_get_host_port_id(struct Scsi_Host *shost)
+{
+       struct csio_lnode *ln   = shost_priv(shost);
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+       spin_lock_irq(&hw->lock);
+       fc_host_port_id(shost) = ln->nport_id;
+       spin_unlock_irq(&hw->lock);
+}
+
+/*
+ * csio_get_port_type - Return FC local port type.
+ * @shost: scsi host.
+ *
+ */
+static void
+csio_get_host_port_type(struct Scsi_Host *shost)
+{
+       struct csio_lnode *ln = shost_priv(shost);
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+       spin_lock_irq(&hw->lock);
+       if (csio_is_npiv_ln(ln))
+               fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+       else
+               fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+       spin_unlock_irq(&hw->lock);
+}
+
+/*
+ * csio_get_port_state - Return FC local port state.
+ * @shost: scsi host.
+ *
+ */
+static void
+csio_get_host_port_state(struct Scsi_Host *shost)
+{
+       struct csio_lnode *ln = shost_priv(shost);
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+       char state[16];
+
+       spin_lock_irq(&hw->lock);
+
+       csio_lnode_state_to_str(ln, state);
+       if (!strcmp(state, "READY"))
+               fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+       else if (!strcmp(state, "OFFLINE"))
+               fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
+       else
+               fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+
+       spin_unlock_irq(&hw->lock);
+}
+
+/*
+ * csio_get_host_speed - Return link speed to FC transport.
+ * @shost: scsi host.
+ *
+ */
+static void
+csio_get_host_speed(struct Scsi_Host *shost)
+{
+       struct csio_lnode *ln = shost_priv(shost);
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+       spin_lock_irq(&hw->lock);
+       switch (hw->pport[ln->portid].link_speed) {
+       case FW_PORT_CAP_SPEED_1G:
+               fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
+               break;
+       case FW_PORT_CAP_SPEED_10G:
+               fc_host_speed(shost) = FC_PORTSPEED_10GBIT;
+               break;
+       default:
+               fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+               break;
+       }
+       spin_unlock_irq(&hw->lock);
+}
+
+/*
+ * csio_get_host_fabric_name - Return fabric name
+ * @shost: scsi host.
+ *
+ */
+static void
+csio_get_host_fabric_name(struct Scsi_Host *shost)
+{
+       struct csio_lnode *ln = shost_priv(shost);
+       struct csio_rnode *rn = NULL;
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+       spin_lock_irq(&hw->lock);
+       rn = csio_rnode_lookup_portid(ln, FC_FID_FLOGI);
+       if (rn)
+               fc_host_fabric_name(shost) = wwn_to_u64(csio_rn_wwnn(rn));
+       else
+               fc_host_fabric_name(shost) = 0;
+       spin_unlock_irq(&hw->lock);
+}
+
+/*
+ * csio_get_host_speed - Return FC transport statistics.
+ * @ln: Lnode.
+ *
+ */
+static struct fc_host_statistics *
+csio_get_stats(struct Scsi_Host *shost)
+{
+       struct csio_lnode *ln = shost_priv(shost);
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+       struct fc_host_statistics *fhs = &ln->fch_stats;
+       struct fw_fcoe_port_stats fcoe_port_stats;
+       uint64_t seconds;
+
+       memset(&fcoe_port_stats, 0, sizeof(struct fw_fcoe_port_stats));
+       csio_get_phy_port_stats(hw, ln->portid, &fcoe_port_stats);
+
+       fhs->tx_frames  += (be64_to_cpu(fcoe_port_stats.tx_bcast_frames) +
+                           be64_to_cpu(fcoe_port_stats.tx_mcast_frames) +
+                           be64_to_cpu(fcoe_port_stats.tx_ucast_frames) +
+                           be64_to_cpu(fcoe_port_stats.tx_offload_frames));
+       fhs->tx_words  += (be64_to_cpu(fcoe_port_stats.tx_bcast_bytes) +
+                          be64_to_cpu(fcoe_port_stats.tx_mcast_bytes) +
+                          be64_to_cpu(fcoe_port_stats.tx_ucast_bytes) +
+                          be64_to_cpu(fcoe_port_stats.tx_offload_bytes)) /
+                                                       CSIO_WORD_TO_BYTE;
+       fhs->rx_frames += (be64_to_cpu(fcoe_port_stats.rx_bcast_frames) +
+                          be64_to_cpu(fcoe_port_stats.rx_mcast_frames) +
+                          be64_to_cpu(fcoe_port_stats.rx_ucast_frames));
+       fhs->rx_words += (be64_to_cpu(fcoe_port_stats.rx_bcast_bytes) +
+                         be64_to_cpu(fcoe_port_stats.rx_mcast_bytes) +
+                         be64_to_cpu(fcoe_port_stats.rx_ucast_bytes)) /
+                                                       CSIO_WORD_TO_BYTE;
+       fhs->error_frames += be64_to_cpu(fcoe_port_stats.rx_err_frames);
+       fhs->fcp_input_requests +=  ln->stats.n_input_requests;
+       fhs->fcp_output_requests +=  ln->stats.n_output_requests;
+       fhs->fcp_control_requests +=  ln->stats.n_control_requests;
+       fhs->fcp_input_megabytes +=  ln->stats.n_input_bytes >> 20;
+       fhs->fcp_output_megabytes +=  ln->stats.n_output_bytes >> 20;
+       fhs->link_failure_count = ln->stats.n_link_down;
+       /* Reset stats for the device */
+       seconds = jiffies_to_msecs(jiffies) - hw->stats.n_reset_start;
+       do_div(seconds, 1000);
+       fhs->seconds_since_last_reset = seconds;
+
+       return fhs;
+}
+
+/*
+ * csio_set_rport_loss_tmo - Set the rport dev loss timeout
+ * @rport: fc rport.
+ * @timeout: new value for dev loss tmo.
+ *
+ * If timeout is non zero set the dev_loss_tmo to timeout, else set
+ * dev_loss_tmo to one.
+ */
+static void
+csio_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+       if (timeout)
+               rport->dev_loss_tmo = timeout;
+       else
+               rport->dev_loss_tmo = 1;
+}
+
+static void
+csio_vport_set_state(struct csio_lnode *ln)
+{
+       struct fc_vport *fc_vport = ln->fc_vport;
+       struct csio_lnode  *pln = ln->pln;
+       char state[16];
+
+       /* Set fc vport state based on phyiscal lnode */
+       csio_lnode_state_to_str(pln, state);
+       if (strcmp(state, "READY")) {
+               fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
+               return;
+       }
+
+       if (!(pln->flags & CSIO_LNF_NPIVSUPP)) {
+               fc_vport_set_state(fc_vport, FC_VPORT_NO_FABRIC_SUPP);
+               return;
+       }
+
+       /* Set fc vport state based on virtual lnode */
+       csio_lnode_state_to_str(ln, state);
+       if (strcmp(state, "READY")) {
+               fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
+               return;
+       }
+       fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+}
+
+static int
+csio_fcoe_alloc_vnp(struct csio_hw *hw, struct csio_lnode *ln)
+{
+       struct csio_lnode *pln;
+       struct csio_mb  *mbp;
+       struct fw_fcoe_vnp_cmd *rsp;
+       int ret = 0;
+       int retry = 0;
+
+       /* Issue VNP cmd to alloc vport */
+       /* Allocate Mbox request */
+       spin_lock_irq(&hw->lock);
+       mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+       if (!mbp) {
+               CSIO_INC_STATS(hw, n_err_nomem);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       pln = ln->pln;
+       ln->fcf_flowid = pln->fcf_flowid;
+       ln->portid = pln->portid;
+
+       csio_fcoe_vnp_alloc_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
+                                   pln->fcf_flowid, pln->vnp_flowid, 0,
+                                   csio_ln_wwnn(ln), csio_ln_wwpn(ln), NULL);
+
+       for (retry = 0; retry < 3; retry++) {
+               /* FW is expected to complete vnp cmd in immediate mode
+                * without much delay.
+                * Otherwise, there will be increase in IO latency since HW
+                * lock is held till completion of vnp mbox cmd.
+                */
+               ret = csio_mb_issue(hw, mbp);
+               if (ret != -EBUSY)
+                       break;
+
+               /* Retry if mbox returns busy */
+               spin_unlock_irq(&hw->lock);
+               msleep(2000);
+               spin_lock_irq(&hw->lock);
+       }
+
+       if (ret) {
+               csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n");
+               goto out_free;
+       }
+
+       /* Process Mbox response of VNP command */
+       rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
+       if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
+               csio_ln_err(ln, "FCOE VNP ALLOC cmd returned 0x%x!\n",
+                           FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
+               ret = -EINVAL;
+               goto out_free;
+       }
+
+       ln->vnp_flowid = FW_FCOE_VNP_CMD_VNPI_GET(
+                               ntohl(rsp->gen_wwn_to_vnpi));
+       memcpy(csio_ln_wwnn(ln), rsp->vnport_wwnn, 8);
+       memcpy(csio_ln_wwpn(ln), rsp->vnport_wwpn, 8);
+
+       csio_ln_dbg(ln, "FCOE VNPI: 0x%x\n", ln->vnp_flowid);
+       csio_ln_dbg(ln, "\tWWNN: %x%x%x%x%x%x%x%x\n",
+                   ln->ln_sparm.wwnn[0], ln->ln_sparm.wwnn[1],
+                   ln->ln_sparm.wwnn[2], ln->ln_sparm.wwnn[3],
+                   ln->ln_sparm.wwnn[4], ln->ln_sparm.wwnn[5],
+                   ln->ln_sparm.wwnn[6], ln->ln_sparm.wwnn[7]);
+       csio_ln_dbg(ln, "\tWWPN: %x%x%x%x%x%x%x%x\n",
+                   ln->ln_sparm.wwpn[0], ln->ln_sparm.wwpn[1],
+                   ln->ln_sparm.wwpn[2], ln->ln_sparm.wwpn[3],
+                   ln->ln_sparm.wwpn[4], ln->ln_sparm.wwpn[5],
+                   ln->ln_sparm.wwpn[6], ln->ln_sparm.wwpn[7]);
+
+out_free:
+       mempool_free(mbp, hw->mb_mempool);
+out:
+       spin_unlock_irq(&hw->lock);
+       return ret;
+}
+
+static int
+csio_fcoe_free_vnp(struct csio_hw *hw, struct csio_lnode *ln)
+{
+       struct csio_lnode *pln;
+       struct csio_mb  *mbp;
+       struct fw_fcoe_vnp_cmd *rsp;
+       int ret = 0;
+       int retry = 0;
+
+       /* Issue VNP cmd to free vport */
+       /* Allocate Mbox request */
+
+       spin_lock_irq(&hw->lock);
+       mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+       if (!mbp) {
+               CSIO_INC_STATS(hw, n_err_nomem);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       pln = ln->pln;
+
+       csio_fcoe_vnp_free_init_mb(ln, mbp, CSIO_MB_DEFAULT_TMO,
+                                  ln->fcf_flowid, ln->vnp_flowid,
+                                  NULL);
+
+       for (retry = 0; retry < 3; retry++) {
+               ret = csio_mb_issue(hw, mbp);
+               if (ret != -EBUSY)
+                       break;
+
+               /* Retry if mbox returns busy */
+               spin_unlock_irq(&hw->lock);
+               msleep(2000);
+               spin_lock_irq(&hw->lock);
+       }
+
+       if (ret) {
+               csio_ln_err(ln, "Failed to issue mbox FCoE VNP command\n");
+               goto out_free;
+       }
+
+       /* Process Mbox response of VNP command */
+       rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
+       if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
+               csio_ln_err(ln, "FCOE VNP FREE cmd returned 0x%x!\n",
+                           FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
+               ret = -EINVAL;
+       }
+
+out_free:
+       mempool_free(mbp, hw->mb_mempool);
+out:
+       spin_unlock_irq(&hw->lock);
+       return ret;
+}
+
+static int
+csio_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+       struct Scsi_Host *shost = fc_vport->shost;
+       struct csio_lnode *pln = shost_priv(shost);
+       struct csio_lnode *ln = NULL;
+       struct csio_hw *hw = csio_lnode_to_hw(pln);
+       uint8_t wwn[8];
+       int ret = -1;
+
+       ln = csio_shost_init(hw, &fc_vport->dev, false, pln);
+       if (!ln)
+               goto error;
+
+       if (fc_vport->node_name != 0) {
+               u64_to_wwn(fc_vport->node_name, wwn);
+
+               if (!CSIO_VALID_WWN(wwn)) {
+                       csio_ln_err(ln,
+                                   "vport create failed. Invalid wwnn\n");
+                       goto error;
+               }
+               memcpy(csio_ln_wwnn(ln), wwn, 8);
+       }
+
+       if (fc_vport->port_name != 0) {
+               u64_to_wwn(fc_vport->port_name, wwn);
+
+               if (!CSIO_VALID_WWN(wwn)) {
+                       csio_ln_err(ln,
+                                   "vport create failed. Invalid wwpn\n");
+                       goto error;
+               }
+
+               if (csio_lnode_lookup_by_wwpn(hw, wwn)) {
+                       csio_ln_err(ln,
+                           "vport create failed. wwpn already exists\n");
+                       goto error;
+               }
+               memcpy(csio_ln_wwpn(ln), wwn, 8);
+       }
+
+       fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
+
+       if (csio_fcoe_alloc_vnp(hw, ln))
+               goto error;
+
+       *(struct csio_lnode **)fc_vport->dd_data = ln;
+       ln->fc_vport = fc_vport;
+       if (!fc_vport->node_name)
+               fc_vport->node_name = wwn_to_u64(csio_ln_wwnn(ln));
+       if (!fc_vport->port_name)
+               fc_vport->port_name = wwn_to_u64(csio_ln_wwpn(ln));
+       csio_fchost_attr_init(ln);
+       return 0;
+error:
+       if (ln)
+               csio_shost_exit(ln);
+
+       return ret;
+}
+
+static int
+csio_vport_delete(struct fc_vport *fc_vport)
+{
+       struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data;
+       struct Scsi_Host *shost = csio_ln_to_shost(ln);
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+       int rmv;
+
+       spin_lock_irq(&hw->lock);
+       rmv = csio_is_hw_removing(hw);
+       spin_unlock_irq(&hw->lock);
+
+       if (rmv) {
+               csio_shost_exit(ln);
+               return 0;
+       }
+
+       /* Quiesce ios and send remove event to lnode */
+       scsi_block_requests(shost);
+       spin_lock_irq(&hw->lock);
+       csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln);
+       csio_lnode_close(ln);
+       spin_unlock_irq(&hw->lock);
+       scsi_unblock_requests(shost);
+
+       /* Free vnp */
+       if (fc_vport->vport_state !=  FC_VPORT_DISABLED)
+               csio_fcoe_free_vnp(hw, ln);
+
+       csio_shost_exit(ln);
+       return 0;
+}
+
+static int
+csio_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+       struct csio_lnode *ln = *(struct csio_lnode **)fc_vport->dd_data;
+       struct Scsi_Host *shost = csio_ln_to_shost(ln);
+       struct csio_hw *hw = csio_lnode_to_hw(ln);
+
+       /* disable vport */
+       if (disable) {
+               /* Quiesce ios and send stop event to lnode */
+               scsi_block_requests(shost);
+               spin_lock_irq(&hw->lock);
+               csio_scsim_cleanup_io_lnode(csio_hw_to_scsim(hw), ln);
+               csio_lnode_stop(ln);
+               spin_unlock_irq(&hw->lock);
+               scsi_unblock_requests(shost);
+
+               /* Free vnp */
+               csio_fcoe_free_vnp(hw, ln);
+               fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+               csio_ln_err(ln, "vport disabled\n");
+               return 0;
+       } else {
+               /* enable vport */
+               fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING);
+               if (csio_fcoe_alloc_vnp(hw, ln)) {
+                       csio_ln_err(ln, "vport enabled failed.\n");
+                       return -1;
+               }
+               csio_ln_err(ln, "vport enabled\n");
+               return 0;
+       }
+}
+
+static void
+csio_dev_loss_tmo_callbk(struct fc_rport *rport)
+{
+       struct csio_rnode *rn;
+       struct csio_hw *hw;
+       struct csio_lnode *ln;
+
+       rn = *((struct csio_rnode **)rport->dd_data);
+       ln = csio_rnode_to_lnode(rn);
+       hw = csio_lnode_to_hw(ln);
+
+       spin_lock_irq(&hw->lock);
+
+       /* return if driver is being removed or same rnode comes back online */
+       if (csio_is_hw_removing(hw) || csio_is_rnode_ready(rn))
+               goto out;
+
+       csio_ln_dbg(ln, "devloss timeout on rnode:%p portid:x%x flowid:x%x\n",
+                   rn, rn->nport_id, csio_rn_flowid(rn));
+
+       CSIO_INC_STATS(ln, n_dev_loss_tmo);
+
+       /*
+        * enqueue devloss event to event worker thread to serialize all
+        * rnode events.
+        */
+       if (csio_enqueue_evt(hw, CSIO_EVT_DEV_LOSS, &rn, sizeof(rn))) {
+               CSIO_INC_STATS(hw, n_evt_drop);
+               goto out;
+       }
+
+       if (!(hw->flags & CSIO_HWF_FWEVT_PENDING)) {
+               hw->flags |= CSIO_HWF_FWEVT_PENDING;
+               spin_unlock_irq(&hw->lock);
+               schedule_work(&hw->evtq_work);
+               return;
+       }
+
+out:
+       spin_unlock_irq(&hw->lock);
+}
+
+/* FC transport functions template - Physical port */
+struct fc_function_template csio_fc_transport_funcs = {
+       .show_host_node_name = 1,
+       .show_host_port_name = 1,
+       .show_host_supported_classes = 1,
+       .show_host_supported_fc4s = 1,
+       .show_host_maxframe_size = 1,
+
+       .get_host_port_id = csio_get_host_port_id,
+       .show_host_port_id = 1,
+
+       .get_host_port_type = csio_get_host_port_type,
+       .show_host_port_type = 1,
+
+       .get_host_port_state = csio_get_host_port_state,
+       .show_host_port_state = 1,
+
+       .show_host_active_fc4s = 1,
+       .get_host_speed = csio_get_host_speed,
+       .show_host_speed = 1,
+       .get_host_fabric_name = csio_get_host_fabric_name,
+       .show_host_fabric_name = 1,
+
+       .get_fc_host_stats = csio_get_stats,
+
+       .dd_fcrport_size = sizeof(struct csio_rnode *),
+       .show_rport_maxframe_size = 1,
+       .show_rport_supported_classes = 1,
+
+       .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo,
+       .show_rport_dev_loss_tmo = 1,
+
+       .show_starget_port_id = 1,
+       .show_starget_node_name = 1,
+       .show_starget_port_name = 1,
+
+       .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk,
+       .dd_fcvport_size = sizeof(struct csio_lnode *),
+
+       .vport_create = csio_vport_create,
+       .vport_disable = csio_vport_disable,
+       .vport_delete = csio_vport_delete,
+};
+
+/* FC transport functions template - Virtual  port */
+struct fc_function_template csio_fc_transport_vport_funcs = {
+       .show_host_node_name = 1,
+       .show_host_port_name = 1,
+       .show_host_supported_classes = 1,
+       .show_host_supported_fc4s = 1,
+       .show_host_maxframe_size = 1,
+
+       .get_host_port_id = csio_get_host_port_id,
+       .show_host_port_id = 1,
+
+       .get_host_port_type = csio_get_host_port_type,
+       .show_host_port_type = 1,
+
+       .get_host_port_state = csio_get_host_port_state,
+       .show_host_port_state = 1,
+       .show_host_active_fc4s = 1,
+
+       .get_host_speed = csio_get_host_speed,
+       .show_host_speed = 1,
+
+       .get_host_fabric_name = csio_get_host_fabric_name,
+       .show_host_fabric_name = 1,
+
+       .get_fc_host_stats = csio_get_stats,
+
+       .dd_fcrport_size = sizeof(struct csio_rnode *),
+       .show_rport_maxframe_size = 1,
+       .show_rport_supported_classes = 1,
+
+       .set_rport_dev_loss_tmo = csio_set_rport_loss_tmo,
+       .show_rport_dev_loss_tmo = 1,
+
+       .show_starget_port_id = 1,
+       .show_starget_node_name = 1,
+       .show_starget_port_name = 1,
+
+       .dev_loss_tmo_callbk = csio_dev_loss_tmo_callbk,
+
+};
diff --git a/drivers/scsi/csiostor/csio_defs.h b/drivers/scsi/csiostor/csio_defs.h
new file mode 100644 (file)
index 0000000..c38017b
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CSIO_DEFS_H__
+#define __CSIO_DEFS_H__
+
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/bug.h>
+#include <linux/pci.h>
+#include <linux/jiffies.h>
+
+#define CSIO_INVALID_IDX               0xFFFFFFFF
+#define CSIO_INC_STATS(elem, val)      ((elem)->stats.val++)
+#define CSIO_DEC_STATS(elem, val)      ((elem)->stats.val--)
+#define CSIO_VALID_WWN(__n)            ((*__n >> 4) == 0x5 ? true : false)
+#define CSIO_DID_MASK                  0xFFFFFF
+#define CSIO_WORD_TO_BYTE              4
+
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+       return readl(addr) + ((u64)readl(addr + 4) << 32);
+}
+
+static inline void writeq(u64 val, void __iomem *addr)
+{
+       writel(val, addr);
+       writel(val >> 32, addr + 4);
+}
+#endif
+
+static inline int
+csio_list_deleted(struct list_head *list)
+{
+       return ((list->next == list) && (list->prev == list));
+}
+
+#define csio_list_next(elem)   (((struct list_head *)(elem))->next)
+#define csio_list_prev(elem)   (((struct list_head *)(elem))->prev)
+
+/* State machine */
+typedef void (*csio_sm_state_t)(void *, uint32_t);
+
+struct csio_sm {
+       struct list_head        sm_list;
+       csio_sm_state_t         sm_state;
+};
+
+static inline void
+csio_set_state(void *smp, void *state)
+{
+       ((struct csio_sm *)smp)->sm_state = (csio_sm_state_t)state;
+}
+
+static inline void
+csio_init_state(struct csio_sm *smp, void *state)
+{
+       csio_set_state(smp, state);
+}
+
+static inline void
+csio_post_event(void *smp, uint32_t evt)
+{
+       ((struct csio_sm *)smp)->sm_state(smp, evt);
+}
+
+static inline csio_sm_state_t
+csio_get_state(void *smp)
+{
+       return ((struct csio_sm *)smp)->sm_state;
+}
+
+static inline bool
+csio_match_state(void *smp, void *state)
+{
+       return (csio_get_state(smp) == (csio_sm_state_t)state);
+}
+
+#define        CSIO_ASSERT(cond)               BUG_ON(!(cond))
+
+#ifdef __CSIO_DEBUG__
+#define CSIO_DB_ASSERT(__c)            CSIO_ASSERT((__c))
+#else
+#define CSIO_DB_ASSERT(__c)
+#endif
+
+#endif /* ifndef __CSIO_DEFS_H__ */
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
new file mode 100644 (file)
index 0000000..8ecdb94
--- /dev/null
@@ -0,0 +1,4395 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2012 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+#include <linux/firmware.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/compiler.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+
+#include "csio_hw.h"
+#include "csio_lnode.h"
+#include "csio_rnode.h"
+
+int csio_force_master;
+int csio_dbg_level = 0xFEFF;
+unsigned int csio_port_mask = 0xf;
+
+/* Default FW event queue entries. */
+static uint32_t csio_evtq_sz = CSIO_EVTQ_SIZE;
+
+/* Default MSI param level */
+int csio_msi = 2;
+
+/* FCoE function instances */
+static int dev_num;
+
+/* FCoE Adapter types & its description */
+static const struct csio_adap_desc csio_fcoe_adapters[] = {
+       {"T440-Dbg 10G", "Chelsio T440-Dbg 10G [FCoE]"},
+       {"T420-CR 10G", "Chelsio T420-CR 10G [FCoE]"},
+       {"T422-CR 10G/1G", "Chelsio T422-CR 10G/1G [FCoE]"},
+       {"T440-CR 10G", "Chelsio T440-CR 10G [FCoE]"},
+       {"T420-BCH 10G", "Chelsio T420-BCH 10G [FCoE]"},
+       {"T440-BCH 10G", "Chelsio T440-BCH 10G [FCoE]"},
+       {"T440-CH 10G", "Chelsio T440-CH 10G [FCoE]"},
+       {"T420-SO 10G", "Chelsio T420-SO 10G [FCoE]"},
+       {"T420-CX4 10G", "Chelsio T420-CX4 10G [FCoE]"},
+       {"T420-BT 10G", "Chelsio T420-BT 10G [FCoE]"},
+       {"T404-BT 1G", "Chelsio T404-BT 1G [FCoE]"},
+       {"B420-SR 10G", "Chelsio B420-SR 10G [FCoE]"},
+       {"B404-BT 1G", "Chelsio B404-BT 1G [FCoE]"},
+       {"T480-CR 10G", "Chelsio T480-CR 10G [FCoE]"},
+       {"T440-LP-CR 10G", "Chelsio T440-LP-CR 10G [FCoE]"},
+       {"T4 FPGA", "Chelsio T4 FPGA [FCoE]"}
+};
+
+static void csio_mgmtm_cleanup(struct csio_mgmtm *);
+static void csio_hw_mbm_cleanup(struct csio_hw *);
+
+/* State machine forward declarations */
+static void csio_hws_uninit(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_configuring(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_initializing(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_ready(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_quiescing(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_quiesced(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_resetting(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_removing(struct csio_hw *, enum csio_hw_ev);
+static void csio_hws_pcierr(struct csio_hw *, enum csio_hw_ev);
+
+static void csio_hw_initialize(struct csio_hw *hw);
+static void csio_evtq_stop(struct csio_hw *hw);
+static void csio_evtq_start(struct csio_hw *hw);
+
+int csio_is_hw_ready(struct csio_hw *hw)
+{
+       return csio_match_state(hw, csio_hws_ready);
+}
+
+int csio_is_hw_removing(struct csio_hw *hw)
+{
+       return csio_match_state(hw, csio_hws_removing);
+}
+
+
+/*
+ *     csio_hw_wait_op_done_val - wait until an operation is completed
+ *     @hw: the HW module
+ *     @reg: the register to check for completion
+ *     @mask: a single-bit field within @reg that indicates completion
+ *     @polarity: the value of the field when the operation is completed
+ *     @attempts: number of check iterations
+ *     @delay: delay in usecs between iterations
+ *     @valp: where to store the value of the register at completion time
+ *
+ *     Wait until an operation is completed by checking a bit in a register
+ *     up to @attempts times.  If @valp is not NULL the value of the register
+ *     at the time it indicated completion is stored there.  Returns 0 if the
+ *     operation completes and -EAGAIN otherwise.
+ */
+static int
+csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask,
+                        int polarity, int attempts, int delay, uint32_t *valp)
+{
+       uint32_t val;
+       while (1) {
+               val = csio_rd_reg32(hw, reg);
+
+               if (!!(val & mask) == polarity) {
+                       if (valp)
+                               *valp = val;
+                       return 0;
+               }
+
+               if (--attempts == 0)
+                       return -EAGAIN;
+               if (delay)
+                       udelay(delay);
+       }
+}
+
+void
+csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask,
+                  uint32_t value)
+{
+       uint32_t val = csio_rd_reg32(hw, reg) & ~mask;
+
+       csio_wr_reg32(hw, val | value, reg);
+       /* Flush */
+       csio_rd_reg32(hw, reg);
+
+}
+
+/*
+ *     csio_hw_mc_read - read from MC through backdoor accesses
+ *     @hw: the hw module
+ *     @addr: address of first byte requested
+ *     @data: 64 bytes of data containing the requested address
+ *     @ecc: where to store the corresponding 64-bit ECC word
+ *
+ *     Read 64 bytes of data from MC starting at a 64-byte-aligned address
+ *     that covers the requested address @addr.  If @parity is not %NULL it
+ *     is assigned the 64-bit ECC word for the read data.
+ */
+int
+csio_hw_mc_read(struct csio_hw *hw, uint32_t addr, __be32 *data,
+               uint64_t *ecc)
+{
+       int i;
+
+       if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST)
+               return -EBUSY;
+       csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR);
+       csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN);
+       csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN);
+       csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST |  BIST_CMD_GAP(1),
+                     MC_BIST_CMD);
+       i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST,
+                0, 10, 1, NULL);
+       if (i)
+               return i;
+
+#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
+
+       for (i = 15; i >= 0; i--)
+               *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
+       if (ecc)
+               *ecc = csio_rd_reg64(hw, MC_DATA(16));
+#undef MC_DATA
+       return 0;
+}
+
+/*
+ *     csio_hw_edc_read - read from EDC through backdoor accesses
+ *     @hw: the hw module
+ *     @idx: which EDC to access
+ *     @addr: address of first byte requested
+ *     @data: 64 bytes of data containing the requested address
+ *     @ecc: where to store the corresponding 64-bit ECC word
+ *
+ *     Read 64 bytes of data from EDC starting at a 64-byte-aligned address
+ *     that covers the requested address @addr.  If @parity is not %NULL it
+ *     is assigned the 64-bit ECC word for the read data.
+ */
+int
+csio_hw_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+               uint64_t *ecc)
+{
+       int i;
+
+       idx *= EDC_STRIDE;
+       if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST)
+               return -EBUSY;
+       csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx);
+       csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx);
+       csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx);
+       csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST,
+                    EDC_BIST_CMD + idx);
+       i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST,
+                0, 10, 1, NULL);
+       if (i)
+               return i;
+
+#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
+
+       for (i = 15; i >= 0; i--)
+               *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
+       if (ecc)
+               *ecc = csio_rd_reg64(hw, EDC_DATA(16));
+#undef EDC_DATA
+       return 0;
+}
+
+/*
+ *      csio_mem_win_rw - read/write memory through PCIE memory window
+ *      @hw: the adapter
+ *      @addr: address of first byte requested
+ *      @data: MEMWIN0_APERTURE bytes of data containing the requested address
+ *      @dir: direction of transfer 1 => read, 0 => write
+ *
+ *      Read/write MEMWIN0_APERTURE bytes of data from MC starting at a
+ *      MEMWIN0_APERTURE-byte-aligned address that covers the requested
+ *      address @addr.
+ */
+static int
+csio_mem_win_rw(struct csio_hw *hw, u32 addr, u32 *data, int dir)
+{
+       int i;
+
+       /*
+        * Setup offset into PCIE memory window.  Address must be a
+        * MEMWIN0_APERTURE-byte-aligned address.  (Read back MA register to
+        * ensure that changes propagate before we attempt to use the new
+        * values.)
+        */
+       csio_wr_reg32(hw, addr & ~(MEMWIN0_APERTURE - 1),
+                       PCIE_MEM_ACCESS_OFFSET);
+       csio_rd_reg32(hw, PCIE_MEM_ACCESS_OFFSET);
+
+       /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
+       for (i = 0; i < MEMWIN0_APERTURE; i = i + sizeof(__be32)) {
+               if (dir)
+                       *data++ = csio_rd_reg32(hw, (MEMWIN0_BASE + i));
+               else
+                       csio_wr_reg32(hw, *data++, (MEMWIN0_BASE + i));
+       }
+
+       return 0;
+}
+
+/*
+ *      csio_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
+ *      @hw: the csio_hw
+ *      @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
+ *      @addr: address within indicated memory type
+ *      @len: amount of memory to transfer
+ *      @buf: host memory buffer
+ *      @dir: direction of transfer 1 => read, 0 => write
+ *
+ *      Reads/writes an [almost] arbitrary memory region in the firmware: the
+ *      firmware memory address, length and host buffer must be aligned on
+ *      32-bit boudaries.  The memory is transferred as a raw byte sequence
+ *      from/to the firmware's memory.  If this memory contains data
+ *      structures which contain multi-byte integers, it's the callers
+ *      responsibility to perform appropriate byte order conversions.
+ */
+static int
+csio_memory_rw(struct csio_hw *hw, int mtype, u32 addr, u32 len,
+               uint32_t *buf, int dir)
+{
+       uint32_t pos, start, end, offset, memoffset;
+       int ret;
+       uint32_t *data;
+
+       /*
+        * Argument sanity checks ...
+        */
+       if ((addr & 0x3) || (len & 0x3))
+               return -EINVAL;
+
+       data = kzalloc(MEMWIN0_APERTURE, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       /* Offset into the region of memory which is being accessed
+        * MEM_EDC0 = 0
+        * MEM_EDC1 = 1
+        * MEM_MC   = 2
+        */
+       memoffset = (mtype * (5 * 1024 * 1024));
+
+       /* Determine the PCIE_MEM_ACCESS_OFFSET */
+       addr = addr + memoffset;
+
+       /*
+        * The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes
+        * at a time so we need to round down the start and round up the end.
+        * We'll start copying out of the first line at (addr - start) a word
+        * at a time.
+        */
+       start = addr & ~(MEMWIN0_APERTURE-1);
+       end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1);
+       offset = (addr - start)/sizeof(__be32);
+
+       for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) {
+               /*
+                * If we're writing, copy the data from the caller's memory
+                * buffer
+                */
+               if (!dir) {
+                       /*
+                        * If we're doing a partial write, then we need to do
+                        * a read-modify-write ...
+                        */
+                       if (offset || len < MEMWIN0_APERTURE) {
+                               ret = csio_mem_win_rw(hw, pos, data, 1);
+                               if (ret) {
+                                       kfree(data);
+                                       return ret;
+                               }
+                       }
+                       while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
+                                                               len > 0) {
+                               data[offset++] = *buf++;
+                               len -= sizeof(__be32);
+                       }
+               }
+
+               /*
+                * Transfer a block of memory and bail if there's an error.
+                */
+               ret = csio_mem_win_rw(hw, pos, data, dir);
+               if (ret) {
+                       kfree(data);
+                       return ret;
+               }
+
+               /*
+                * If we're reading, copy the data into the caller's memory
+                * buffer.
+                */
+               if (dir)
+                       while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
+                                                               len > 0) {
+                               *buf++ = data[offset++];
+                               len -= sizeof(__be32);
+                       }
+       }
+
+       kfree(data);
+
+       return 0;
+}
+
+static int
+csio_memory_write(struct csio_hw *hw, int mtype, u32 addr, u32 len, u32 *buf)
+{
+       return csio_memory_rw(hw, mtype, addr, len, buf, 0);
+}
+
+/*
+ * EEPROM reads take a few tens of us while writes can take a bit over 5 ms.
+ */
+#define EEPROM_MAX_RD_POLL 40
+#define EEPROM_MAX_WR_POLL 6
+#define EEPROM_STAT_ADDR   0x7bfc
+#define VPD_BASE           0x400
+#define VPD_BASE_OLD      0
+#define VPD_LEN            512
+#define VPD_INFO_FLD_HDR_SIZE  3
+
+/*
+ *     csio_hw_seeprom_read - read a serial EEPROM location
+ *     @hw: hw to read
+ *     @addr: EEPROM virtual address
+ *     @data: where to store the read data
+ *
+ *     Read a 32-bit word from a location in serial EEPROM using the card's PCI
+ *     VPD capability.  Note that this function must be called with a virtual
+ *     address.
+ */
+static int
+csio_hw_seeprom_read(struct csio_hw *hw, uint32_t addr, uint32_t *data)
+{
+       uint16_t val = 0;
+       int attempts = EEPROM_MAX_RD_POLL;
+       uint32_t base = hw->params.pci.vpd_cap_addr;
+
+       if (addr >= EEPROMVSIZE || (addr & 3))
+               return -EINVAL;
+
+       pci_write_config_word(hw->pdev, base + PCI_VPD_ADDR, (uint16_t)addr);
+
+       do {
+               udelay(10);
+               pci_read_config_word(hw->pdev, base + PCI_VPD_ADDR, &val);
+       } while (!(val & PCI_VPD_ADDR_F) && --attempts);
+
+       if (!(val & PCI_VPD_ADDR_F)) {
+               csio_err(hw, "reading EEPROM address 0x%x failed\n", addr);
+               return -EINVAL;
+       }
+
+       pci_read_config_dword(hw->pdev, base + PCI_VPD_DATA, data);
+       *data = le32_to_cpu(*data);
+
+       return 0;
+}
+
+/*
+ * Partial EEPROM Vital Product Data structure.  Includes only the ID and
+ * VPD-R sections.
+ */
+struct t4_vpd_hdr {
+       u8  id_tag;
+       u8  id_len[2];
+       u8  id_data[ID_LEN];
+       u8  vpdr_tag;
+       u8  vpdr_len[2];
+};
+
+/*
+ *     csio_hw_get_vpd_keyword_val - Locates an information field keyword in
+ *                                   the VPD
+ *     @v: Pointer to buffered vpd data structure
+ *     @kw: The keyword to search for
+ *
+ *     Returns the value of the information field keyword or
+ *     -EINVAL otherwise.
+ */
+static int
+csio_hw_get_vpd_keyword_val(const struct t4_vpd_hdr *v, const char *kw)
+{
+       int32_t i;
+       int32_t offset , len;
+       const uint8_t *buf = &v->id_tag;
+       const uint8_t *vpdr_len = &v->vpdr_tag;
+       offset = sizeof(struct t4_vpd_hdr);
+       len =  (uint16_t)vpdr_len[1] + ((uint16_t)vpdr_len[2] << 8);
+
+       if (len + sizeof(struct t4_vpd_hdr) > VPD_LEN)
+               return -EINVAL;
+
+       for (i = offset; (i + VPD_INFO_FLD_HDR_SIZE) <= (offset + len);) {
+               if (memcmp(buf + i , kw, 2) == 0) {
+                       i += VPD_INFO_FLD_HDR_SIZE;
+                       return i;
+               }
+
+               i += VPD_INFO_FLD_HDR_SIZE + buf[i+2];
+       }
+
+       return -EINVAL;
+}
+
+static int
+csio_pci_capability(struct pci_dev *pdev, int cap, int *pos)
+{
+       *pos = pci_find_capability(pdev, cap);
+       if (*pos)
+               return 0;
+
+       return -1;
+}
+
+/*
+ *     csio_hw_get_vpd_params - read VPD parameters from VPD EEPROM
+ *     @hw: HW module
+ *     @p: where to store the parameters
+ *
+ *     Reads card parameters stored in VPD EEPROM.
+ */
+static int
+csio_hw_get_vpd_params(struct csio_hw *hw, struct csio_vpd *p)
+{
+       int i, ret, ec, sn, addr;
+       uint8_t *vpd, csum;
+       const struct t4_vpd_hdr *v;
+       /* To get around compilation warning from strstrip */
+       char *s;
+
+       if (csio_is_valid_vpd(hw))
+               return 0;
+
+       ret = csio_pci_capability(hw->pdev, PCI_CAP_ID_VPD,
+                                 &hw->params.pci.vpd_cap_addr);
+       if (ret)
+               return -EINVAL;
+
+       vpd = kzalloc(VPD_LEN, GFP_ATOMIC);
+       if (vpd == NULL)
+               return -ENOMEM;
+
+       /*
+        * Card information normally starts at VPD_BASE but early cards had
+        * it at 0.
+        */
+       ret = csio_hw_seeprom_read(hw, VPD_BASE, (uint32_t *)(vpd));
+       addr = *vpd == 0x82 ? VPD_BASE : VPD_BASE_OLD;
+
+       for (i = 0; i < VPD_LEN; i += 4) {
+               ret = csio_hw_seeprom_read(hw, addr + i, (uint32_t *)(vpd + i));
+               if (ret) {
+                       kfree(vpd);
+                       return ret;
+               }
+       }
+
+       /* Reset the VPD flag! */
+       hw->flags &= (~CSIO_HWF_VPD_VALID);
+
+       v = (const struct t4_vpd_hdr *)vpd;
+
+#define FIND_VPD_KW(var, name) do { \
+       var = csio_hw_get_vpd_keyword_val(v, name); \
+       if (var < 0) { \
+               csio_err(hw, "missing VPD keyword " name "\n"); \
+               kfree(vpd); \
+               return -EINVAL; \
+       } \
+} while (0)
+
+       FIND_VPD_KW(i, "RV");
+       for (csum = 0; i >= 0; i--)
+               csum += vpd[i];
+
+       if (csum) {
+               csio_err(hw, "corrupted VPD EEPROM, actual csum %u\n", csum);
+               kfree(vpd);
+               return -EINVAL;
+       }
+       FIND_VPD_KW(ec, "EC");
+       FIND_VPD_KW(sn, "SN");
+#undef FIND_VPD_KW
+
+       memcpy(p->id, v->id_data, ID_LEN);
+       s = strstrip(p->id);
+       memcpy(p->ec, vpd + ec, EC_LEN);
+       s = strstrip(p->ec);
+       i = vpd[sn - VPD_INFO_FLD_HDR_SIZE + 2];
+       memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
+       s = strstrip(p->sn);
+
+       csio_valid_vpd_copied(hw);
+
+       kfree(vpd);
+       return 0;
+}
+
+/*
+ *     csio_hw_sf1_read - read data from the serial flash
+ *     @hw: the HW module
+ *     @byte_cnt: number of bytes to read
+ *     @cont: whether another operation will be chained
+ *      @lock: whether to lock SF for PL access only
+ *     @valp: where to store the read data
+ *
+ *     Reads up to 4 bytes of data from the serial flash.  The location of
+ *     the read needs to be specified prior to calling this by issuing the
+ *     appropriate commands to the serial flash.
+ */
+static int
+csio_hw_sf1_read(struct csio_hw *hw, uint32_t byte_cnt, int32_t cont,
+                int32_t lock, uint32_t *valp)
+{
+       int ret;
+
+       if (!byte_cnt || byte_cnt > 4)
+               return -EINVAL;
+       if (csio_rd_reg32(hw, SF_OP) & SF_BUSY)
+               return -EBUSY;
+
+       cont = cont ? SF_CONT : 0;
+       lock = lock ? SF_LOCK : 0;
+
+       csio_wr_reg32(hw, lock | cont | BYTECNT(byte_cnt - 1), SF_OP);
+       ret = csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS,
+                                        10, NULL);
+       if (!ret)
+               *valp = csio_rd_reg32(hw, SF_DATA);
+       return ret;
+}
+
+/*
+ *     csio_hw_sf1_write - write data to the serial flash
+ *     @hw: the HW module
+ *     @byte_cnt: number of bytes to write
+ *     @cont: whether another operation will be chained
+ *      @lock: whether to lock SF for PL access only
+ *     @val: value to write
+ *
+ *     Writes up to 4 bytes of data to the serial flash.  The location of
+ *     the write needs to be specified prior to calling this by issuing the
+ *     appropriate commands to the serial flash.
+ */
+static int
+csio_hw_sf1_write(struct csio_hw *hw, uint32_t byte_cnt, uint32_t cont,
+                 int32_t lock, uint32_t val)
+{
+       if (!byte_cnt || byte_cnt > 4)
+               return -EINVAL;
+       if (csio_rd_reg32(hw, SF_OP) & SF_BUSY)
+               return -EBUSY;
+
+       cont = cont ? SF_CONT : 0;
+       lock = lock ? SF_LOCK : 0;
+
+       csio_wr_reg32(hw, val, SF_DATA);
+       csio_wr_reg32(hw, cont | BYTECNT(byte_cnt - 1) | OP_WR | lock, SF_OP);
+
+       return csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS,
+                                       10, NULL);
+}
+
+/*
+ *     csio_hw_flash_wait_op - wait for a flash operation to complete
+ *     @hw: the HW module
+ *     @attempts: max number of polls of the status register
+ *     @delay: delay between polls in ms
+ *
+ *     Wait for a flash operation to complete by polling the status register.
+ */
+static int
+csio_hw_flash_wait_op(struct csio_hw *hw, int32_t attempts, int32_t delay)
+{
+       int ret;
+       uint32_t status;
+
+       while (1) {
+               ret = csio_hw_sf1_write(hw, 1, 1, 1, SF_RD_STATUS);
+               if (ret != 0)
+                       return ret;
+
+               ret = csio_hw_sf1_read(hw, 1, 0, 1, &status);
+               if (ret != 0)
+                       return ret;
+
+               if (!(status & 1))
+                       return 0;
+               if (--attempts == 0)
+                       return -EAGAIN;
+               if (delay)
+                       msleep(delay);
+       }
+}
+
+/*
+ *     csio_hw_read_flash - read words from serial flash
+ *     @hw: the HW module
+ *     @addr: the start address for the read
+ *     @nwords: how many 32-bit words to read
+ *     @data: where to store the read data
+ *     @byte_oriented: whether to store data as bytes or as words
+ *
+ *     Read the specified number of 32-bit words from the serial flash.
+ *     If @byte_oriented is set the read data is stored as a byte array
+ *     (i.e., big-endian), otherwise as 32-bit words in the platform's
+ *     natural endianess.
+ */
+static int
+csio_hw_read_flash(struct csio_hw *hw, uint32_t addr, uint32_t nwords,
+                 uint32_t *data, int32_t byte_oriented)
+{
+       int ret;
+
+       if (addr + nwords * sizeof(uint32_t) > hw->params.sf_size || (addr & 3))
+               return -EINVAL;
+
+       addr = swab32(addr) | SF_RD_DATA_FAST;
+
+       ret = csio_hw_sf1_write(hw, 4, 1, 0, addr);
+       if (ret != 0)
+               return ret;
+
+       ret = csio_hw_sf1_read(hw, 1, 1, 0, data);
+       if (ret != 0)
+               return ret;
+
+       for ( ; nwords; nwords--, data++) {
+               ret = csio_hw_sf1_read(hw, 4, nwords > 1, nwords == 1, data);
+               if (nwords == 1)
+                       csio_wr_reg32(hw, 0, SF_OP);    /* unlock SF */
+               if (ret)
+                       return ret;
+               if (byte_oriented)
+                       *data = htonl(*data);
+       }
+       return 0;
+}
+
+/*
+ *     csio_hw_write_flash - write up to a page of data to the serial flash
+ *     @hw: the hw
+ *     @addr: the start address to write
+ *     @n: length of data to write in bytes
+ *     @data: the data to write
+ *
+ *     Writes up to a page of data (256 bytes) to the serial flash starting
+ *     at the given address.  All the data must be written to the same page.
+ */
+static int
+csio_hw_write_flash(struct csio_hw *hw, uint32_t addr,
+                   uint32_t n, const uint8_t *data)
+{
+       int ret = -EINVAL;
+       uint32_t buf[64];
+       uint32_t i, c, left, val, offset = addr & 0xff;
+
+       if (addr >= hw->params.sf_size || offset + n > SF_PAGE_SIZE)
+               return -EINVAL;
+
+       val = swab32(addr) | SF_PROG_PAGE;
+
+       ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE);
+       if (ret != 0)
+               goto unlock;
+
+       ret = csio_hw_sf1_write(hw, 4, 1, 1, val);
+       if (ret != 0)
+               goto unlock;
+
+       for (left = n; left; left -= c) {
+               c = min(left, 4U);
+               for (val = 0, i = 0; i < c; ++i)
+                       val = (val << 8) + *data++;
+
+               ret = csio_hw_sf1_write(hw, c, c != left, 1, val);
+               if (ret)
+                       goto unlock;
+       }
+       ret = csio_hw_flash_wait_op(hw, 8, 1);
+       if (ret)
+               goto unlock;
+
+       csio_wr_reg32(hw, 0, SF_OP);    /* unlock SF */
+
+       /* Read the page to verify the write succeeded */
+       ret = csio_hw_read_flash(hw, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
+       if (ret)
+               return ret;
+
+       if (memcmp(data - n, (uint8_t *)buf + offset, n)) {
+               csio_err(hw,
+                        "failed to correctly write the flash page at %#x\n",
+                        addr);
+               return -EINVAL;
+       }
+
+       return 0;
+
+unlock:
+       csio_wr_reg32(hw, 0, SF_OP);    /* unlock SF */
+       return ret;
+}
+
+/*
+ *     csio_hw_flash_erase_sectors - erase a range of flash sectors
+ *     @hw: the HW module
+ *     @start: the first sector to erase
+ *     @end: the last sector to erase
+ *
+ *     Erases the sectors in the given inclusive range.
+ */
+static int
+csio_hw_flash_erase_sectors(struct csio_hw *hw, int32_t start, int32_t end)
+{
+       int ret = 0;
+
+       while (start <= end) {
+
+               ret = csio_hw_sf1_write(hw, 1, 0, 1, SF_WR_ENABLE);
+               if (ret != 0)
+                       goto out;
+
+               ret = csio_hw_sf1_write(hw, 4, 0, 1,
+                                       SF_ERASE_SECTOR | (start << 8));
+               if (ret != 0)
+                       goto out;
+
+               ret = csio_hw_flash_wait_op(hw, 14, 500);
+               if (ret != 0)
+                       goto out;
+
+               start++;
+       }
+out:
+       if (ret)
+               csio_err(hw, "erase of flash sector %d failed, error %d\n",
+                        start, ret);
+       csio_wr_reg32(hw, 0, SF_OP);    /* unlock SF */
+       return 0;
+}
+
+/*
+ *     csio_hw_flash_cfg_addr - return the address of the flash
+ *                             configuration file
+ *     @hw: the HW module
+ *
+ *     Return the address within the flash where the Firmware Configuration
+ *     File is stored.
+ */
+static unsigned int
+csio_hw_flash_cfg_addr(struct csio_hw *hw)
+{
+       if (hw->params.sf_size == 0x100000)
+               return FPGA_FLASH_CFG_OFFSET;
+       else
+               return FLASH_CFG_OFFSET;
+}
+
+static void
+csio_hw_print_fw_version(struct csio_hw *hw, char *str)
+{
+       csio_info(hw, "%s: %u.%u.%u.%u\n", str,
+                   FW_HDR_FW_VER_MAJOR_GET(hw->fwrev),
+                   FW_HDR_FW_VER_MINOR_GET(hw->fwrev),
+                   FW_HDR_FW_VER_MICRO_GET(hw->fwrev),
+                   FW_HDR_FW_VER_BUILD_GET(hw->fwrev));
+}
+
+/*
+ * csio_hw_get_fw_version - read the firmware version
+ * @hw: HW module
+ * @vers: where to place the version
+ *
+ * Reads the FW version from flash.
+ */
+static int
+csio_hw_get_fw_version(struct csio_hw *hw, uint32_t *vers)
+{
+       return csio_hw_read_flash(hw, FW_IMG_START +
+                                 offsetof(struct fw_hdr, fw_ver), 1,
+                                 vers, 0);
+}
+
+/*
+ *     csio_hw_get_tp_version - read the TP microcode version
+ *     @hw: HW module
+ *     @vers: where to place the version
+ *
+ *     Reads the TP microcode version from flash.
+ */
+static int
+csio_hw_get_tp_version(struct csio_hw *hw, u32 *vers)
+{
+       return csio_hw_read_flash(hw, FLASH_FW_START +
+                       offsetof(struct fw_hdr, tp_microcode_ver), 1,
+                       vers, 0);
+}
+
+/*
+ *     csio_hw_check_fw_version - check if the FW is compatible with
+ *                                this driver
+ *     @hw: HW module
+ *
+ *     Checks if an adapter's FW is compatible with the driver.  Returns 0
+ *     if there's exact match, a negative error if the version could not be
+ *     read or there's a major/minor version mismatch/minor.
+ */
+static int
+csio_hw_check_fw_version(struct csio_hw *hw)
+{
+       int ret, major, minor, micro;
+
+       ret = csio_hw_get_fw_version(hw, &hw->fwrev);
+       if (!ret)
+               ret = csio_hw_get_tp_version(hw, &hw->tp_vers);
+       if (ret)
+               return ret;
+
+       major = FW_HDR_FW_VER_MAJOR_GET(hw->fwrev);
+       minor = FW_HDR_FW_VER_MINOR_GET(hw->fwrev);
+       micro = FW_HDR_FW_VER_MICRO_GET(hw->fwrev);
+
+       if (major != FW_VERSION_MAJOR) {            /* major mismatch - fail */
+               csio_err(hw, "card FW has major version %u, driver wants %u\n",
+                        major, FW_VERSION_MAJOR);
+               return -EINVAL;
+       }
+
+       if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO)
+               return 0;        /* perfect match */
+
+       /* Minor/micro version mismatch */
+       return -EINVAL;
+}
+
+/*
+ * csio_hw_fw_dload - download firmware.
+ * @hw: HW module
+ * @fw_data: firmware image to write.
+ * @size: image size
+ *
+ * Write the supplied firmware image to the card's serial flash.
+ */
+static int
+csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size)
+{
+       uint32_t csum;
+       int32_t addr;
+       int ret;
+       uint32_t i;
+       uint8_t first_page[SF_PAGE_SIZE];
+       const __be32 *p = (const __be32 *)fw_data;
+       struct fw_hdr *hdr = (struct fw_hdr *)fw_data;
+       uint32_t sf_sec_size;
+
+       if ((!hw->params.sf_size) || (!hw->params.sf_nsec)) {
+               csio_err(hw, "Serial Flash data invalid\n");
+               return -EINVAL;
+       }
+
+       if (!size) {
+               csio_err(hw, "FW image has no data\n");
+               return -EINVAL;
+       }
+
+       if (size & 511) {
+               csio_err(hw, "FW image size not multiple of 512 bytes\n");
+               return -EINVAL;
+       }
+
+       if (ntohs(hdr->len512) * 512 != size) {
+               csio_err(hw, "FW image size differs from size in FW header\n");
+               return -EINVAL;
+       }
+
+       if (size > FW_MAX_SIZE) {
+               csio_err(hw, "FW image too large, max is %u bytes\n",
+                           FW_MAX_SIZE);
+               return -EINVAL;
+       }
+
+       for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+               csum += ntohl(p[i]);
+
+       if (csum != 0xffffffff) {
+               csio_err(hw, "corrupted firmware image, checksum %#x\n", csum);
+               return -EINVAL;
+       }
+
+       sf_sec_size = hw->params.sf_size / hw->params.sf_nsec;
+       i = DIV_ROUND_UP(size, sf_sec_size);        /* # of sectors spanned */
+
+       csio_dbg(hw, "Erasing sectors... start:%d end:%d\n",
+                         FW_START_SEC, FW_START_SEC + i - 1);
+
+       ret = csio_hw_flash_erase_sectors(hw, FW_START_SEC,
+                                         FW_START_SEC + i - 1);
+       if (ret) {
+               csio_err(hw, "Flash Erase failed\n");
+               goto out;
+       }
+
+       /*
+        * We write the correct version at the end so the driver can see a bad
+        * version if the FW write fails.  Start by writing a copy of the
+        * first page with a bad version.
+        */
+       memcpy(first_page, fw_data, SF_PAGE_SIZE);
+       ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
+       ret = csio_hw_write_flash(hw, FW_IMG_START, SF_PAGE_SIZE, first_page);
+       if (ret)
+               goto out;
+
+       csio_dbg(hw, "Writing Flash .. start:%d end:%d\n",
+                   FW_IMG_START, FW_IMG_START + size);
+
+       addr = FW_IMG_START;
+       for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
+               addr += SF_PAGE_SIZE;
+               fw_data += SF_PAGE_SIZE;
+               ret = csio_hw_write_flash(hw, addr, SF_PAGE_SIZE, fw_data);
+               if (ret)
+                       goto out;
+       }
+
+       ret = csio_hw_write_flash(hw,
+                                 FW_IMG_START +
+                                       offsetof(struct fw_hdr, fw_ver),
+                                 sizeof(hdr->fw_ver),
+                                 (const uint8_t *)&hdr->fw_ver);
+
+out:
+       if (ret)
+               csio_err(hw, "firmware download failed, error %d\n", ret);
+       return ret;
+}
+
+static int
+csio_hw_get_flash_params(struct csio_hw *hw)
+{
+       int ret;
+       uint32_t info = 0;
+
+       ret = csio_hw_sf1_write(hw, 1, 1, 0, SF_RD_ID);
+       if (!ret)
+               ret = csio_hw_sf1_read(hw, 3, 0, 1, &info);
+       csio_wr_reg32(hw, 0, SF_OP);    /* unlock SF */
+       if (ret != 0)
+               return ret;
+
+       if ((info & 0xff) != 0x20)              /* not a Numonix flash */
+               return -EINVAL;
+       info >>= 16;                            /* log2 of size */
+       if (info >= 0x14 && info < 0x18)
+               hw->params.sf_nsec = 1 << (info - 16);
+       else if (info == 0x18)
+               hw->params.sf_nsec = 64;
+       else
+               return -EINVAL;
+       hw->params.sf_size = 1 << info;
+
+       return 0;
+}
+
+static void
+csio_set_pcie_completion_timeout(struct csio_hw *hw, u8 range)
+{
+       uint16_t val;
+       uint32_t pcie_cap;
+
+       if (!csio_pci_capability(hw->pdev, PCI_CAP_ID_EXP, &pcie_cap)) {
+               pci_read_config_word(hw->pdev,
+                                    pcie_cap + PCI_EXP_DEVCTL2, &val);
+               val &= 0xfff0;
+               val |= range ;
+               pci_write_config_word(hw->pdev,
+                                     pcie_cap + PCI_EXP_DEVCTL2, val);
+       }
+}
+
+
+/*
+ * Return the specified PCI-E Configuration Space register from our Physical
+ * Function.  We try first via a Firmware LDST Command since we prefer to let
+ * the firmware own all of these registers, but if that fails we go for it
+ * directly ourselves.
+ */
+static uint32_t
+csio_read_pcie_cfg4(struct csio_hw *hw, int reg)
+{
+       u32 val = 0;
+       struct csio_mb *mbp;
+       int rv;
+       struct fw_ldst_cmd *ldst_cmd;
+
+       mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+       if (!mbp) {
+               CSIO_INC_STATS(hw, n_err_nomem);
+               pci_read_config_dword(hw->pdev, reg, &val);
+               return val;
+       }
+
+       csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg);
+
+       rv = csio_mb_issue(hw, mbp);
+
+       /*
+     &nbs