Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 21 May 2010 14:19:18 +0000 (07:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 21 May 2010 14:19:18 +0000 (07:19 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (182 commits)
  [SCSI] aacraid: add an ifdef'd device delete case instead of taking the device offline
  [SCSI] aacraid: prohibit access to array container space
  [SCSI] aacraid: add support for handling ATA pass-through commands.
  [SCSI] aacraid: expose physical devices for models with newer firmware
  [SCSI] aacraid: respond automatically to volumes added by config tool
  [SCSI] fcoe: fix fcoe module ref counting
  [SCSI] libfcoe: FIP Keep-Alive messages for VPorts are sent with incorrect port_id and wwn
  [SCSI] libfcoe: Fix incorrect MAC address clearing
  [SCSI] fcoe: fix a circular locking issue with rtnl and sysfs mutex
  [SCSI] libfc: Move the port_id into lport
  [SCSI] fcoe: move link speed checking into its own routine
  [SCSI] libfc: Remove extra pointer check
  [SCSI] libfc: Remove unused fc_get_host_port_type
  [SCSI] fcoe: fixes wrong error exit in fcoe_create
  [SCSI] libfc: set seq_id for incoming sequence
  [SCSI] qla2xxx: Updates to ISP82xx support.
  [SCSI] qla2xxx: Optionally disable target reset.
  [SCSI] qla2xxx: ensure flash operation and host reset via sg_reset are mutually exclusive
  [SCSI] qla2xxx: Silence bogus warning by gcc for wrap and did.
  [SCSI] qla2xxx: T10 DIF support added.
  ...

161 files changed:
MAINTAINERS
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptsas.h
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptspi.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fc.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_qdio.h
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-9xxx.h
drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h
drivers/scsi/Makefile
drivers/scsi/a2091.c
drivers/scsi/a2091.h
drivers/scsi/a3000.c
drivers/scsi/a3000.h
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commsup.c
drivers/scsi/bfa/bfa_cb_ioim_macros.h
drivers/scsi/bfa/bfa_ioim.c
drivers/scsi/bfa/bfa_os_inc.h
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_attr.c
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfad_im.h
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_init.c
drivers/scsi/cxgb3i/cxgb3i_init.c
drivers/scsi/device_handler/scsi_dh_emc.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/libfcoe.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_fcs.c
drivers/scsi/fnic/fnic_main.c
drivers/scsi/gdth.c
drivers/scsi/gvp11.c
drivers/scsi/gvp11.h
drivers/scsi/hpsa.c
drivers/scsi/hpsa_cmd.h
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/iscsi_tcp.c
drivers/scsi/iscsi_tcp.h
drivers/scsi/libfc/fc_disc.c
drivers/scsi/libfc/fc_elsct.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_libfc.h
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_npiv.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_bsg.h
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_nportdisc.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/lpfc/lpfc_vport.c
drivers/scsi/mpt2sas/Kconfig
drivers/scsi/mpt2sas/mpi/mpi2.h
drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
drivers/scsi/mpt2sas/mpi/mpi2_history.txt
drivers/scsi/mpt2sas/mpi/mpi2_init.h
drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
drivers/scsi/mpt2sas/mpi/mpi2_tool.h
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_config.c
drivers/scsi/mpt2sas/mpt2sas_ctl.c
drivers/scsi/mpt2sas/mpt2sas_ctl.h
drivers/scsi/mpt2sas/mpt2sas_debug.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/mpt2sas/mpt2sas_transport.c
drivers/scsi/mvme147.c
drivers/scsi/mvme147.h
drivers/scsi/mvsas/mv_64xx.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_sas.c
drivers/scsi/pmcraid.c
drivers/scsi/qla2xxx/Makefile
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_bsg.h [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_dbg.h
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_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_nx.c [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_nx.h [new file with mode: 0644]
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_fw.h
drivers/scsi/qla4xxx/ql4_glbl.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_iocb.c
drivers/scsi/qla4xxx/ql4_isr.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qla4xxx/ql4_version.h
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_trace.c [new file with mode: 0644]
drivers/scsi/scsi_transport_fc.c
drivers/scsi/sd.c
drivers/scsi/wd33c93.c
drivers/scsi/wd33c93.h
include/linux/ftrace_event.h
include/scsi/Kbuild
include/scsi/fc/fc_fcp.h
include/scsi/fc_encode.h
include/scsi/libfc.h
include/scsi/libfcoe.h
include/scsi/scsi.h
include/scsi/scsi_transport_fc.h
include/trace/events/scsi.h [new file with mode: 0644]
include/trace/ftrace.h
kernel/trace/trace_output.c

index 22a49e6..601ede3 100644 (file)
@@ -131,19 +131,12 @@ L:        netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/typhoon*
 
-3W-9XXX SATA-RAID CONTROLLER DRIVER
-M:     Adam Radford <linuxraid@amcc.com>
+3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS)
+M:     Adam Radford <linuxraid@lsi.com>
 L:     linux-scsi@vger.kernel.org
-W:     http://www.amcc.com
+W:     http://www.lsi.com
 S:     Supported
-F:     drivers/scsi/3w-9xxx*
-
-3W-XXXX ATA-RAID CONTROLLER DRIVER
-M:     Adam Radford <linuxraid@amcc.com>
-L:     linux-scsi@vger.kernel.org
-W:     http://www.amcc.com
-S:     Supported
-F:     drivers/scsi/3w-xxxx*
+F:     drivers/scsi/3w-*
 
 53C700 AND 53C700-66 SCSI DRIVER
 M:     "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
@@ -4621,6 +4614,14 @@ S:       Supported
 F:     Documentation/scsi/LICENSE.qla2xxx
 F:     drivers/scsi/qla2xxx/
 
+QLOGIC QLA4XXX iSCSI DRIVER
+M:     Ravi Anand <ravi.anand@qlogic.com>
+M:     Vikas Chaudhary <vikas.chaudhary@qlogic.com>
+M:     iscsi-driver@qlogic.com
+L:     linux-scsi@vger.kernel.org
+S:     Supported
+F:     drivers/scsi/qla4xxx/
+
 QLOGIC QLA3XXX NETWORK DRIVER
 M:     Ron Mercer <ron.mercer@qlogic.com>
 M:     linux-driver@qlogic.com
index 5382b5a..a6a5701 100644 (file)
@@ -5064,7 +5064,7 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
                if (!timeleft) {
                        printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
                            ioc->name, __func__);
-                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
                        mpt_free_msg_frame(ioc, mf);
                }
                goto out;
@@ -6456,10 +6456,15 @@ out:
                issue_hard_reset = 0;
                printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
                    ioc->name, __func__);
-               mpt_HardResetHandler(ioc, CAN_SLEEP);
+               if (retry_count == 0) {
+                       if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
+                               retry_count++;
+               } else
+                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+
                mpt_free_msg_frame(ioc, mf);
                /* attempt one retry for a timed out command */
-               if (!retry_count) {
+               if (retry_count < 2) {
                        printk(MYIOC_s_INFO_FMT
                            "Attempting Retry Config request"
                            " type 0x%x, page 0x%x,"
@@ -6904,6 +6909,172 @@ mpt_halt_firmware(MPT_ADAPTER *ioc)
 }
 EXPORT_SYMBOL(mpt_halt_firmware);
 
+/**
+ *     mpt_SoftResetHandler - Issues a less expensive reset
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Indicates if sleep or schedule must be called.
+
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ *
+ *     Message Unit Reset - instructs the IOC to reset the Reply Post and
+ *     Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
+ *     All posted buffers are freed, and event notification is turned off.
+ *     IOC doesnt reply to any outstanding request. This will transfer IOC
+ *     to READY state.
+ **/
+int
+mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
+{
+       int              rc;
+       int              ii;
+       u8               cb_idx;
+       unsigned long    flags;
+       u32              ioc_state;
+       unsigned long    time_count;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
+               ioc->name));
+
+       ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
+
+       if (mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
+
+       if (ioc_state == MPI_IOC_STATE_FAULT ||
+           ioc_state == MPI_IOC_STATE_RESET) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "skipping, either in FAULT or RESET state!\n", ioc->name));
+               return -1;
+       }
+
+       if (ioc->bus_type == FC) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "skipping, because the bus type is FC!\n", ioc->name));
+               return -1;
+       }
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               return -1;
+       }
+       ioc->ioc_reset_in_progress = 1;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       rc = -1;
+
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptResetHandlers[cb_idx])
+                       mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+       }
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->taskmgmt_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               return -1;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+       /* Disable reply interrupts (also blocks FreeQ) */
+       CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+       ioc->active = 0;
+       time_count = jiffies;
+
+       rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
+
+       for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+               if (MptResetHandlers[cb_idx])
+                       mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
+       }
+
+       if (rc)
+               goto out;
+
+       ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
+       if (ioc_state != MPI_IOC_STATE_READY)
+               goto out;
+
+       for (ii = 0; ii < 5; ii++) {
+               /* Get IOC facts! Allow 5 retries */
+               rc = GetIocFacts(ioc, sleepFlag,
+                       MPT_HOSTEVENT_IOC_RECOVER);
+               if (rc == 0)
+                       break;
+               if (sleepFlag == CAN_SLEEP)
+                       msleep(100);
+               else
+                       mdelay(100);
+       }
+       if (ii == 5)
+               goto out;
+
+       rc = PrimeIocFifos(ioc);
+       if (rc != 0)
+               goto out;
+
+       rc = SendIocInit(ioc, sleepFlag);
+       if (rc != 0)
+               goto out;
+
+       rc = SendEventNotification(ioc, 1, sleepFlag);
+       if (rc != 0)
+               goto out;
+
+       if (ioc->hard_resets < -1)
+               ioc->hard_resets++;
+
+       /*
+        * At this point, we know soft reset succeeded.
+        */
+
+       ioc->active = 1;
+       CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
+
+ out:
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       ioc->ioc_reset_in_progress = 0;
+       ioc->taskmgmt_quiesce_io = 0;
+       ioc->taskmgmt_in_progress = 0;
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+       if (ioc->active) {      /* otherwise, hard reset coming */
+               for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+                       if (MptResetHandlers[cb_idx])
+                               mpt_signal_reset(cb_idx, ioc,
+                                       MPT_IOC_POST_RESET);
+               }
+       }
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+               "SoftResetHandler: completed (%d seconds): %s\n",
+               ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
+               ((rc == 0) ? "SUCCESS" : "FAILED")));
+
+       return rc;
+}
+
+/**
+ *     mpt_Soft_Hard_ResetHandler - Try less expensive reset
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @sleepFlag: Indicates if sleep or schedule must be called.
+
+ *
+ *     Returns 0 for SUCCESS or -1 if FAILED.
+ *     Try for softreset first, only if it fails go for expensive
+ *     HardReset.
+ **/
+int
+mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
+       int ret = -1;
+
+       ret = mpt_SoftResetHandler(ioc, sleepFlag);
+       if (ret == 0)
+               return ret;
+       ret = mpt_HardResetHandler(ioc, sleepFlag);
+       return ret;
+}
+EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     Reset Handling
index 9718c8f..b613eb3 100644 (file)
@@ -76,8 +76,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.04.14"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.14"
+#define MPT_LINUX_VERSION_COMMON       "3.04.15"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.04.15"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -940,6 +940,7 @@ extern int   mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
 extern u32      mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 extern void     mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
 extern int      mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+extern int      mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 extern int      mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
 extern int      mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
 extern void     mpt_free_fw_memory(MPT_ADAPTER *ioc);
index caa8f56..f06b291 100644 (file)
@@ -128,7 +128,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags
                struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
 static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
                struct buflist *buflist, MPT_ADAPTER *ioc);
-static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function);
 
 /*
  * Reset Handler cleanup function
@@ -275,45 +274,6 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
        return 1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptctl_timeout_expired
- *
- * Expecting an interrupt, however timed out.
- *
- */
-static void
-mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
-{
-       unsigned long flags;
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
-               ioc->name, __func__));
-
-       if (mpt_fwfault_debug)
-               mpt_halt_firmware(ioc);
-
-       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
-       if (ioc->ioc_reset_in_progress) {
-               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
-               CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
-               mpt_free_msg_frame(ioc, mf);
-               return;
-       }
-       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
-
-
-       if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
-               return;
-
-       /* Issue a reset for this device.
-        * The IOC is not responding.
-        */
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-                ioc->name));
-       CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
-       mpt_HardResetHandler(ioc, CAN_SLEEP);
-       mpt_free_msg_frame(ioc, mf);
-}
 
 static int
 mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
@@ -343,12 +303,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        return 0;
 }
 
-/* mptctl_bus_reset
- *
- * Bus reset code.
- *
- */
-static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
+static int
+mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id)
 {
        MPT_FRAME_HDR   *mf;
        SCSITaskMgmt_t  *pScsiTm;
@@ -359,13 +315,6 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
        unsigned long    time_count;
        u16              iocstatus;
 
-       /* bus reset is only good for SCSI IO, RAID PASSTHRU */
-       if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
-               function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                       "TaskMgmt, not SCSI_IO!!\n", ioc->name));
-               return -EPERM;
-       }
 
        mutex_lock(&ioc->taskmgmt_cmds.mutex);
        if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
@@ -375,15 +324,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 
        retval = 0;
 
-       /* Send request
-        */
        mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
        if (mf == NULL) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                       "TaskMgmt, no msg frames!!\n", ioc->name));
+               dtmprintk(ioc,
+                       printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
+                       ioc->name));
                mpt_clear_taskmgmt_in_progress_flag(ioc);
                retval = -ENOMEM;
-               goto mptctl_bus_reset_done;
+               goto tm_done;
        }
 
        dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
@@ -392,10 +340,13 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
        pScsiTm = (SCSITaskMgmt_t *) mf;
        memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
        pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
-       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-       pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
-       pScsiTm->TargetID = 0;
-       pScsiTm->Bus = 0;
+       pScsiTm->TaskType = tm_type;
+       if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) &&
+               (ioc->bus_type == FC))
+               pScsiTm->MsgFlags =
+                               MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+       pScsiTm->TargetID = target_id;
+       pScsiTm->Bus = bus_id;
        pScsiTm->ChainOffset = 0;
        pScsiTm->Reserved = 0;
        pScsiTm->Reserved1 = 0;
@@ -413,17 +364,16 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                timeout = 30;
                break;
        case SPI:
-       default:
-               timeout = 2;
+               default:
+               timeout = 10;
                break;
        }
 
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               "TaskMgmt type=%d timeout=%ld\n",
-               ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
+       dtmprintk(ioc,
+               printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
+               ioc->name, tm_type, timeout));
 
        INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
-       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
        time_count = jiffies;
        if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
            (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
@@ -432,17 +382,20 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
                    sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
                if (retval != 0) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       dfailprintk(ioc,
+                               printk(MYIOC_s_ERR_FMT
                                "TaskMgmt send_handshake FAILED!"
                                " (ioc %p, mf %p, rc=%d) \n", ioc->name,
                                ioc, mf, retval));
+                       mpt_free_msg_frame(ioc, mf);
                        mpt_clear_taskmgmt_in_progress_flag(ioc);
-                       goto mptctl_bus_reset_done;
+                       goto tm_done;
                }
        }
 
        /* Now wait for the command to complete */
        ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+
        if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
                dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                    "TaskMgmt failed\n", ioc->name));
@@ -452,14 +405,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                        retval = 0;
                else
                        retval = -1; /* return failure */
-               goto mptctl_bus_reset_done;
+               goto tm_done;
        }
 
        if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
                dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                    "TaskMgmt failed\n", ioc->name));
                retval = -1; /* return failure */
-               goto mptctl_bus_reset_done;
+               goto tm_done;
        }
 
        pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
@@ -467,7 +420,7 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
            "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
            "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
            "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
-           pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+           pScsiTmReply->TargetID, tm_type,
            le16_to_cpu(pScsiTmReply->IOCStatus),
            le32_to_cpu(pScsiTmReply->IOCLogInfo),
            pScsiTmReply->ResponseCode,
@@ -485,13 +438,71 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                retval = -1; /* return failure */
        }
 
-
- mptctl_bus_reset_done:
+ tm_done:
        mutex_unlock(&ioc->taskmgmt_cmds.mutex);
        CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
        return retval;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_timeout_expired
+ *
+ * Expecting an interrupt, however timed out.
+ *
+ */
+static void
+mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+{
+       unsigned long flags;
+       int ret_val = -1;
+       SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf;
+       u8 function = mf->u.hdr.Function;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
+               ioc->name, __func__));
+
+       if (mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+               mpt_free_msg_frame(ioc, mf);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+
+       CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+
+       if (ioc->bus_type == SAS) {
+               if (function == MPI_FUNCTION_SCSI_IO_REQUEST)
+                       ret_val = mptctl_do_taskmgmt(ioc,
+                               MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+                               scsi_req->Bus, scsi_req->TargetID);
+               else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
+                       ret_val = mptctl_do_taskmgmt(ioc,
+                               MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                               scsi_req->Bus, 0);
+               if (!ret_val)
+                       return;
+       } else {
+               if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+                       (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH))
+                       ret_val = mptctl_do_taskmgmt(ioc,
+                               MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                               scsi_req->Bus, 0);
+               if (!ret_val)
+                       return;
+       }
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n",
+                ioc->name));
+       mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
+       mpt_free_msg_frame(ioc, mf);
+}
+
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* mptctl_ioc_reset
@@ -1318,6 +1329,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        if (ioc->sh) {
                shost_for_each_device(sdev, ioc->sh) {
                        vdevice = sdev->hostdata;
+                       if (vdevice == NULL || vdevice->vtarget == NULL)
+                               continue;
                        if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
@@ -1439,6 +1452,8 @@ mptctl_gettargetinfo (unsigned long arg)
                        if (!maxWordsLeft)
                                continue;
                        vdevice = sdev->hostdata;
+                       if (vdevice == NULL || vdevice->vtarget == NULL)
+                               continue;
                        if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
@@ -1967,6 +1982,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                struct scsi_target *starget = scsi_target(sdev);
                                VirtTarget *vtarget = starget->hostdata;
 
+                               if (vtarget == NULL)
+                                       continue;
+
                                if ((pScsiReq->TargetID == vtarget->id) &&
                                    (pScsiReq->Bus == vtarget->channel) &&
                                    (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
@@ -2991,6 +3009,14 @@ static int __init mptctl_init(void)
        }
 
        mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
+       if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
+               printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
+               mpt_deregister(mptctl_id);
+               misc_deregister(&mptctl_miscdev);
+               err = -EBUSY;
+               goto out_fail;
+       }
+
        mpt_reset_register(mptctl_id, mptctl_ioc_reset);
        mpt_event_register(mptctl_id, mptctl_event_process);
 
@@ -3010,12 +3036,15 @@ static void mptctl_exit(void)
        printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
                         mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
 
+       /* De-register event handler from base module */
+       mpt_event_deregister(mptctl_id);
+
        /* De-register reset handler from base module */
        mpt_reset_deregister(mptctl_id);
 
        /* De-register callback handler from base module */
+       mpt_deregister(mptctl_taskmgmt_id);
        mpt_deregister(mptctl_id);
-       mpt_reset_deregister(mptctl_taskmgmt_id);
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);
 
index 33f7256..b5f03ad 100644 (file)
@@ -482,6 +482,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
                                if (vtarget) {
                                        vtarget->id = pg0->CurrentTargetID;
                                        vtarget->channel = pg0->CurrentBus;
+                                       vtarget->deleted = 0;
                                }
                        }
                        *((struct mptfc_rport_info **)rport->dd_data) = ri;
@@ -1092,6 +1093,8 @@ mptfc_setup_reset(struct work_struct *work)
                container_of(work, MPT_ADAPTER, fc_setup_reset_work);
        u64                     pn;
        struct mptfc_rport_info *ri;
+       struct scsi_target      *starget;
+       VirtTarget              *vtarget;
 
        /* reset about to happen, delete (block) all rports */
        list_for_each_entry(ri, &ioc->fc_rports, list) {
@@ -1099,6 +1102,12 @@ mptfc_setup_reset(struct work_struct *work)
                        ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
                        fc_remote_port_delete(ri->rport);       /* won't sleep */
                        ri->rport = NULL;
+                       starget = ri->starget;
+                       if (starget) {
+                               vtarget = starget->hostdata;
+                               if (vtarget)
+                                       vtarget->deleted = 1;
+                       }
 
                        pn = (u64)ri->pg0.WWPN.High << 32 |
                             (u64)ri->pg0.WWPN.Low;
@@ -1119,6 +1128,8 @@ mptfc_rescan_devices(struct work_struct *work)
        int                     ii;
        u64                     pn;
        struct mptfc_rport_info *ri;
+       struct scsi_target      *starget;
+       VirtTarget              *vtarget;
 
        /* start by tagging all ports as missing */
        list_for_each_entry(ri, &ioc->fc_rports, list) {
@@ -1146,6 +1157,12 @@ mptfc_rescan_devices(struct work_struct *work)
                                       MPT_RPORT_INFO_FLAGS_MISSING);
                        fc_remote_port_delete(ri->rport);       /* won't sleep */
                        ri->rport = NULL;
+                       starget = ri->starget;
+                       if (starget) {
+                               vtarget = starget->hostdata;
+                               if (vtarget)
+                                       vtarget->deleted = 1;
+                       }
 
                        pn = (u64)ri->pg0.WWPN.High << 32 |
                             (u64)ri->pg0.WWPN.Low;
@@ -1358,6 +1375,9 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
        unsigned long flags;
        int rc=1;
 
+       if (ioc->bus_type != FC)
+               return 0;
+
        devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
                        ioc->name, event));
 
@@ -1396,7 +1416,7 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        unsigned long   flags;
 
        rc = mptscsih_ioc_reset(ioc,reset_phase);
-       if (rc == 0)
+       if ((ioc->bus_type != FC) || (!rc))
                return rc;
 
 
index 7668712..ac000e8 100644 (file)
@@ -1894,7 +1894,7 @@ static struct scsi_host_template mptsas_driver_template = {
        .module                         = THIS_MODULE,
        .proc_name                      = "mptsas",
        .proc_info                      = mptscsih_proc_info,
-       .name                           = "MPT SPI Host",
+       .name                           = "MPT SAS Host",
        .info                           = mptscsih_info,
        .queuecommand                   = mptsas_qcmd,
        .target_alloc                   = mptsas_target_alloc,
@@ -2038,11 +2038,13 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
 
        timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
                        10 * HZ);
-       if (!timeleft) {
-               /* On timeout reset the board */
+       if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               error = -ETIME;
                mpt_free_msg_frame(ioc, mf);
-               mpt_HardResetHandler(ioc, CAN_SLEEP);
-               error = -ETIMEDOUT;
+               if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto out_unlock;
+               if (!timeleft)
+                       mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
                goto out_unlock;
        }
 
@@ -2223,11 +2225,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
 
        timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
-       if (!timeleft) {
-               printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
-               /* On timeout reset the board */
-               mpt_HardResetHandler(ioc, CAN_SLEEP);
-               ret = -ETIMEDOUT;
+       if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+               ret = -ETIME;
+               mpt_free_msg_frame(ioc, mf);
+               mf = NULL;
+               if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
+                       goto unmap;
+               if (!timeleft)
+                       mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
                goto unmap;
        }
        mf = NULL;
@@ -2518,6 +2523,12 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 
        error = mpt_config(ioc, &cfg);
+
+       if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+               error = -ENODEV;
+               goto out_free_consistent;
+       }
+
        if (error)
                goto out_free_consistent;
 
@@ -2594,14 +2605,14 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
        cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 
        error = mpt_config(ioc, &cfg);
-       if (error)
-               goto out_free_consistent;
-
-       if (!buffer->NumPhys) {
+       if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
                error = -ENODEV;
                goto out_free_consistent;
        }
 
+       if (error)
+               goto out_free_consistent;
+
        /* save config data */
        port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
        port_info->phy_info = kcalloc(port_info->num_phys,
@@ -2677,7 +2688,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
 
        if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
                error = -ENODEV;
-               goto out;
+               goto out_free_consistent;
        }
 
        if (error)
@@ -2833,7 +2844,7 @@ mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
                if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
                        goto out_free;
                if (!timeleft)
-                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
                goto out_free;
        }
 
@@ -4098,6 +4109,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
        cfg.pageAddr = (channel << 8) + id;
        cfg.cfghdr.hdr = &hdr;
        cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
        if (mpt_config(ioc, &cfg) != 0)
                goto out;
@@ -4717,7 +4729,7 @@ mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
        if (issue_reset) {
                printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
                    ioc->name, __func__);
-               mpt_HardResetHandler(ioc, CAN_SLEEP);
+               mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
        }
        mptsas_free_fw_event(ioc, fw_event);
 }
@@ -4779,6 +4791,9 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
        struct fw_event_work *fw_event;
        unsigned long delay;
 
+       if (ioc->bus_type != SAS)
+               return 0;
+
        /* events turned off due to host reset or driver unloading */
        if (ioc->fw_events_off)
                return 0;
@@ -5073,6 +5088,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
        struct mptsas_portinfo *p, *n;
        int i;
 
+       if (!ioc->sh) {
+               printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
+               mpt_detach(pdev);
+               return;
+       }
+
        mptsas_shutdown(pdev);
 
        mptsas_del_device_components(ioc);
index 953c2bf..7b249ed 100644 (file)
@@ -110,7 +110,7 @@ struct fw_event_work {
        MPT_ADAPTER     *ioc;
        u32                     event;
        u8                      retries;
-       u8                      event_data[1];
+       u8                      __attribute__((aligned(4))) event_data[1];
 };
 
 struct mptsas_discovery_event {
index 6796597..7bd4c0f 100644 (file)
@@ -1149,11 +1149,6 @@ mptscsih_remove(struct pci_dev *pdev)
        MPT_SCSI_HOST           *hd;
        int sz1;
 
-       if(!host) {
-               mpt_detach(pdev);
-               return;
-       }
-
        scsi_remove_host(host);
 
        if((hd = shost_priv(host)) == NULL)
@@ -1711,7 +1706,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
        if (issue_hard_reset) {
                printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
                        ioc->name, __func__);
-               retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+               retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
                mpt_free_msg_frame(ioc, mf);
        }
 
@@ -1728,6 +1723,7 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
        case FC:
                return 40;
        case SAS:
+               return 30;
        case SPI:
        default:
                return 10;
@@ -1777,7 +1773,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
                    ioc->name, SCpnt));
                SCpnt->result = DID_NO_CONNECT << 16;
                SCpnt->scsi_done(SCpnt);
-               retval = 0;
+               retval = SUCCESS;
                goto out;
        }
 
@@ -1792,6 +1788,17 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
                goto out;
        }
 
+       /* Task aborts are not supported for volumes.
+        */
+       if (vdevice->vtarget->raidVolume) {
+               dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                   "task abort: raid volume (sc=%p)\n",
+                   ioc->name, SCpnt));
+               SCpnt->result = DID_RESET << 16;
+               retval = FAILED;
+               goto out;
+       }
+
        /* Find this command
         */
        if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
@@ -1991,7 +1998,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
        /*  If our attempts to reset the host failed, then return a failed
         *  status.  The host will be taken off line by the SCSI mid-layer.
         */
-    retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+    retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
        if (retval < 0)
                status = FAILED;
        else
@@ -2344,6 +2351,8 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
        vdevice = sdev->hostdata;
+       if (!vdevice)
+               return;
 
        mptscsih_search_running_cmds(hd, vdevice);
        vtarget->num_luns--;
@@ -3040,7 +3049,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
                if (!timeleft) {
                        printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
                            ioc->name, __func__);
-                       mpt_HardResetHandler(ioc, CAN_SLEEP);
+                       mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
                        mpt_free_msg_frame(ioc, mf);
                }
                goto out;
index e443651..1abaa5d 100644 (file)
@@ -210,6 +210,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
        target->maxOffset = offset;
        target->maxWidth = width;
 
+       spi_min_period(scsi_target(sdev)) = factor;
+       spi_max_offset(scsi_target(sdev)) = offset;
+       spi_max_width(scsi_target(sdev)) = width;
+
        target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
 
        /* Disable unused features.
@@ -558,6 +562,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
        cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
        cfg.dir = 0;
        cfg.pageAddr = starget->id;
+       cfg.timeout = 60;
 
        if (mpt_config(ioc, &cfg)) {
                starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
@@ -1152,6 +1157,9 @@ mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
        u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
        struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
 
+       if (ioc->bus_type != SPI)
+               return 0;
+
        if (hd && event ==  MPI_EVENT_INTEGRATED_RAID) {
                int reason
                        = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
@@ -1283,6 +1291,8 @@ mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
        int rc;
 
        rc = mptscsih_ioc_reset(ioc, reset_phase);
+       if ((ioc->bus_type != SPI) || (!rc))
+               return rc;
 
        /* only try to do a renegotiation if we're properly set up
         * if we get an ioc fault on bringup, ioc->sh will be NULL */
index 1e6183a..e331df2 100644 (file)
@@ -425,7 +425,8 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter)
 {
        while (atomic_read(&adapter->stat_miss) > 0)
                if (zfcp_fsf_status_read(adapter->qdio)) {
-                       if (atomic_read(&adapter->stat_miss) >= 16) {
+                       if (atomic_read(&adapter->stat_miss) >=
+                           adapter->stat_read_buf_num) {
                                zfcp_erp_adapter_reopen(adapter, 0, "axsref1",
                                                        NULL);
                                return 1;
@@ -545,6 +546,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
                               &zfcp_sysfs_adapter_attrs))
                goto failed;
 
+       /* report size limit per scatter-gather segment */
+       adapter->dma_parms.max_segment_size = ZFCP_QDIO_SBALE_LEN;
+       adapter->ccw_device->dev.dma_parms = &adapter->dma_parms;
+
        if (!zfcp_adapter_scsi_register(adapter))
                return adapter;
 
index 7131c7d..9fa1b06 100644 (file)
@@ -44,23 +44,6 @@ struct zfcp_reqlist;
 /********************* SCSI SPECIFIC DEFINES *********************************/
 #define ZFCP_SCSI_ER_TIMEOUT                    (10*HZ)
 
-/********************* CIO/QDIO SPECIFIC DEFINES *****************************/
-
-/* DMQ bug workaround: don't use last SBALE */
-#define ZFCP_MAX_SBALES_PER_SBAL       (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
-
-/* index of last SBALE (with respect to DMQ bug workaround) */
-#define ZFCP_LAST_SBALE_PER_SBAL       (ZFCP_MAX_SBALES_PER_SBAL - 1)
-
-/* max. number of (data buffer) SBALEs in largest SBAL chain */
-#define ZFCP_MAX_SBALES_PER_REQ                \
-       (FSF_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2)
-        /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
-
-#define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8)
-        /* max. number of (data buffer) SBALEs in largest SBAL chain
-           multiplied with number of sectors per 4k block */
-
 /********************* FSF SPECIFIC DEFINES *********************************/
 
 /* ATTENTION: value must not be used by hardware */
@@ -181,6 +164,7 @@ struct zfcp_adapter {
                                                      stack abort/command
                                                      completion races */
        atomic_t                stat_miss;         /* # missing status reads*/
+       unsigned int            stat_read_buf_num;
        struct work_struct      stat_work;
        atomic_t                status;            /* status of this adapter */
        struct list_head        erp_ready_head;    /* error recovery for this
@@ -205,6 +189,7 @@ struct zfcp_adapter {
        struct work_struct      scan_work;
        struct service_level    service_level;
        struct workqueue_struct *work_queue;
+       struct device_dma_parameters dma_parms;
 };
 
 struct zfcp_port {
index 0be5e7e..e3dbeda 100644 (file)
@@ -714,7 +714,7 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
        if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
                return ZFCP_ERP_FAILED;
 
-       atomic_set(&act->adapter->stat_miss, 16);
+       atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
        if (zfcp_status_read_refill(act->adapter))
                return ZFCP_ERP_FAILED;
 
index 8786a79..48a8f93 100644 (file)
@@ -3,7 +3,7 @@
  *
  * External function declarations.
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #ifndef ZFCP_EXT_H
@@ -143,9 +143,9 @@ extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);
 /* zfcp_qdio.c */
 extern int zfcp_qdio_setup(struct zfcp_adapter *);
 extern void zfcp_qdio_destroy(struct zfcp_qdio *);
+extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
 extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
-extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *,
-                                  struct zfcp_qdio_req *, unsigned long,
+extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
                                   struct scatterlist *, int);
 extern int zfcp_qdio_open(struct zfcp_qdio *);
 extern void zfcp_qdio_close(struct zfcp_qdio *);
index 2a1cbb7..6f8ab43 100644 (file)
@@ -400,7 +400,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
        struct zfcp_adapter *adapter = port->adapter;
        int ret;
 
-       adisc = kmem_cache_alloc(zfcp_data.adisc_cache, GFP_ATOMIC);
+       adisc = kmem_cache_zalloc(zfcp_data.adisc_cache, GFP_ATOMIC);
        if (!adisc)
                return -ENOMEM;
 
@@ -493,7 +493,7 @@ static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num)
        if (!gpn_ft)
                return NULL;
 
-       req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
+       req = kmem_cache_zalloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
        if (!req) {
                kfree(gpn_ft);
                gpn_ft = NULL;
index b3b1d2f..9ac6a6e 100644 (file)
@@ -496,6 +496,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
 
        adapter->hydra_version = bottom->adapter_type;
        adapter->timer_ticks = bottom->timer_interval;
+       adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)16);
 
        if (fc_host_permanent_port_name(shost) == -1)
                fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
@@ -640,37 +641,6 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
        }
 }
 
-static int zfcp_fsf_sbal_check(struct zfcp_qdio *qdio)
-{
-       struct zfcp_qdio_queue *req_q = &qdio->req_q;
-
-       spin_lock_bh(&qdio->req_q_lock);
-       if (atomic_read(&req_q->count))
-               return 1;
-       spin_unlock_bh(&qdio->req_q_lock);
-       return 0;
-}
-
-static int zfcp_fsf_req_sbal_get(struct zfcp_qdio *qdio)
-{
-       struct zfcp_adapter *adapter = qdio->adapter;
-       long ret;
-
-       spin_unlock_bh(&qdio->req_q_lock);
-       ret = wait_event_interruptible_timeout(qdio->req_q_wq,
-                              zfcp_fsf_sbal_check(qdio), 5 * HZ);
-       if (ret > 0)
-               return 0;
-       if (!ret) {
-               atomic_inc(&qdio->req_q_full);
-               /* assume hanging outbound queue, try queue recovery */
-               zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
-       }
-
-       spin_lock_bh(&qdio->req_q_lock);
-       return -EIO;
-}
-
 static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool)
 {
        struct zfcp_fsf_req *req;
@@ -705,10 +675,9 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)
 }
 
 static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
-                                               u32 fsf_cmd, mempool_t *pool)
+                                               u32 fsf_cmd, u32 sbtype,
+                                               mempool_t *pool)
 {
-       struct qdio_buffer_element *sbale;
-       struct zfcp_qdio_queue *req_q = &qdio->req_q;
        struct zfcp_adapter *adapter = qdio->adapter;
        struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool);
 
@@ -725,14 +694,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
        req->adapter = adapter;
        req->fsf_command = fsf_cmd;
        req->req_id = adapter->req_no;
-       req->qdio_req.sbal_number = 1;
-       req->qdio_req.sbal_first = req_q->first;
-       req->qdio_req.sbal_last = req_q->first;
-       req->qdio_req.sbale_curr = 1;
-
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].addr = (void *) req->req_id;
-       sbale[0].flags |= SBAL_FLAGS0_COMMAND;
 
        if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
                if (likely(pool))
@@ -753,10 +714,11 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
                req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
                req->qtcb->header.req_handle = req->req_id;
                req->qtcb->header.fsf_command = req->fsf_command;
-               sbale[1].addr = (void *) req->qtcb;
-               sbale[1].length = sizeof(struct fsf_qtcb);
        }
 
+       zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype,
+                          req->qtcb, sizeof(struct fsf_qtcb));
+
        if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
                zfcp_fsf_req_free(req);
                return ERR_PTR(-EIO);
@@ -803,24 +765,19 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
        struct zfcp_adapter *adapter = qdio->adapter;
        struct zfcp_fsf_req *req;
        struct fsf_status_read_buffer *sr_buf;
-       struct qdio_buffer_element *sbale;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
-       req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
+       req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0,
                                  adapter->pool.status_read_req);
        if (IS_ERR(req)) {
                retval = PTR_ERR(req);
                goto out;
        }
 
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
-       req->qdio_req.sbale_curr = 2;
-
        sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC);
        if (!sr_buf) {
                retval = -ENOMEM;
@@ -828,9 +785,9 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
        }
        memset(sr_buf, 0, sizeof(*sr_buf));
        req->data = sr_buf;
-       sbale = zfcp_qdio_sbale_curr(qdio, &req->qdio_req);
-       sbale->addr = (void *) sr_buf;
-       sbale->length = sizeof(*sr_buf);
+
+       zfcp_qdio_fill_next(qdio, &req->qdio_req, sr_buf, sizeof(*sr_buf));
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        retval = zfcp_fsf_req_send(req);
        if (retval)
@@ -907,14 +864,14 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
 struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
                                                struct zfcp_unit *unit)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_fsf_req *req = NULL;
        struct zfcp_qdio *qdio = unit->port->adapter->qdio;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.scsi_abort);
        if (IS_ERR(req)) {
                req = NULL;
@@ -925,9 +882,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
                       ZFCP_STATUS_COMMON_UNBLOCKED)))
                goto out_error_free;
 
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->data = unit;
        req->handler = zfcp_fsf_abort_fcp_command_handler;
@@ -996,21 +951,14 @@ skip_fsfstatus:
                ct->handler(ct->handler_data);
 }
 
-static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
+static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio,
+                                           struct zfcp_qdio_req *q_req,
                                            struct scatterlist *sg_req,
                                            struct scatterlist *sg_resp)
 {
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
-       sbale[2].addr   = sg_virt(sg_req);
-       sbale[2].length = sg_req->length;
-       sbale[3].addr   = sg_virt(sg_resp);
-       sbale[3].length = sg_resp->length;
-       sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
-}
-
-static int zfcp_fsf_one_sbal(struct scatterlist *sg)
-{
-       return sg_is_last(sg) && sg->length <= PAGE_SIZE;
+       zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_req), sg_req->length);
+       zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_resp), sg_resp->length);
+       zfcp_qdio_set_sbale_last(qdio, q_req);
 }
 
 static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
@@ -1019,35 +967,34 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
                                       int max_sbals)
 {
        struct zfcp_adapter *adapter = req->adapter;
-       struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio,
-                                                              &req->qdio_req);
        u32 feat = adapter->adapter_features;
        int bytes;
 
        if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
-               if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
+               if (!zfcp_qdio_sg_one_sbale(sg_req) ||
+                   !zfcp_qdio_sg_one_sbale(sg_resp))
                        return -EOPNOTSUPP;
 
-               zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
+               zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
+                                               sg_req, sg_resp);
                return 0;
        }
 
        /* use single, unchained SBAL if it can hold the request */
-       if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
-               zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
+       if (zfcp_qdio_sg_one_sbale(sg_req) || zfcp_qdio_sg_one_sbale(sg_resp)) {
+               zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
+                                               sg_req, sg_resp);
                return 0;
        }
 
        bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-                                       SBAL_FLAGS0_TYPE_WRITE_READ,
                                        sg_req, max_sbals);
        if (bytes <= 0)
                return -EIO;
        req->qtcb->bottom.support.req_buf_length = bytes;
-       req->qdio_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
+       zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
 
        bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-                                       SBAL_FLAGS0_TYPE_WRITE_READ,
                                        sg_resp, max_sbals);
        req->qtcb->bottom.support.resp_buf_length = bytes;
        if (bytes <= 0)
@@ -1091,10 +1038,11 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
        int ret = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
-       req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, pool);
+       req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC,
+                                 SBAL_FLAGS0_TYPE_WRITE_READ, pool);
 
        if (IS_ERR(req)) {
                ret = PTR_ERR(req);
@@ -1103,7 +1051,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
        ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
-                                   FSF_MAX_SBALS_PER_REQ, timeout);
+                                   ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
        if (ret)
                goto failed_send;
 
@@ -1187,10 +1135,11 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
        int ret = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
-       req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, NULL);
+       req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS,
+                                 SBAL_FLAGS0_TYPE_WRITE_READ, NULL);
 
        if (IS_ERR(req)) {
                ret = PTR_ERR(req);
@@ -1224,16 +1173,16 @@ out:
 
 int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_fsf_req *req;
        struct zfcp_qdio *qdio = erp_action->adapter->qdio;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1242,9 +1191,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->qtcb->bottom.config.feature_selection =
                        FSF_FEATURE_CFDC |
@@ -1269,24 +1216,22 @@ out:
 int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
                                       struct fsf_qtcb_bottom_config *data)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_fsf_req *req = NULL;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out_unlock;
 
-       req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL);
+       req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
+                                 SBAL_FLAGS0_TYPE_READ, NULL);
 
        if (IS_ERR(req)) {
                retval = PTR_ERR(req);
                goto out_unlock;
        }
 
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
        req->handler = zfcp_fsf_exchange_config_data_handler;
 
        req->qtcb->bottom.config.feature_selection =
@@ -1320,7 +1265,6 @@ out_unlock:
 int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
 {
        struct zfcp_qdio *qdio = erp_action->adapter->qdio;
-       struct qdio_buffer_element *sbale;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
@@ -1328,10 +1272,11 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
                return -EOPNOTSUPP;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1340,9 +1285,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->handler = zfcp_fsf_exchange_port_data_handler;
        req->erp_action = erp_action;
@@ -1368,7 +1311,6 @@ out:
 int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
                                     struct fsf_qtcb_bottom_port *data)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_fsf_req *req = NULL;
        int retval = -EIO;
 
@@ -1376,10 +1318,11 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
                return -EOPNOTSUPP;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out_unlock;
 
-       req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, NULL);
+       req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
+                                 SBAL_FLAGS0_TYPE_READ, NULL);
 
        if (IS_ERR(req)) {
                retval = PTR_ERR(req);
@@ -1389,9 +1332,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
        if (data)
                req->data = data;
 
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->handler = zfcp_fsf_exchange_port_data_handler;
        zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
@@ -1485,17 +1426,17 @@ out:
  */
 int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_qdio *qdio = erp_action->adapter->qdio;
        struct zfcp_port *port = erp_action->port;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1504,9 +1445,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->handler = zfcp_fsf_open_port_handler;
        hton24(req->qtcb->bottom.support.d_id, port->d_id);
@@ -1556,16 +1495,16 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_qdio *qdio = erp_action->adapter->qdio;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1574,9 +1513,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->handler = zfcp_fsf_close_port_handler;
        req->data = erp_action->port;
@@ -1633,16 +1570,16 @@ out:
  */
 int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_qdio *qdio = wka_port->adapter->qdio;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (unlikely(IS_ERR(req))) {
@@ -1651,9 +1588,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->handler = zfcp_fsf_open_wka_port_handler;
        hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
@@ -1688,16 +1623,16 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_qdio *qdio = wka_port->adapter->qdio;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (unlikely(IS_ERR(req))) {
@@ -1706,9 +1641,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->handler = zfcp_fsf_close_wka_port_handler;
        req->data = wka_port;
@@ -1782,16 +1715,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_qdio *qdio = erp_action->adapter->qdio;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1800,9 +1733,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->data = erp_action->port;
        req->qtcb->header.port_handle = erp_action->port->handle;
@@ -1954,17 +1885,17 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_adapter *adapter = erp_action->adapter;
        struct zfcp_qdio *qdio = adapter->qdio;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -1973,9 +1904,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->qtcb->header.port_handle = erp_action->port->handle;
        req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
@@ -2041,16 +1970,16 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_qdio *qdio = erp_action->adapter->qdio;
        struct zfcp_fsf_req *req;
        int retval = -EIO;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN,
+                                 SBAL_FLAGS0_TYPE_READ,
                                  qdio->adapter->pool.erp_req);
 
        if (IS_ERR(req)) {
@@ -2059,9 +1988,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        req->qtcb->header.port_handle = erp_action->port->handle;
        req->qtcb->header.lun_handle = erp_action->unit->handle;
@@ -2289,8 +2216,11 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
                goto out;
        }
 
+       if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE)
+               sbtype = SBAL_FLAGS0_TYPE_WRITE;
+
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
-                                 adapter->pool.scsi_req);
+                                 sbtype, adapter->pool.scsi_req);
 
        if (IS_ERR(req)) {
                retval = PTR_ERR(req);
@@ -2298,7 +2228,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
        }
 
        req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-       get_device(&unit->dev);
        req->unit = unit;
        req->data = scsi_cmnd;
        req->handler = zfcp_fsf_send_fcp_command_handler;
@@ -2323,20 +2252,21 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
                break;
        case DMA_TO_DEVICE:
                req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
-               sbtype = SBAL_FLAGS0_TYPE_WRITE;
                break;
        case DMA_BIDIRECTIONAL:
                goto failed_scsi_cmnd;
        }
 
+       get_device(&unit->dev);
+
        fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
        zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
 
-       real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sbtype,
+       real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
                                             scsi_sglist(scsi_cmnd),
-                                            FSF_MAX_SBALS_PER_REQ);
+                                            ZFCP_FSF_MAX_SBALS_PER_REQ);
        if (unlikely(real_bytes < 0)) {
-               if (req->qdio_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) {
+               if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
                        dev_err(&adapter->ccw_device->dev,
                                "Oversize data package, unit 0x%016Lx "
                                "on port 0x%016Lx closed\n",
@@ -2371,7 +2301,6 @@ out:
  */
 struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_fsf_req *req = NULL;
        struct fcp_cmnd *fcp_cmnd;
        struct zfcp_qdio *qdio = unit->port->adapter->qdio;
@@ -2381,10 +2310,11 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
                return NULL;
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
        req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
+                                 SBAL_FLAGS0_TYPE_WRITE,
                                  qdio->adapter->pool.scsi_req);
 
        if (IS_ERR(req)) {
@@ -2401,9 +2331,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
        req->qtcb->bottom.io.service_class = FSF_CLASS_3;
        req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
 
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
-       sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+       zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
        fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
        zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags);
@@ -2432,7 +2360,6 @@ static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
 struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
                                           struct zfcp_fsf_cfdc *fsf_cfdc)
 {
-       struct qdio_buffer_element *sbale;
        struct zfcp_qdio *qdio = adapter->qdio;
        struct zfcp_fsf_req *req = NULL;
        struct fsf_qtcb_bottom_support *bottom;
@@ -2453,10 +2380,10 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
        }
 
        spin_lock_bh(&qdio->req_q_lock);
-       if (zfcp_fsf_req_sbal_get(qdio))
+       if (zfcp_qdio_sbal_get(qdio))
                goto out;
 
-       req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, NULL);
+       req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, direction, NULL);
        if (IS_ERR(req)) {
                retval = -EPERM;
                goto out;
@@ -2464,16 +2391,13 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
 
        req->handler = zfcp_fsf_control_file_handler;
 
-       sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-       sbale[0].flags |= direction;
-
        bottom = &req->qtcb->bottom.support;
        bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
        bottom->option = fsf_cfdc->option;
 
        bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
-                                       direction, fsf_cfdc->sg,
-                                       FSF_MAX_SBALS_PER_REQ);
+                                       fsf_cfdc->sg,
+                                       ZFCP_FSF_MAX_SBALS_PER_REQ);
        if (bytes != ZFCP_CFDC_MAX_SIZE) {
                zfcp_fsf_req_free(req);
                goto out;
index b3de682..519083f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Interface to the FSF support functions.
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #ifndef FSF_H
 #define FSF_CLASS_3                            0x00000003
 
 /* SBAL chaining */
-#define FSF_MAX_SBALS_PER_REQ                  36
+#define ZFCP_FSF_MAX_SBALS_PER_REQ             36
+
+/* max. number of (data buffer) SBALEs in largest SBAL chain
+ * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */
+#define ZFCP_FSF_MAX_SBALES_PER_REQ    \
+       (ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
 
 /* logging space behind QTCB */
 #define FSF_QTCB_LOG_SIZE                      1024
@@ -361,7 +366,7 @@ struct fsf_qtcb_bottom_config {
        u32 adapter_type;
        u8 res0;
        u8 peer_d_id[3];
-       u8 res1[2];
+       u16 status_read_buf_num;
        u16 timer_interval;
        u8 res2[9];
        u8 s_id[3];
index dbfa312..28117e1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Setup and helper functions to access QDIO.
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -151,8 +151,7 @@ static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
 }
 
 static struct qdio_buffer_element *
-zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-                    unsigned long sbtype)
+zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
        struct qdio_buffer_element *sbale;
 
@@ -180,17 +179,16 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
 
        /* set storage-block type for new SBAL */
        sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-       sbale->flags |= sbtype;
+       sbale->flags |= q_req->sbtype;
 
        return sbale;
 }
 
 static struct qdio_buffer_element *
-zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-                    unsigned int sbtype)
+zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
-       if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
-               return zfcp_qdio_sbal_chain(qdio, q_req, sbtype);
+       if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL)
+               return zfcp_qdio_sbal_chain(qdio, q_req);
        q_req->sbale_curr++;
        return zfcp_qdio_sbale_curr(qdio, q_req);
 }
@@ -206,62 +204,38 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
        zfcp_qdio_zero_sbals(sbal, first, count);
 }
 
-static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
-                               struct zfcp_qdio_req *q_req,
-                               unsigned int sbtype, void *start_addr,
-                               unsigned int total_length)
-{
-       struct qdio_buffer_element *sbale;
-       unsigned long remaining, length;
-       void *addr;
-
-       /* split segment up */
-       for (addr = start_addr, remaining = total_length; remaining > 0;
-            addr += length, remaining -= length) {
-               sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype);
-               if (!sbale) {
-                       atomic_inc(&qdio->req_q_full);
-                       zfcp_qdio_undo_sbals(qdio, q_req);
-                       return -EINVAL;
-               }
-
-               /* new piece must not exceed next page boundary */
-               length = min(remaining,
-                            (PAGE_SIZE - ((unsigned long)addr &
-                                          (PAGE_SIZE - 1))));
-               sbale->addr = addr;
-               sbale->length = length;
-       }
-       return 0;
-}
-
 /**
  * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
- * @fsf_req: request to be processed
- * @sbtype: SBALE flags
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_qdio_req
  * @sg: scatter-gather list
  * @max_sbals: upper bound for number of SBALs to be used
  * Returns: number of bytes, or error (negativ)
  */
 int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-                           unsigned long sbtype, struct scatterlist *sg,
-                           int max_sbals)
+                           struct scatterlist *sg, int max_sbals)
 {
        struct qdio_buffer_element *sbale;
-       int retval, bytes = 0;
+       int bytes = 0;
 
        /* figure out last allowed SBAL */
        zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
 
        /* set storage-block type for this request */
        sbale = zfcp_qdio_sbale_req(qdio, q_req);
-       sbale->flags |= sbtype;
+       sbale->flags |= q_req->sbtype;
 
        for (; sg; sg = sg_next(sg)) {
-               retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype,
-                                             sg_virt(sg), sg->length);
-               if (retval < 0)
-                       return retval;
+               sbale = zfcp_qdio_sbale_next(qdio, q_req);
+               if (!sbale) {
+                       atomic_inc(&qdio->req_q_full);
+                       zfcp_qdio_undo_sbals(qdio, q_req);
+                       return -EINVAL;
+               }
+
+               sbale->addr = sg_virt(sg);
+               sbale->length = sg->length;
+
                bytes += sg->length;
        }
 
@@ -272,6 +246,46 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
        return bytes;
 }
 
+static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
+{
+       struct zfcp_qdio_queue *req_q = &qdio->req_q;
+
+       spin_lock_bh(&qdio->req_q_lock);
+       if (atomic_read(&req_q->count))
+               return 1;
+       spin_unlock_bh(&qdio->req_q_lock);
+       return 0;
+}
+
+/**
+ * zfcp_qdio_sbal_get - get free sbal in request queue, wait if necessary
+ * @qdio: pointer to struct zfcp_qdio
+ *
+ * The req_q_lock must be held by the caller of this function, and
+ * this function may only be called from process context; it will
+ * sleep when waiting for a free sbal.
+ *
+ * Returns: 0 on success, -EIO if there is no free sbal after waiting.
+ */
+int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
+{
+       long ret;
+
+       spin_unlock_bh(&qdio->req_q_lock);
+       ret = wait_event_interruptible_timeout(qdio->req_q_wq,
+                              zfcp_qdio_sbal_check(qdio), 5 * HZ);
+       if (ret > 0)
+               return 0;
+       if (!ret) {
+               atomic_inc(&qdio->req_q_full);
+               /* assume hanging outbound queue, try queue recovery */
+               zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL);
+       }
+
+       spin_lock_bh(&qdio->req_q_lock);
+       return -EIO;
+}
+
 /**
  * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
  * @qdio: pointer to struct zfcp_qdio
index 8cca546..138fba5 100644 (file)
 
 #include <asm/qdio.h>
 
+#define ZFCP_QDIO_SBALE_LEN    PAGE_SIZE
+
+/* DMQ bug workaround: don't use last SBALE */
+#define ZFCP_QDIO_MAX_SBALES_PER_SBAL  (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
+
+/* index of last SBALE (with respect to DMQ bug workaround) */
+#define ZFCP_QDIO_LAST_SBALE_PER_SBAL  (ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1)
+
 /**
  * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
  * @sbal: qdio buffers
@@ -49,6 +57,7 @@ struct zfcp_qdio {
 
 /**
  * struct zfcp_qdio_req - qdio queue related values for a request
+ * @sbtype: sbal type flags for sbale 0
  * @sbal_number: number of free sbals
  * @sbal_first: first sbal for this request
  * @sbal_last: last sbal for this request
@@ -59,6 +68,7 @@ struct zfcp_qdio {
  * @qdio_inb_usage: usage of inbound queue
  */
 struct zfcp_qdio_req {
+       u32     sbtype;
        u8      sbal_number;
        u8      sbal_first;
        u8      sbal_last;
@@ -106,4 +116,98 @@ zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
                               q_req->sbale_curr);
 }
 
+/**
+ * zfcp_qdio_req_init - initialize qdio request
+ * @qdio: request queue where to start putting the request
+ * @q_req: the qdio request to start
+ * @req_id: The request id
+ * @sbtype: type flags to set for all sbals
+ * @data: First data block
+ * @len: Length of first data block
+ *
+ * This is the start of putting the request into the queue, the last
+ * step is passing the request to zfcp_qdio_send. The request queue
+ * lock must be held during the whole process from init to send.
+ */
+static inline
+void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
+                       unsigned long req_id, u32 sbtype, void *data, u32 len)
+{
+       struct qdio_buffer_element *sbale;
+
+       q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
+       q_req->sbal_number = 1;
+       q_req->sbtype = sbtype;
+
+       sbale = zfcp_qdio_sbale_req(qdio, q_req);
+       sbale->addr = (void *) req_id;
+       sbale->flags |= SBAL_FLAGS0_COMMAND;
+       sbale->flags |= sbtype;
+
+       q_req->sbale_curr = 1;
+       sbale++;
+       sbale->addr = data;
+       if (likely(data))
+               sbale->length = len;
+}
+
+/**
+ * zfcp_qdio_fill_next - Fill next sbale, only for single sbal requests
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_queue_req
+ *
+ * This is only required for single sbal requests, calling it when
+ * wrapping around to the next sbal is a bug.
+ */
+static inline
+void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
+                        void *data, u32 len)
+{
+       struct qdio_buffer_element *sbale;
+
+       BUG_ON(q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL);
+       q_req->sbale_curr++;
+       sbale = zfcp_qdio_sbale_curr(qdio, q_req);
+       sbale->addr = data;
+       sbale->length = len;
+}
+
+/**
+ * zfcp_qdio_set_sbale_last - set last entry flag in current sbale
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_queue_req
+ */
+static inline
+void zfcp_qdio_set_sbale_last(struct zfcp_qdio *qdio,
+                             struct zfcp_qdio_req *q_req)
+{
+       struct qdio_buffer_element *sbale;
+
+       sbale = zfcp_qdio_sbale_curr(qdio, q_req);
+       sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+}
+
+/**
+ * zfcp_qdio_sg_one_sbal - check if one sbale is enough for sg data
+ * @sg: The scatterlist where to check the data size
+ *
+ * Returns: 1 when one sbale is enough for the data in the scatterlist,
+ *         0 if not.
+ */
+static inline
+int zfcp_qdio_sg_one_sbale(struct scatterlist *sg)
+{
+       return sg_is_last(sg) && sg->length <= ZFCP_QDIO_SBALE_LEN;
+}
+
+/**
+ * zfcp_qdio_skip_to_last_sbale - skip to last sbale in sbal
+ * @q_req: The current zfcp_qdio_req
+ */
+static inline
+void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req)
+{
+       q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
+}
+
 #endif /* ZFCP_QDIO_H */
index 174b6d5..be5d2c6 100644 (file)
@@ -175,7 +175,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        struct zfcp_fsf_req *old_req, *abrt_req;
        unsigned long flags;
        unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
-       int retval = SUCCESS;
+       int retval = SUCCESS, ret;
        int retry = 3;
        char *dbf_tag;
 
@@ -200,7 +200,9 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
                        break;
 
                zfcp_erp_wait(adapter);
-               fc_block_scsi_eh(scpnt);
+               ret = fc_block_scsi_eh(scpnt);
+               if (ret)
+                       return ret;
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING)) {
                        zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
@@ -231,7 +233,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
        struct zfcp_unit *unit = scpnt->device->hostdata;
        struct zfcp_adapter *adapter = unit->port->adapter;
        struct zfcp_fsf_req *fsf_req = NULL;
-       int retval = SUCCESS;
+       int retval = SUCCESS, ret;
        int retry = 3;
 
        while (retry--) {
@@ -240,7 +242,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
                        break;
 
                zfcp_erp_wait(adapter);
-               fc_block_scsi_eh(scpnt);
+               ret = fc_block_scsi_eh(scpnt);
+               if (ret)
+                       return ret;
+
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING)) {
                        zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
@@ -276,10 +281,13 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 {
        struct zfcp_unit *unit = scpnt->device->hostdata;
        struct zfcp_adapter *adapter = unit->port->adapter;
+       int ret;
 
        zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
        zfcp_erp_wait(adapter);
-       fc_block_scsi_eh(scpnt);
+       ret = fc_block_scsi_eh(scpnt);
+       if (ret)
+               return ret;
 
        return SUCCESS;
 }
@@ -669,11 +677,12 @@ struct zfcp_data zfcp_data = {
                .eh_host_reset_handler   = zfcp_scsi_eh_host_reset_handler,
                .can_queue               = 4096,
                .this_id                 = -1,
-               .sg_tablesize            = ZFCP_MAX_SBALES_PER_REQ,
+               .sg_tablesize            = ZFCP_FSF_MAX_SBALES_PER_REQ,
                .cmd_per_lun             = 1,
                .use_clustering          = 1,
                .sdev_attrs              = zfcp_sysfs_sdev_attrs,
-               .max_sectors             = (ZFCP_MAX_SBALES_PER_REQ * 8),
+               .max_sectors             = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8),
+               .dma_boundary            = ZFCP_QDIO_SBALE_LEN - 1,
                .shost_attrs             = zfcp_sysfs_shost_attrs,
        },
 };
index e9788f5..1bb774b 100644 (file)
@@ -1,10 +1,11 @@
 /*
    3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
 
-   Written By: Adam Radford <linuxraid@amcc.com>
-   Modifications By: Tom Couch <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
+   Modifications By: Tom Couch <linuxraid@lsi.com>
 
    Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
+   Copyright (C) 2010 LSI Corporation.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
    Bugs/Comments/Suggestions should be mailed to:
-   linuxraid@amcc.com
+   linuxraid@lsi.com
 
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 
    Note: This version of the driver does not contain a bundled firmware
          image.
@@ -77,6 +78,7 @@
                  Use pci_resource_len() for ioremap().
    2.26.02.012 - Add power management support.
    2.26.02.013 - Fix bug in twa_load_sgl().
+   2.26.02.014 - Force 60 second timeout default.
 */
 
 #include <linux/module.h>
 #include "3w-9xxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.013"
+#define TW_DRIVER_VERSION "2.26.02.014"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
 extern struct timezone sys_tz;
 
 /* Module parameters */
-MODULE_AUTHOR ("AMCC");
+MODULE_AUTHOR ("LSI");
 MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(TW_DRIVER_VERSION);
@@ -1990,6 +1992,15 @@ static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
                scsi_dma_unmap(cmd);
 } /* End twa_unmap_scsi_data() */
 
+/* This function gets called when a disk is coming on-line */
+static int twa_slave_configure(struct scsi_device *sdev)
+{
+       /* Force 60 second timeout */
+       blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
+
+       return 0;
+} /* End twa_slave_configure() */
+
 /* scsi_host_template initializer */
 static struct scsi_host_template driver_template = {
        .module                 = THIS_MODULE,
@@ -1999,6 +2010,7 @@ static struct scsi_host_template driver_template = {
        .bios_param             = twa_scsi_biosparam,
        .change_queue_depth     = twa_change_queue_depth,
        .can_queue              = TW_Q_LENGTH-2,
+       .slave_configure        = twa_slave_configure,
        .this_id                = -1,
        .sg_tablesize           = TW_APACHE_MAX_SGL_LENGTH,
        .max_sectors            = TW_MAX_SECTORS,
index 2893eec..3343824 100644 (file)
@@ -1,10 +1,11 @@
 /*
    3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux.
 
-   Written By: Adam Radford <linuxraid@amcc.com>
-   Modifications By: Tom Couch <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
+   Modifications By: Tom Couch <linuxraid@lsi.com>
 
    Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
+   Copyright (C) 2010 LSI Corporation.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
    Bugs/Comments/Suggestions should be mailed to:
-   linuxraid@amcc.com
+   linuxraid@lsi.com
 
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 */
 
 #ifndef _3W_9XXX_H
index 5faf903..d119a61 100644 (file)
@@ -1,12 +1,12 @@
 /* 
    3w-xxxx.c -- 3ware Storage Controller device driver for Linux.
 
-   Written By: Adam Radford <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
                     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2009 3ware Inc.
+   Copyright (C) 1999-2010 3ware Inc.
 
    Kernel compatibility By:    Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000      Andre Hedrick <andre@suse.com>
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
    Bugs/Comments/Suggestions should be mailed to:                            
-   linuxraid@amcc.com
+   linuxraid@lsi.com
 
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 
    History
    -------
    1.26.02.002 - Free irq handler in __tw_shutdown().
                  Turn on RCD bit for caching mode page.
                  Serialize reset code.
+   1.26.02.003 - Force 60 second timeout default.
 */
 
 #include <linux/module.h>
 #include "3w-xxxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "1.26.02.002"
+#define TW_DRIVER_VERSION "1.26.02.003"
 static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 static int tw_device_extension_count = 0;
 static int twe_major = -1;
 
 /* Module parameters */
-MODULE_AUTHOR("AMCC");
+MODULE_AUTHOR("LSI");
 MODULE_DESCRIPTION("3ware Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(TW_DRIVER_VERSION);
@@ -2245,6 +2246,15 @@ static void tw_shutdown(struct pci_dev *pdev)
        __tw_shutdown(tw_dev);
 } /* End tw_shutdown() */
 
+/* This function gets called when a disk is coming online */
+static int tw_slave_configure(struct scsi_device *sdev)
+{
+       /* Force 60 second timeout */
+       blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
+
+       return 0;
+} /* End tw_slave_configure() */
+
 static struct scsi_host_template driver_template = {
        .module                 = THIS_MODULE,
        .name                   = "3ware Storage Controller",
@@ -2253,6 +2263,7 @@ static struct scsi_host_template driver_template = {
        .bios_param             = tw_scsi_biosparam,
        .change_queue_depth     = tw_change_queue_depth,
        .can_queue              = TW_Q_LENGTH-2,
+       .slave_configure        = tw_slave_configure,
        .this_id                = -1,
        .sg_tablesize           = TW_MAX_SGL_LENGTH,
        .max_sectors            = TW_MAX_SECTORS,
index a5a2ba2..8b9f9d1 100644 (file)
@@ -1,12 +1,12 @@
 /* 
    3w-xxxx.h -- 3ware Storage Controller device driver for Linux.
    
-   Written By: Adam Radford <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
                     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2009 3ware Inc.
+   Copyright (C) 1999-2010 3ware Inc.
 
    Kernel compatiblity By:     Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000      Andre Hedrick <andre@suse.com>
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
    Bugs/Comments/Suggestions should be mailed to:                            
-   linuxraid@amcc.com
+   linuxraid@lsi.com
    
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 */
 
 #ifndef _3W_XXXX_H
index 92a8c50..1c7ac49 100644 (file)
@@ -162,6 +162,7 @@ scsi_mod-y                  += scsi_scan.o scsi_sysfs.o scsi_devinfo.o
 scsi_mod-$(CONFIG_SCSI_NETLINK)        += scsi_netlink.o
 scsi_mod-$(CONFIG_SYSCTL)      += scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)        += scsi_proc.o
+scsi_mod-y                     += scsi_trace.o
 
 scsi_tgt-y                     += scsi_tgt_lib.o scsi_tgt_if.o
 
index d8fe5b7..308541f 100644 (file)
 #include "wd33c93.h"
 #include "a2091.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
-#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
-#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
 
 static int a2091_release(struct Scsi_Host *instance);
 
-static irqreturn_t a2091_intr (int irq, void *_instance)
+static irqreturn_t a2091_intr(int irq, void *data)
 {
-    unsigned long flags;
-    unsigned int status;
-    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
-
-    status = DMA(instance)->ISTR;
-    if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS))
-       return IRQ_NONE;
-
-    spin_lock_irqsave(instance->host_lock, flags);
-    wd33c93_intr(instance);
-    spin_unlock_irqrestore(instance->host_lock, flags);
-    return IRQ_HANDLED;
+       struct Scsi_Host *instance = data;
+       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       unsigned int status = regs->ISTR;
+       unsigned long flags;
+
+       if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS))
+               return IRQ_NONE;
+
+       spin_lock_irqsave(instance->host_lock, flags);
+       wd33c93_intr(instance);
+       spin_unlock_irqrestore(instance->host_lock, flags);
+       return IRQ_HANDLED;
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
-    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-    struct Scsi_Host *instance = cmd->device->host;
-
-    /* don't allow DMA if the physical address is bad */
-    if (addr & A2091_XFER_MASK)
-    {
-       HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
-           & ~0x1ff;
-       HDATA(instance)->dma_bounce_buffer =
-           kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL);
-       
-       /* can't allocate memory; use PIO */
-       if (!HDATA(instance)->dma_bounce_buffer) {
-           HDATA(instance)->dma_bounce_len = 0;
-           return 1;
-       }
-
-       /* get the physical address of the bounce buffer */
-       addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+       unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
-       /* the bounce buffer may not be in the first 16M of physmem */
+       /* don't allow DMA if the physical address is bad */
        if (addr & A2091_XFER_MASK) {
-           /* we could use chipmem... maybe later */
-           kfree (HDATA(instance)->dma_bounce_buffer);
-           HDATA(instance)->dma_bounce_buffer = NULL;
-           HDATA(instance)->dma_bounce_len = 0;
-           return 1;
+               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+               hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
+                                                  GFP_KERNEL);
+
+               /* can't allocate memory; use PIO */
+               if (!hdata->dma_bounce_buffer) {
+                       hdata->dma_bounce_len = 0;
+                       return 1;
+               }
+
+               /* get the physical address of the bounce buffer */
+               addr = virt_to_bus(hdata->dma_bounce_buffer);
+
+               /* the bounce buffer may not be in the first 16M of physmem */
+               if (addr & A2091_XFER_MASK) {
+                       /* we could use chipmem... maybe later */
+                       kfree(hdata->dma_bounce_buffer);
+                       hdata->dma_bounce_buffer = NULL;
+                       hdata->dma_bounce_len = 0;
+                       return 1;
+               }
+
+               if (!dir_in) {
+                       /* copy to bounce buffer for a write */
+                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                              cmd->SCp.this_residual);
+               }
        }
 
-       if (!dir_in) {
-               /* copy to bounce buffer for a write */
-               memcpy (HDATA(instance)->dma_bounce_buffer,
-                       cmd->SCp.ptr, cmd->SCp.this_residual);
-       }
-    }
+       /* setup dma direction */
+       if (!dir_in)
+               cntr |= CNTR_DDIR;
 
-    /* setup dma direction */
-    if (!dir_in)
-       cntr |= CNTR_DDIR;
+       /* remember direction */
+       hdata->dma_dir = dir_in;
 
-    /* remember direction */
-    HDATA(cmd->device->host)->dma_dir = dir_in;
+       regs->CNTR = cntr;
 
-    DMA(cmd->device->host)->CNTR = cntr;
+       /* setup DMA *physical* address */
+       regs->ACR = addr;
 
-    /* setup DMA *physical* address */
-    DMA(cmd->device->host)->ACR = addr;
-
-    if (dir_in){
-       /* invalidate any cache */
-       cache_clear (addr, cmd->SCp.this_residual);
-    }else{
-       /* push any dirty cache */
-       cache_push (addr, cmd->SCp.this_residual);
-      }
-    /* start DMA */
-    DMA(cmd->device->host)->ST_DMA = 1;
+       if (dir_in) {
+               /* invalidate any cache */
+               cache_clear(addr, cmd->SCp.this_residual);
+       } else {
+               /* push any dirty cache */
+               cache_push(addr, cmd->SCp.this_residual);
+       }
+       /* start DMA */
+       regs->ST_DMA = 1;
 
-    /* return success */
-    return 0;
+       /* return success */
+       return 0;
 }
 
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
-                     int status)
+                    int status)
 {
-    /* disable SCSI interrupts */
-    unsigned short cntr = CNTR_PDMD;
-
-    if (!HDATA(instance)->dma_dir)
-           cntr |= CNTR_DDIR;
-
-    /* disable SCSI interrupts */
-    DMA(instance)->CNTR = cntr;
-
-    /* flush if we were reading */
-    if (HDATA(instance)->dma_dir) {
-       DMA(instance)->FLUSH = 1;
-       while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
-           ;
-    }
-
-    /* clear a possible interrupt */
-    DMA(instance)->CINT = 1;
-
-    /* stop DMA */
-    DMA(instance)->SP_DMA = 1;
-
-    /* restore the CONTROL bits (minus the direction flag) */
-    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
-
-    /* copy from a bounce buffer, if necessary */
-    if (status && HDATA(instance)->dma_bounce_buffer) {
-       if( HDATA(instance)->dma_dir )
-               memcpy (SCpnt->SCp.ptr, 
-                       HDATA(instance)->dma_bounce_buffer,
-                       SCpnt->SCp.this_residual);
-       kfree (HDATA(instance)->dma_bounce_buffer);
-       HDATA(instance)->dma_bounce_buffer = NULL;
-       HDATA(instance)->dma_bounce_len = 0;
-    }
+       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+
+       /* disable SCSI interrupts */
+       unsigned short cntr = CNTR_PDMD;
+
+       if (!hdata->dma_dir)
+               cntr |= CNTR_DDIR;
+
+       /* disable SCSI interrupts */
+       regs->CNTR = cntr;
+
+       /* flush if we were reading */
+       if (hdata->dma_dir) {
+               regs->FLUSH = 1;
+               while (!(regs->ISTR & ISTR_FE_FLG))
+                       ;
+       }
+
+       /* clear a possible interrupt */
+       regs->CINT = 1;
+
+       /* stop DMA */
+       regs->SP_DMA = 1;
+
+       /* restore the CONTROL bits (minus the direction flag) */
+       regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+       /* copy from a bounce buffer, if necessary */
+       if (status && hdata->dma_bounce_buffer) {
+               if (hdata->dma_dir)
+                       memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+                              SCpnt->SCp.this_residual);
+               kfree(hdata->dma_bounce_buffer);
+               hdata->dma_bounce_buffer = NULL;
+               hdata->dma_bounce_len = 0;
+       }
 }
 
 static int __init a2091_detect(struct scsi_host_template *tpnt)
 {
-    static unsigned char called = 0;
-    struct Scsi_Host *instance;
-    unsigned long address;
-    struct zorro_dev *z = NULL;
-    wd33c93_regs regs;
-    int num_a2091 = 0;
-
-    if (!MACH_IS_AMIGA || called)
-       return 0;
-    called = 1;
-
-    tpnt->proc_name = "A2091";
-    tpnt->proc_info = &wd33c93_proc_info;
-
-    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-       if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
-           z->id != ZORRO_PROD_CBM_A590_A2091_2)
-           continue;
-       address = z->resource.start;
-       if (!request_mem_region(address, 256, "wd33c93"))
-           continue;
-
-       instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
-       if (instance == NULL)
-           goto release;
-       instance->base = ZTWO_VADDR(address);
-       instance->irq = IRQ_AMIGA_PORTS;
-       instance->unique_id = z->slotaddr;
-       DMA(instance)->DAWR = DAWR_A2091;
-       regs.SASR = &(DMA(instance)->SASR);
-       regs.SCMD = &(DMA(instance)->SCMD);
-       HDATA(instance)->no_sync = 0xff;
-       HDATA(instance)->fast = 0;
-       HDATA(instance)->dma_mode = CTRL_DMA;
-       wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
-       if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI",
-                       instance))
-           goto unregister;
-       DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
-       num_a2091++;
-       continue;
+       static unsigned char called = 0;
+       struct Scsi_Host *instance;
+       unsigned long address;
+       struct zorro_dev *z = NULL;
+       wd33c93_regs wdregs;
+       a2091_scsiregs *regs;
+       struct WD33C93_hostdata *hdata;
+       int num_a2091 = 0;
+
+       if (!MACH_IS_AMIGA || called)
+               return 0;
+       called = 1;
+
+       tpnt->proc_name = "A2091";
+       tpnt->proc_info = &wd33c93_proc_info;
+
+       while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+               if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
+                   z->id != ZORRO_PROD_CBM_A590_A2091_2)
+                       continue;
+               address = z->resource.start;
+               if (!request_mem_region(address, 256, "wd33c93"))
+                       continue;
+
+               instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+               if (instance == NULL)
+                       goto release;
+               instance->base = ZTWO_VADDR(address);
+               instance->irq = IRQ_AMIGA_PORTS;
+               instance->unique_id = z->slotaddr;
+               regs = (a2091_scsiregs *)(instance->base);
+               regs->DAWR = DAWR_A2091;
+               wdregs.SASR = &regs->SASR;
+               wdregs.SCMD = &regs->SCMD;
+               hdata = shost_priv(instance);
+               hdata->no_sync = 0xff;
+               hdata->fast = 0;
+               hdata->dma_mode = CTRL_DMA;
+               wd33c93_init(instance, wdregs, dma_setup, dma_stop,
+                            WD33C93_FS_8_10);
+               if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
+                               "A2091 SCSI", instance))
+                       goto unregister;
+               regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+               num_a2091++;
+               continue;
 
 unregister:
-       scsi_unregister(instance);
-       wd33c93_release();
+               scsi_unregister(instance);
 release:
-       release_mem_region(address, 256);
-    }
+               release_mem_region(address, 256);
+       }
 
-    return num_a2091;
+       return num_a2091;
 }
 
 static int a2091_bus_reset(struct scsi_cmnd *cmd)
@@ -239,10 +243,11 @@ static struct scsi_host_template driver_template = {
 static int a2091_release(struct Scsi_Host *instance)
 {
 #ifdef MODULE
-       DMA(instance)->CNTR = 0;
+       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+
+       regs->CNTR = 0;
        release_mem_region(ZTWO_PADDR(instance->base), 256);
        free_irq(IRQ_AMIGA_PORTS, instance);
-       wd33c93_release();
 #endif
        return 1;
 }
index 252528f..1c3daa1 100644 (file)
 #include <linux/types.h>
 
 #ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
+#define CMD_PER_LUN            2
 #endif
 
 #ifndef CAN_QUEUE
-#define CAN_QUEUE 16
+#define CAN_QUEUE              16
 #endif
 
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
-#define A2091_XFER_MASK  (0xff000001)
+#define A2091_XFER_MASK                (0xff000001)
 
 typedef struct {
-             unsigned char      pad1[64];
-    volatile unsigned short     ISTR;
-    volatile unsigned short     CNTR;
-             unsigned char      pad2[60];
-    volatile unsigned int       WTC;
-    volatile unsigned long      ACR;
-             unsigned char      pad3[6];
-    volatile unsigned short     DAWR;
-             unsigned char      pad4;
-    volatile unsigned char      SASR;
-             unsigned char      pad5;
-    volatile unsigned char      SCMD;
-             unsigned char      pad6[76];
-    volatile unsigned short     ST_DMA;
-    volatile unsigned short     SP_DMA;
-    volatile unsigned short     CINT;
-             unsigned char      pad7[2];
-    volatile unsigned short     FLUSH;
+                unsigned char  pad1[64];
+       volatile unsigned short ISTR;
+       volatile unsigned short CNTR;
+                unsigned char  pad2[60];
+       volatile unsigned int   WTC;
+       volatile unsigned long  ACR;
+                unsigned char  pad3[6];
+       volatile unsigned short DAWR;
+                unsigned char  pad4;
+       volatile unsigned char  SASR;
+                unsigned char  pad5;
+       volatile unsigned char  SCMD;
+                unsigned char  pad6[76];
+       volatile unsigned short ST_DMA;
+       volatile unsigned short SP_DMA;
+       volatile unsigned short CINT;
+                unsigned char  pad7[2];
+       volatile unsigned short FLUSH;
 } a2091_scsiregs;
 
 #define DAWR_A2091             (3)
index c35fc55..bc6eb69 100644 (file)
 #include "wd33c93.h"
 #include "a3000.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
-#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
-#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+#define DMA(ptr)       ((a3000_scsiregs *)((ptr)->base))
 
 static struct Scsi_Host *a3000_host = NULL;
 
 static int a3000_release(struct Scsi_Host *instance);
 
-static irqreturn_t a3000_intr (int irq, void *dummy)
+static irqreturn_t a3000_intr(int irq, void *dummy)
 {
        unsigned long flags;
        unsigned int status = DMA(a3000_host)->ISTR;
 
        if (!(status & ISTR_INT_P))
                return IRQ_NONE;
-       if (status & ISTR_INTS)
-       {
+       if (status & ISTR_INTS) {
                spin_lock_irqsave(a3000_host->host_lock, flags);
-               wd33c93_intr (a3000_host);
+               wd33c93_intr(a3000_host);
                spin_unlock_irqrestore(a3000_host->host_lock, flags);
                return IRQ_HANDLED;
        }
@@ -48,162 +47,165 @@ static irqreturn_t a3000_intr (int irq, void *dummy)
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
-    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-
-    /*
-     * if the physical address has the wrong alignment, or if
-     * physical address is bad, or if it is a write and at the
-     * end of a physical memory chunk, then allocate a bounce
-     * buffer
-     */
-    if (addr & A3000_XFER_MASK)
-    {
-       HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
-           & ~0x1ff;
-       HDATA(a3000_host)->dma_bounce_buffer =
-           kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL);
-       
-       /* can't allocate memory; use PIO */
-       if (!HDATA(a3000_host)->dma_bounce_buffer) {
-           HDATA(a3000_host)->dma_bounce_len = 0;
-           return 1;
-       }
-
-       if (!dir_in) {
-           /* copy to bounce buffer for a write */
-           memcpy (HDATA(a3000_host)->dma_bounce_buffer,
-               cmd->SCp.ptr, cmd->SCp.this_residual);
+       struct WD33C93_hostdata *hdata = shost_priv(a3000_host);
+       unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+       unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+
+       /*
+        * if the physical address has the wrong alignment, or if
+        * physical address is bad, or if it is a write and at the
+        * end of a physical memory chunk, then allocate a bounce
+        * buffer
+        */
+       if (addr & A3000_XFER_MASK) {
+               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+               hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
+                                                  GFP_KERNEL);
+
+               /* can't allocate memory; use PIO */
+               if (!hdata->dma_bounce_buffer) {
+                       hdata->dma_bounce_len = 0;
+                       return 1;
+               }
+
+               if (!dir_in) {
+                       /* copy to bounce buffer for a write */
+                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                              cmd->SCp.this_residual);
+               }
+
+               addr = virt_to_bus(hdata->dma_bounce_buffer);
        }
 
-       addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
-    }
+       /* setup dma direction */
+       if (!dir_in)
+               cntr |= CNTR_DDIR;
 
-    /* setup dma direction */
-    if (!dir_in)
-       cntr |= CNTR_DDIR;
+       /* remember direction */
+       hdata->dma_dir = dir_in;
 
-    /* remember direction */
-    HDATA(a3000_host)->dma_dir = dir_in;
+       DMA(a3000_host)->CNTR = cntr;
 
-    DMA(a3000_host)->CNTR = cntr;
+       /* setup DMA *physical* address */
+       DMA(a3000_host)->ACR = addr;
 
-    /* setup DMA *physical* address */
-    DMA(a3000_host)->ACR = addr;
-
-    if (dir_in)
-       /* invalidate any cache */
-       cache_clear (addr, cmd->SCp.this_residual);
-    else
-       /* push any dirty cache */
-       cache_push (addr, cmd->SCp.this_residual);
+       if (dir_in) {
+               /* invalidate any cache */
+               cache_clear(addr, cmd->SCp.this_residual);
+       } else {
+               /* push any dirty cache */
+               cache_push(addr, cmd->SCp.this_residual);
+       }
 
-    /* start DMA */
-    mb();                      /* make sure setup is completed */
-    DMA(a3000_host)->ST_DMA = 1;
-    mb();                      /* make sure DMA has started before next IO */
+       /* start DMA */
+       mb();                   /* make sure setup is completed */
+       DMA(a3000_host)->ST_DMA = 1;
+       mb();                   /* make sure DMA has started before next IO */
 
-    /* return success */
-    return 0;
+       /* return success */
+       return 0;
 }
 
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-    /* disable SCSI interrupts */
-    unsigned short cntr = CNTR_PDMD;
-
-    if (!HDATA(instance)->dma_dir)
-       cntr |= CNTR_DDIR;
-
-    DMA(instance)->CNTR = cntr;
-    mb();                      /* make sure CNTR is updated before next IO */
-
-    /* flush if we were reading */
-    if (HDATA(instance)->dma_dir) {
-       DMA(instance)->FLUSH = 1;
-       mb();                   /* don't allow prefetch */
-       while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
-           barrier();
-       mb();                   /* no IO until FLUSH is done */
-    }
-
-    /* clear a possible interrupt */
-    /* I think that this CINT is only necessary if you are
-     * using the terminal count features.   HM 7 Mar 1994
-     */
-    DMA(instance)->CINT = 1;
-
-    /* stop DMA */
-    DMA(instance)->SP_DMA = 1;
-    mb();                      /* make sure DMA is stopped before next IO */
-
-    /* restore the CONTROL bits (minus the direction flag) */
-    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
-    mb();                      /* make sure CNTR is updated before next IO */
-
-    /* copy from a bounce buffer, if necessary */
-    if (status && HDATA(instance)->dma_bounce_buffer) {
-       if (SCpnt) {
-           if (HDATA(instance)->dma_dir && SCpnt)
-               memcpy (SCpnt->SCp.ptr,
-                       HDATA(instance)->dma_bounce_buffer,
-                       SCpnt->SCp.this_residual);
-           kfree (HDATA(instance)->dma_bounce_buffer);
-           HDATA(instance)->dma_bounce_buffer = NULL;
-           HDATA(instance)->dma_bounce_len = 0;
-       } else {
-           kfree (HDATA(instance)->dma_bounce_buffer);
-           HDATA(instance)->dma_bounce_buffer = NULL;
-           HDATA(instance)->dma_bounce_len = 0;
+       struct WD33C93_hostdata *hdata = shost_priv(instance);
+
+       /* disable SCSI interrupts */
+       unsigned short cntr = CNTR_PDMD;
+
+       if (!hdata->dma_dir)
+               cntr |= CNTR_DDIR;
+
+       DMA(instance)->CNTR = cntr;
+       mb();                   /* make sure CNTR is updated before next IO */
+
+       /* flush if we were reading */
+       if (hdata->dma_dir) {
+               DMA(instance)->FLUSH = 1;
+               mb();           /* don't allow prefetch */
+               while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+                       barrier();
+               mb();           /* no IO until FLUSH is done */
+       }
+
+       /* clear a possible interrupt */
+       /* I think that this CINT is only necessary if you are
+        * using the terminal count features.   HM 7 Mar 1994
+        */
+       DMA(instance)->CINT = 1;
+
+       /* stop DMA */
+       DMA(instance)->SP_DMA = 1;
+       mb();                   /* make sure DMA is stopped before next IO */
+
+       /* restore the CONTROL bits (minus the direction flag) */
+       DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+       mb();                   /* make sure CNTR is updated before next IO */
+
+       /* copy from a bounce buffer, if necessary */
+       if (status && hdata->dma_bounce_buffer) {
+               if (SCpnt) {
+                       if (hdata->dma_dir && SCpnt)
+                               memcpy(SCpnt->SCp.ptr,
+                                      hdata->dma_bounce_buffer,
+                                      SCpnt->SCp.this_residual);
+                       kfree(hdata->dma_bounce_buffer);
+                       hdata->dma_bounce_buffer = NULL;
+                       hdata->dma_bounce_len = 0;
+               } else {
+                       kfree(hdata->dma_bounce_buffer);
+                       hdata->dma_bounce_buffer = NULL;
+                       hdata->dma_bounce_len = 0;
+               }
        }
-    }
 }
 
 static int __init a3000_detect(struct scsi_host_template *tpnt)
 {
-    wd33c93_regs regs;
-
-    if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
-       return 0;
-    if (!request_mem_region(0xDD0000, 256, "wd33c93"))
-       return 0;
-
-    tpnt->proc_name = "A3000";
-    tpnt->proc_info = &wd33c93_proc_info;
-
-    a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
-    if (a3000_host == NULL)
-       goto fail_register;
-
-    a3000_host->base = ZTWO_VADDR(0xDD0000);
-    a3000_host->irq = IRQ_AMIGA_PORTS;
-    DMA(a3000_host)->DAWR = DAWR_A3000;
-    regs.SASR = &(DMA(a3000_host)->SASR);
-    regs.SCMD = &(DMA(a3000_host)->SCMD);
-    HDATA(a3000_host)->no_sync = 0xff;
-    HDATA(a3000_host)->fast = 0;
-    HDATA(a3000_host)->dma_mode = CTRL_DMA;
-    wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
-    if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
-                   a3000_intr))
-        goto fail_irq;
-    DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
-
-    return 1;
+       wd33c93_regs regs;
+       struct WD33C93_hostdata *hdata;
+
+       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
+               return 0;
+       if (!request_mem_region(0xDD0000, 256, "wd33c93"))
+               return 0;
+
+       tpnt->proc_name = "A3000";
+       tpnt->proc_info = &wd33c93_proc_info;
+
+       a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+       if (a3000_host == NULL)
+               goto fail_register;
+
+       a3000_host->base = ZTWO_VADDR(0xDD0000);
+       a3000_host->irq = IRQ_AMIGA_PORTS;
+       DMA(a3000_host)->DAWR = DAWR_A3000;
+       regs.SASR = &(DMA(a3000_host)->SASR);
+       regs.SCMD = &(DMA(a3000_host)->SCMD);
+       hdata = shost_priv(a3000_host);
+       hdata->no_sync = 0xff;
+       hdata->fast = 0;
+       hdata->dma_mode = CTRL_DMA;
+       wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
+       if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
+                       a3000_intr))
+               goto fail_irq;
+       DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+       return 1;
 
 fail_irq:
-    wd33c93_release();
-    scsi_unregister(a3000_host);
+       scsi_unregister(a3000_host);
 fail_register:
-    release_mem_region(0xDD0000, 256);
-    return 0;
+       release_mem_region(0xDD0000, 256);
+       return 0;
 }
 
 static int a3000_bus_reset(struct scsi_cmnd *cmd)
 {
        /* FIXME perform bus-specific reset */
-       
+
        /* FIXME 2: kill this entire function, which should
           cause mid-layer to call wd33c93_host_reset anyway? */
 
@@ -237,11 +239,10 @@ static struct scsi_host_template driver_template = {
 
 static int a3000_release(struct Scsi_Host *instance)
 {
-    wd33c93_release();
-    DMA(instance)->CNTR = 0;
-    release_mem_region(0xDD0000, 256);
-    free_irq(IRQ_AMIGA_PORTS, a3000_intr);
-    return 1;
+       DMA(instance)->CNTR = 0;
+       release_mem_region(0xDD0000, 256);
+       free_irq(IRQ_AMIGA_PORTS, a3000_intr);
+       return 1;
 }
 
 MODULE_LICENSE("GPL");
index c7afe16..684813e 100644 (file)
 #include <linux/types.h>
 
 #ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
+#define CMD_PER_LUN            2
 #endif
 
 #ifndef CAN_QUEUE
-#define CAN_QUEUE 16
+#define CAN_QUEUE              16
 #endif
 
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
-#define A3000_XFER_MASK  (0x00000003)
+#define A3000_XFER_MASK                (0x00000003)
 
 typedef struct {
-             unsigned char      pad1[2];
-    volatile unsigned short     DAWR;
-    volatile unsigned int       WTC;
-             unsigned char      pad2[2];
-    volatile unsigned short     CNTR;
-    volatile unsigned long      ACR;
-             unsigned char      pad3[2];
-    volatile unsigned short     ST_DMA;
-             unsigned char      pad4[2];
-    volatile unsigned short     FLUSH;
-             unsigned char      pad5[2];
-    volatile unsigned short     CINT;
-             unsigned char      pad6[2];
-    volatile unsigned short     ISTR;
-            unsigned char      pad7[30];
-    volatile unsigned short     SP_DMA;
-             unsigned char      pad8;
-    volatile unsigned char      SASR;
-             unsigned char      pad9;
-    volatile unsigned char      SCMD;
+                unsigned char  pad1[2];
+       volatile unsigned short DAWR;
+       volatile unsigned int   WTC;
+                unsigned char  pad2[2];
+       volatile unsigned short CNTR;
+       volatile unsigned long  ACR;
+                unsigned char  pad3[2];
+       volatile unsigned short ST_DMA;
+                unsigned char  pad4[2];
+       volatile unsigned short FLUSH;
+                unsigned char  pad5[2];
+       volatile unsigned short CINT;
+                unsigned char  pad6[2];
+       volatile unsigned short ISTR;
+                unsigned char  pad7[30];
+       volatile unsigned short SP_DMA;
+                unsigned char  pad8;
+       volatile unsigned char  SASR;
+                unsigned char  pad9;
+       volatile unsigned char  SCMD;
 } a3000_scsiregs;
 
 #define DAWR_A3000             (3)
index 7e26ebc..7df2dd1 100644 (file)
@@ -328,6 +328,16 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
        return status;
 }
 
+static void aac_expose_phy_device(struct scsi_cmnd *scsicmd)
+{
+       char inq_data;
+       scsi_sg_copy_to_buffer(scsicmd,  &inq_data, sizeof(inq_data));
+       if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) {
+               inq_data &= 0xdf;
+               scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
+       }
+}
+
 /**
  *     aac_get_containers      -       list containers
  *     @common: adapter to probe
@@ -1598,6 +1608,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
        int status;
        struct aac_dev *dev;
        struct fib * cmd_fibcontext;
+       int cid;
 
        dev = (struct aac_dev *)scsicmd->device->host->hostdata;
        /*
@@ -1647,6 +1658,22 @@ static int aac_read(struct scsi_cmnd * scsicmd)
                count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
                break;
        }
+
+       if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
+               cid = scmd_id(scsicmd);
+               dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_CHECK_CONDITION;
+               set_sense(&dev->fsa_dev[cid].sense_data,
+                         HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+                         ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
+               scsicmd->scsi_done(scsicmd);
+               return 1;
+       }
+
        dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
          smp_processor_id(), (unsigned long long)lba, jiffies));
        if (aac_adapter_bounds(dev,scsicmd,lba))
@@ -1688,6 +1715,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
        int status;
        struct aac_dev *dev;
        struct fib * cmd_fibcontext;
+       int cid;
 
        dev = (struct aac_dev *)scsicmd->device->host->hostdata;
        /*
@@ -1727,6 +1755,22 @@ static int aac_write(struct scsi_cmnd * scsicmd)
                count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
                fua = scsicmd->cmnd[1] & 0x8;
        }
+
+       if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
+               cid = scmd_id(scsicmd);
+               dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_CHECK_CONDITION;
+               set_sense(&dev->fsa_dev[cid].sense_data,
+                         HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+                         ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
+               scsicmd->scsi_done(scsicmd);
+               return 1;
+       }
+
        dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
          smp_processor_id(), (unsigned long long)lba, jiffies));
        if (aac_adapter_bounds(dev,scsicmd,lba))
@@ -2573,6 +2617,11 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 
        scsi_dma_unmap(scsicmd);
 
+       /* expose physical device if expose_physicald flag is on */
+       if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
+         && expose_physicals > 0)
+               aac_expose_phy_device(scsicmd);
+
        /*
         * First check the fib status
         */
@@ -2678,8 +2727,22 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
                        scsicmd->cmnd[0],
                        le32_to_cpu(srbreply->scsi_status));
 #endif
-               scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
-               break;
+               if ((scsicmd->cmnd[0] == ATA_12)
+                 || (scsicmd->cmnd[0] == ATA_16)) {
+                       if (scsicmd->cmnd[2] & (0x01 << 5)) {
+                               scsicmd->result = DID_OK << 16
+                                               | COMMAND_COMPLETE << 8;
+                               break;
+                       } else {
+                               scsicmd->result = DID_ERROR << 16
+                                               | COMMAND_COMPLETE << 8;
+                               break;
+                       }
+               } else {
+                       scsicmd->result = DID_ERROR << 16
+                                       | COMMAND_COMPLETE << 8;
+                       break;
+               }
        }
        if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
                int len;
index 619c02d..4dbcc05 100644 (file)
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 24702
+# define AAC_DRIVER_BUILD 26400
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
@@ -26,6 +26,8 @@
 #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
 #define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)256)
 
+#define AAC_DEBUG_INSTRUMENT_AIF_DELETE
+
 /*
  * These macros convert from physical channels to virtual channels
  */
index 94d2954..7007914 100644 (file)
@@ -966,6 +966,16 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                        device_config_needed =
                          (((__le32 *)aifcmd->data)[0] ==
                            cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
+                       if (device_config_needed == ADD) {
+                               device = scsi_device_lookup(dev->scsi_host_ptr,
+                                       channel,
+                                       id,
+                                       lun);
+                               if (device) {
+                                       scsi_remove_device(device);
+                                       scsi_device_put(device);
+                               }
+                       }
                        break;
 
                case AifEnEnclosureManagement:
@@ -1123,6 +1133,9 @@ retry_next:
        if (device) {
                switch (device_config_needed) {
                case DELETE:
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
+                       scsi_remove_device(device);
+#else
                        if (scsi_device_online(device)) {
                                scsi_device_set_state(device, SDEV_OFFLINE);
                                sdev_printk(KERN_INFO, device,
@@ -1131,6 +1144,7 @@ retry_next:
                                                "array deleted" :
                                                "enclosure services event");
                        }
+#endif
                        break;
                case ADD:
                        if (!scsi_device_online(device)) {
@@ -1145,12 +1159,16 @@ retry_next:
                case CHANGE:
                        if ((channel == CONTAINER_CHANNEL)
                         && (!dev->fsa_dev[container].valid)) {
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
+                               scsi_remove_device(device);
+#else
                                if (!scsi_device_online(device))
                                        break;
                                scsi_device_set_state(device, SDEV_OFFLINE);
                                sdev_printk(KERN_INFO, device,
                                        "Device offlined - %s\n",
                                        "array failed");
+#endif
                                break;
                        }
                        scsi_rescan_device(&device->sdev_gendev);
index 961fe43..53a616f 100644 (file)
@@ -117,35 +117,6 @@ bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
 }
 
 /**
- * Get SG element for the I/O request given the SG element index
- */
-static inline union bfi_addr_u
-bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
-{
-       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-       struct scatterlist *sge;
-       u64        addr;
-
-       sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
-       addr = (u64) sg_dma_address(sge);
-
-       return *((union bfi_addr_u *) &addr);
-}
-
-static inline u32
-bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid)
-{
-       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-       struct scatterlist *sge;
-       u32        len;
-
-       sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
-       len = sg_dma_len(sge);
-
-       return len;
-}
-
-/**
  * Get Command Reference Number for the I/O request. 0 if none.
  */
 static inline u8
index 5b107ab..687f3d6 100644 (file)
@@ -731,6 +731,9 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
        static struct fcp_cmnd_s cmnd_z0 = { 0 };
        struct bfi_sge_s      *sge;
        u32        pgdlen = 0;
+       u64 addr;
+       struct scatterlist *sg;
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
 
        /**
         * check for room in queue to send request now
@@ -754,8 +757,10 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
         */
        sge = &m->sges[0];
        if (ioim->nsges) {
-               sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0);
-               pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0);
+               sg = (struct scatterlist *)scsi_sglist(cmnd);
+               addr = bfa_os_sgaddr(sg_dma_address(sg));
+               sge->sga = *(union bfi_addr_u *) &addr;
+               pgdlen = sg_dma_len(sg);
                sge->sg_len = pgdlen;
                sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
                                        BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
@@ -868,10 +873,16 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
        struct bfi_sge_s      *sge;
        struct bfa_sgpg_s *sgpg;
        u32        pgcumsz;
+       u64        addr;
+       struct scatterlist *sg;
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
 
        sgeid = BFI_SGE_INLINE;
        ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
 
+       sg = scsi_sglist(cmnd);
+       sg = sg_next(sg);
+
        do {
                sge = sgpg->sgpg->sges;
                nsges = ioim->nsges - sgeid;
@@ -879,9 +890,10 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
                        nsges = BFI_SGPG_DATA_SGES;
 
                pgcumsz = 0;
-               for (i = 0; i < nsges; i++, sge++, sgeid++) {
-                       sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid);
-                       sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid);
+               for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) {
+                       addr = bfa_os_sgaddr(sg_dma_address(sg));
+                       sge->sga = *(union bfi_addr_u *) &addr;
+                       sge->sg_len = sg_dma_len(sg);
                        pgcumsz += sge->sg_len;
 
                        /**
index 10a89f7..bd1cd3e 100644 (file)
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_transport.h>
 
+#ifdef __BIG_ENDIAN
+#define __BIGENDIAN
+#endif
+
 #define BFA_ERR                        KERN_ERR
 #define BFA_WARNING            KERN_WARNING
 #define BFA_NOTICE             KERN_NOTICE
@@ -123,6 +127,15 @@ int bfa_os_MWB(void *);
        (((_x) & 0x00ff0000) >> 8)      |       \
        (((_x) & 0xff000000) >> 24))
 
+#define bfa_os_swap_sgaddr(_x) ((u64)(                                 \
+       (((u64)(_x) & (u64)0x00000000000000ffull) << 32)        |       \
+       (((u64)(_x) & (u64)0x000000000000ff00ull) << 32)        |       \
+       (((u64)(_x) & (u64)0x0000000000ff0000ull) << 32)        |       \
+       (((u64)(_x) & (u64)0x00000000ff000000ull) << 32)        |       \
+       (((u64)(_x) & (u64)0x000000ff00000000ull) >> 32)        |       \
+       (((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32)        |       \
+       (((u64)(_x) & (u64)0x00ff000000000000ull) >> 32)        |       \
+       (((u64)(_x) & (u64)0xff00000000000000ull) >> 32)))
 
 #ifndef __BIGENDIAN
 #define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
@@ -133,6 +146,7 @@ int bfa_os_MWB(void *);
 #define bfa_os_hton3b(_x)      bfa_swap_3b(_x)
 
 #define bfa_os_wtole(_x)   (_x)
+#define bfa_os_sgaddr(_x)  (_x)
 
 #else
 
@@ -141,6 +155,7 @@ int bfa_os_MWB(void *);
 #define bfa_os_hton3b(_x)  (_x)
 #define bfa_os_htonll(_x)  (_x)
 #define bfa_os_wtole(_x)   bfa_os_swap32(_x)
+#define bfa_os_sgaddr(_x)  bfa_os_swap_sgaddr(_x)
 
 #endif
 
@@ -161,12 +176,12 @@ int bfa_os_MWB(void *);
 #define bfa_os_addr_t char __iomem *
 #define bfa_os_panic()
 
-#define bfa_os_reg_read(_raddr) bfa_os_wtole(readl(_raddr))
-#define bfa_os_reg_write(_raddr, _val) writel(bfa_os_wtole((_val)), (_raddr))
+#define bfa_os_reg_read(_raddr) readl(_raddr)
+#define bfa_os_reg_write(_raddr, _val) writel((_val), (_raddr))
 #define bfa_os_mem_read(_raddr, _off)                                   \
-       bfa_os_ntohl(readl(((_raddr) + (_off))))
+       bfa_os_swap32(readl(((_raddr) + (_off))))
 #define bfa_os_mem_write(_raddr, _off, _val)                            \
-       writel(bfa_os_htonl((_val)), ((_raddr) + (_off)))
+       writel(bfa_os_swap32((_val)), ((_raddr) + (_off)))
 
 #define BFA_TRC_TS(_trcm)                                              \
                        ({                                              \
index 13f5feb..d4fc428 100644 (file)
@@ -33,7 +33,7 @@
 #include <fcb/bfa_fcb.h>
 
 BFA_TRC_FILE(LDRV, BFAD);
-static DEFINE_MUTEX(bfad_mutex);
+DEFINE_MUTEX(bfad_mutex);
 LIST_HEAD(bfad_list);
 static int      bfad_inst;
 int bfad_supported_fc4s;
@@ -299,8 +299,6 @@ bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv)
                complete(vport_drv->comp_del);
                return;
        }
-
-       kfree(vport_drv);
 }
 
 /**
@@ -483,7 +481,7 @@ ext:
  */
 bfa_status_t
 bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
-                 struct bfa_port_cfg_s *port_cfg)
+                 struct bfa_port_cfg_s *port_cfg, struct device *dev)
 {
        struct bfad_vport_s *vport;
        int             rc = BFA_STATUS_OK;
@@ -506,7 +504,8 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
                goto ext_free_vport;
 
        if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) {
-               rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port);
+               rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port,
+                                                       dev);
                if (rc != BFA_STATUS_OK)
                        goto ext_free_fcs_vport;
        }
@@ -591,7 +590,6 @@ bfad_init_timer(struct bfad_s *bfad)
 int
 bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
 {
-       unsigned long   bar0_len;
        int             rc = -ENODEV;
 
        if (pci_enable_device(pdev)) {
@@ -611,9 +609,7 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
                        goto out_release_region;
                }
 
-       bfad->pci_bar0_map = pci_resource_start(pdev, 0);
-       bar0_len = pci_resource_len(pdev, 0);
-       bfad->pci_bar0_kva = ioremap(bfad->pci_bar0_map, bar0_len);
+       bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
 
        if (bfad->pci_bar0_kva == NULL) {
                BFA_PRINTF(BFA_ERR, "Fail to map bar0\n");
@@ -646,11 +642,7 @@ out:
 void
 bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
 {
-#if defined(__ia64__)
        pci_iounmap(pdev, bfad->pci_bar0_kva);
-#else
-       iounmap(bfad->pci_bar0_kva);
-#endif
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
@@ -848,7 +840,8 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role)
                        goto out;
                }
 
-               rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port);
+               rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port,
+                                               &bfad->pcidev->dev);
                if (rc != BFA_STATUS_OK)
                        goto out;
 
index 6a2efdd..e477bfb 100644 (file)
@@ -364,6 +364,152 @@ bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
 
 }
 
+static int
+bfad_im_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+       char *vname = fc_vport->symbolic_name;
+       struct Scsi_Host *shost = fc_vport->shost;
+       struct bfad_im_port_s *im_port =
+               (struct bfad_im_port_s *) shost->hostdata[0];
+       struct bfad_s *bfad = im_port->bfad;
+       struct bfa_port_cfg_s port_cfg;
+       int status = 0, rc;
+       unsigned long flags;
+
+       memset(&port_cfg, 0, sizeof(port_cfg));
+
+       port_cfg.pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
+       port_cfg.nwwn = wwn_to_u64((u8 *) &fc_vport->node_name);
+
+       if (strlen(vname) > 0)
+               strcpy((char *)&port_cfg.sym_name, vname);
+
+       port_cfg.roles = BFA_PORT_ROLE_FCP_IM;
+       rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev);
+
+       if (rc == BFA_STATUS_OK) {
+               struct bfad_vport_s   *vport;
+               struct bfa_fcs_vport_s *fcs_vport;
+               struct Scsi_Host *vshost;
+
+               spin_lock_irqsave(&bfad->bfad_lock, flags);
+               fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0,
+                                       port_cfg.pwwn);
+               if (fcs_vport == NULL) {
+                       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+                       return VPCERR_BAD_WWN;
+               }
+
+               fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+               if (disable) {
+                       bfa_fcs_vport_stop(fcs_vport);
+                       fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+               }
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+               vport = fcs_vport->vport_drv;
+               vshost = vport->drv_port.im_port->shost;
+               fc_host_node_name(vshost) = wwn_to_u64((u8 *) &port_cfg.nwwn);
+               fc_host_port_name(vshost) = wwn_to_u64((u8 *) &port_cfg.pwwn);
+               fc_vport->dd_data = vport;
+               vport->drv_port.im_port->fc_vport = fc_vport;
+
+       } else if (rc == BFA_STATUS_INVALID_WWN)
+               return VPCERR_BAD_WWN;
+       else if (rc == BFA_STATUS_VPORT_EXISTS)
+               return VPCERR_BAD_WWN;
+       else if (rc == BFA_STATUS_VPORT_MAX)
+               return VPCERR_NO_FABRIC_SUPP;
+       else if (rc == BFA_STATUS_VPORT_WWN_BP)
+               return VPCERR_BAD_WWN;
+        else
+               return FC_VPORT_FAILED;
+
+       return status;
+}
+
+static int
+bfad_im_vport_delete(struct fc_vport *fc_vport)
+{
+       struct bfad_vport_s *vport = (struct bfad_vport_s *)fc_vport->dd_data;
+       struct bfad_im_port_s *im_port =
+                       (struct bfad_im_port_s *) vport->drv_port.im_port;
+       struct bfad_s *bfad = im_port->bfad;
+       struct bfad_port_s *port;
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct Scsi_Host *vshost;
+       wwn_t   pwwn;
+       int rc;
+       unsigned long flags;
+       struct completion fcomp;
+
+       if (im_port->flags & BFAD_PORT_DELETE)
+               goto free_scsi_host;
+
+       port = im_port->port;
+
+       vshost = vport->drv_port.im_port->shost;
+       pwwn = wwn_to_u64((u8 *) &fc_host_port_name(vshost));
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       if (fcs_vport == NULL)
+               return VPCERR_BAD_WWN;
+
+       vport->drv_port.flags |= BFAD_PORT_DELETE;
+
+       vport->comp_del = &fcomp;
+       init_completion(vport->comp_del);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       rc = bfa_fcs_vport_delete(&vport->fcs_vport);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       wait_for_completion(vport->comp_del);
+
+free_scsi_host:
+       bfad_os_scsi_host_free(bfad, im_port);
+
+       kfree(vport);
+
+       return 0;
+}
+
+static int
+bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+       struct bfad_vport_s *vport;
+       struct bfad_s *bfad;
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct Scsi_Host *vshost;
+       wwn_t   pwwn;
+       unsigned long flags;
+
+       vport = (struct bfad_vport_s *)fc_vport->dd_data;
+       bfad = vport->drv_port.bfad;
+       vshost = vport->drv_port.im_port->shost;
+       pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       if (fcs_vport == NULL)
+               return VPCERR_BAD_WWN;
+
+       if (disable) {
+               bfa_fcs_vport_stop(fcs_vport);
+               fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+       } else {
+               bfa_fcs_vport_start(fcs_vport);
+               fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+       }
+
+       return 0;
+}
+
 struct fc_function_template bfad_im_fc_function_template = {
 
        /* Target dynamic attributes */
@@ -413,6 +559,61 @@ struct fc_function_template bfad_im_fc_function_template = {
        .show_rport_dev_loss_tmo = 1,
        .get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
        .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
+
+       .vport_create = bfad_im_vport_create,
+       .vport_delete = bfad_im_vport_delete,
+       .vport_disable = bfad_im_vport_disable,
+};
+
+struct fc_function_template bfad_im_vport_fc_function_template = {
+
+       /* Target dynamic attributes */
+       .get_starget_port_id = bfad_im_get_starget_port_id,
+       .show_starget_port_id = 1,
+       .get_starget_node_name = bfad_im_get_starget_node_name,
+       .show_starget_node_name = 1,
+       .get_starget_port_name = bfad_im_get_starget_port_name,
+       .show_starget_port_name = 1,
+
+       /* Host dynamic attribute */
+       .get_host_port_id = bfad_im_get_host_port_id,
+       .show_host_port_id = 1,
+
+       /* Host fixed attributes */
+       .show_host_node_name = 1,
+       .show_host_port_name = 1,
+       .show_host_supported_classes = 1,
+       .show_host_supported_fc4s = 1,
+       .show_host_supported_speeds = 1,
+       .show_host_maxframe_size = 1,
+
+       /* More host dynamic attributes */
+       .show_host_port_type = 1,
+       .get_host_port_type = bfad_im_get_host_port_type,
+       .show_host_port_state = 1,
+       .get_host_port_state = bfad_im_get_host_port_state,
+       .show_host_active_fc4s = 1,
+       .get_host_active_fc4s = bfad_im_get_host_active_fc4s,
+       .show_host_speed = 1,
+       .get_host_speed = bfad_im_get_host_speed,
+       .show_host_fabric_name = 1,
+       .get_host_fabric_name = bfad_im_get_host_fabric_name,
+
+       .show_host_symbolic_name = 1,
+
+       /* Statistics */
+       .get_fc_host_stats = bfad_im_get_stats,
+       .reset_fc_host_stats = bfad_im_reset_stats,
+
+       /* Allocation length for host specific data */
+       .dd_fcrport_size = sizeof(struct bfad_itnim_data_s *),
+
+       /* Remote port fixed attributes */
+       .show_rport_maxframe_size = 1,
+       .show_rport_supported_classes = 1,
+       .show_rport_dev_loss_tmo = 1,
+       .get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
+       .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
 };
 
 /**
index 107848c..6c920c1 100644 (file)
@@ -162,7 +162,6 @@ struct bfad_s {
        const char *pci_name;
        struct bfa_pcidev_s hal_pcidev;
        struct bfa_ioc_pci_attr_s pci_attr;
-       unsigned long   pci_bar0_map;
        void __iomem   *pci_bar0_kva;
        struct completion comp;
        struct completion suspend;
@@ -254,7 +253,7 @@ do {                                                \
 
 
 bfa_status_t    bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
-                                 struct bfa_port_cfg_s *port_cfg);
+                         struct bfa_port_cfg_s *port_cfg, struct device *dev);
 bfa_status_t    bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
                               struct bfa_port_cfg_s *port_cfg);
 bfa_status_t    bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role);
@@ -294,5 +293,6 @@ extern struct list_head bfad_list;
 extern int bfa_lun_queue_depth;
 extern int bfad_supported_fc4s;
 extern int bfa_linkup_delay;
+extern struct mutex bfad_mutex;
 
 #endif /* __BFAD_DRV_H__ */
index 78f42aa..5b7cf53 100644 (file)
@@ -30,6 +30,7 @@ BFA_TRC_FILE(LDRV, IM);
 
 DEFINE_IDR(bfad_im_port_index);
 struct scsi_transport_template *bfad_im_scsi_transport_template;
+struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
 static void bfad_im_itnim_work_handler(struct work_struct *work);
 static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
                void (*done)(struct scsi_cmnd *));
@@ -252,7 +253,6 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
        struct bfa_itnim_s *bfa_itnim;
        bfa_status_t    rc = BFA_STATUS_OK;
 
-       bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
        tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
        if (!tskim) {
                BFA_DEV_PRINTF(bfad, BFA_ERR,
@@ -513,11 +513,14 @@ void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim)
  * Allocate a Scsi_Host for a port.
  */
 int
-bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
+                               struct device *dev)
 {
        int error = 1;
 
+       mutex_lock(&bfad_mutex);
        if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) {
+               mutex_unlock(&bfad_mutex);
                printk(KERN_WARNING "idr_pre_get failure\n");
                goto out;
        }
@@ -525,10 +528,13 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
        error = idr_get_new(&bfad_im_port_index, im_port,
                                         &im_port->idr_id);
        if (error) {
+               mutex_unlock(&bfad_mutex);
                printk(KERN_WARNING "idr_get_new failure\n");
                goto out;
        }
 
+       mutex_unlock(&bfad_mutex);
+
        im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
        if (!im_port->shost) {
                error = 1;
@@ -542,12 +548,15 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
        im_port->shost->max_lun = MAX_FCP_LUN;
        im_port->shost->max_cmd_len = 16;
        im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth;
-       im_port->shost->transportt = bfad_im_scsi_transport_template;
+       if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
+               im_port->shost->transportt = bfad_im_scsi_transport_template;
+       else
+               im_port->shost->transportt =
+                               bfad_im_scsi_vport_transport_template;
 
-       error = bfad_os_scsi_add_host(im_port->shost, im_port, bfad);
+       error = scsi_add_host(im_port->shost, dev);
        if (error) {
-               printk(KERN_WARNING "bfad_os_scsi_add_host failure %d\n",
-                                                       error);
+               printk(KERN_WARNING "scsi_add_host failure %d\n", error);
                goto out_fc_rel;
        }
 
@@ -559,7 +568,9 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 out_fc_rel:
        scsi_host_put(im_port->shost);
 out_free_idr:
+       mutex_lock(&bfad_mutex);
        idr_remove(&bfad_im_port_index, im_port->idr_id);
+       mutex_unlock(&bfad_mutex);
 out:
        return error;
 }
@@ -567,8 +578,6 @@ out:
 void
 bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 {
-       unsigned long flags;
-
        bfa_trc(bfad, bfad->inst_no);
        bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE,
                        im_port->shost->host_no);
@@ -578,9 +587,9 @@ bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
        scsi_remove_host(im_port->shost);
        scsi_host_put(im_port->shost);
 
-       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       mutex_lock(&bfad_mutex);
        idr_remove(&bfad_im_port_index, im_port->idr_id);
-       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       mutex_unlock(&bfad_mutex);
 }
 
 static void
@@ -589,9 +598,11 @@ bfad_im_port_delete_handler(struct work_struct *work)
        struct bfad_im_port_s *im_port =
                container_of(work, struct bfad_im_port_s, port_delete_work);
 
-       bfad_im_scsi_host_free(im_port->bfad, im_port);
-       bfad_im_port_clean(im_port);
-       kfree(im_port);
+       if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
+               im_port->flags |= BFAD_PORT_DELETE;
+               fc_vport_terminate(im_port->fc_vport);
+       }
+
 }
 
 bfa_status_t
@@ -690,23 +701,6 @@ bfad_im_probe_undo(struct bfad_s *bfad)
        }
 }
 
-
-
-
-int
-bfad_os_scsi_add_host(struct Scsi_Host *shost, struct bfad_im_port_s *im_port,
-                       struct bfad_s *bfad)
-{
-    struct device *dev;
-
-    if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
-               dev = &bfad->pcidev->dev;
-    else
-               dev = &bfad->pport.im_port->shost->shost_gendev;
-
-    return scsi_add_host(shost, dev);
-}
-
 struct Scsi_Host *
 bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
 {
@@ -725,7 +719,8 @@ bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
 void
 bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 {
-       flush_workqueue(bfad->im->drv_workq);
+       if (!(im_port->flags & BFAD_PORT_DELETE))
+               flush_workqueue(bfad->im->drv_workq);
        bfad_im_scsi_host_free(im_port->bfad, im_port);
        bfad_im_port_clean(im_port);
        kfree(im_port);
@@ -830,6 +825,13 @@ bfad_im_module_init(void)
        if (!bfad_im_scsi_transport_template)
                return BFA_STATUS_ENOMEM;
 
+       bfad_im_scsi_vport_transport_template =
+               fc_attach_transport(&bfad_im_vport_fc_function_template);
+       if (!bfad_im_scsi_vport_transport_template) {
+               fc_release_transport(bfad_im_scsi_transport_template);
+               return BFA_STATUS_ENOMEM;
+       }
+
        return BFA_STATUS_OK;
 }
 
@@ -838,6 +840,8 @@ bfad_im_module_exit(void)
 {
        if (bfad_im_scsi_transport_template)
                fc_release_transport(bfad_im_scsi_transport_template);
+       if (bfad_im_scsi_vport_transport_template)
+               fc_release_transport(bfad_im_scsi_vport_transport_template);
 }
 
 void
@@ -938,6 +942,7 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
                bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port)));
        fc_host_port_name(host) =
                bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port)));
+       fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa);
 
        fc_host_supported_classes(host) = FC_COS_CLASS3;
 
index 85ab2da..973cab4 100644 (file)
@@ -34,7 +34,7 @@ void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port);
 void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port);
 void bfad_im_port_clean(struct bfad_im_port_s *im_port);
 int  bfad_im_scsi_host_alloc(struct bfad_s *bfad,
-                               struct bfad_im_port_s *im_port);
+               struct bfad_im_port_s *im_port, struct device *dev);
 void bfad_im_scsi_host_free(struct bfad_s *bfad,
                                struct bfad_im_port_s *im_port);
 
@@ -64,9 +64,11 @@ struct bfad_im_port_s {
        struct work_struct port_delete_work;
        int             idr_id;
        u16        cur_scsi_id;
+       u16        flags;
        struct list_head binding_list;
        struct Scsi_Host *shost;
        struct list_head itnim_mapped_list;
+       struct fc_vport *fc_vport;
 };
 
 enum bfad_itnim_state {
@@ -140,6 +142,8 @@ void bfad_im_itnim_unmap(struct bfad_im_port_s  *im_port,
 extern struct scsi_host_template bfad_im_scsi_host_template;
 extern struct scsi_host_template bfad_im_vport_template;
 extern struct fc_function_template bfad_im_fc_function_template;
+extern struct fc_function_template bfad_im_vport_fc_function_template;
 extern struct scsi_transport_template *bfad_im_scsi_transport_template;
+extern struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
 
 #endif
index 18352ff..3a66ca2 100644 (file)
@@ -347,6 +347,7 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
 
        login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
        login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
+       login_wqe->flags = ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN;
 
        login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
        login_wqe->resp_bd_list_addr_hi =
@@ -356,7 +357,6 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
                 (bnx2i_conn->gen_pdu.resp_buf_size <<
                  ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
        login_wqe->resp_buffer = dword;
-       login_wqe->flags = 0;
        login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
        login_wqe->bd_list_addr_hi =
                (u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);
index 5d9296c..af6a00a 100644 (file)
@@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
 static u32 adapter_count;
 
 #define DRV_MODULE_NAME                "bnx2i"
-#define DRV_MODULE_VERSION     "2.1.0"
-#define DRV_MODULE_RELDATE     "Dec 06, 2009"
+#define DRV_MODULE_VERSION     "2.1.1"
+#define DRV_MODULE_RELDATE     "Mar 24, 2010"
 
 static char version[] __devinitdata =
                "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -26,7 +26,8 @@ static char version[] __devinitdata =
 
 
 MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711"
+                  " iSCSI Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -289,6 +290,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
        int rc;
 
        mutex_lock(&bnx2i_dev_lock);
+       hba->cnic = cnic;
        rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
        if (!rc) {
                hba->age++;
@@ -335,8 +337,7 @@ void bnx2i_ulp_init(struct cnic_dev *dev)
        if (bnx2i_init_one(hba, dev)) {
                printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);
                bnx2i_free_hba(hba);
-       } else
-               hba->cnic = dev;
+       }
 }
 
 
index d0ab23a..685af36 100644 (file)
@@ -104,8 +104,10 @@ static int __init cxgb3i_init_module(void)
                return err;
 
        err = cxgb3i_pdu_init();
-       if (err < 0)
+       if (err < 0) {
+               cxgb3i_iscsi_cleanup();
                return err;
+       }
 
        cxgb3_register_client(&t3c_client);
 
index e8a0bc3..6faf472 100644 (file)
@@ -285,13 +285,11 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
        switch (cmd) {
        case MODE_SELECT:
                len = sizeof(short_trespass);
-               rq->cmd_flags |= REQ_RW;
                rq->cmd[1] = 0x10;
                rq->cmd[4] = len;
                break;
        case MODE_SELECT_10:
                len = sizeof(long_trespass);
-               rq->cmd_flags |= REQ_RW;
                rq->cmd[1] = 0x10;
                rq->cmd[8] = len;
                break;
index 54c870b..9276121 100644 (file)
@@ -74,6 +74,7 @@ static int fcoe_rcv(struct sk_buff *, struct net_device *,
 static int fcoe_percpu_receive_thread(void *);
 static void fcoe_clean_pending_queue(struct fc_lport *);
 static void fcoe_percpu_clean(struct fc_lport *);
+static int fcoe_link_speed_update(struct fc_lport *);
 static int fcoe_link_ok(struct fc_lport *);
 
 static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
@@ -146,6 +147,7 @@ static int fcoe_vport_destroy(struct fc_vport *);
 static int fcoe_vport_create(struct fc_vport *, bool disabled);
 static int fcoe_vport_disable(struct fc_vport *, bool disable);
 static void fcoe_set_vport_symbolic_name(struct fc_vport *);
+static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);
 
 static struct libfc_function_template fcoe_libfc_fcn_templ = {
        .frame_send = fcoe_xmit,
@@ -153,6 +155,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {
        .ddp_done = fcoe_ddp_done,
        .elsct_send = fcoe_elsct_send,
        .get_lesb = fcoe_get_lesb,
+       .lport_set_port_id = fcoe_set_port_id,
 };
 
 struct fc_function_template fcoe_transport_function = {
@@ -629,6 +632,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
        port->fcoe_pending_queue_active = 0;
        setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
 
+       fcoe_link_speed_update(lport);
+
        if (!lport->vport) {
                /*
                 * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN:
@@ -653,15 +658,13 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
 /**
  * fcoe_shost_config() - Set up the SCSI host associated with a local port
  * @lport: The local port
- * @shost: The SCSI host to associate with the local port
  * @dev:   The device associated with the SCSI host
  *
  * Must be called after fcoe_lport_config() and fcoe_netdev_config()
  *
  * Returns: 0 for success
  */
-static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,
-                            struct device *dev)
+static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
 {
        int rc = 0;
 
@@ -669,6 +672,8 @@ static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,
        lport->host->max_lun = FCOE_MAX_LUN;
        lport->host->max_id = FCOE_MAX_FCP_TARGET;
        lport->host->max_channel = 0;
+       lport->host->max_cmd_len = FCOE_MAX_CMD_LEN;
+
        if (lport->vport)
                lport->host->transportt = fcoe_vport_transport_template;
        else
@@ -796,6 +801,12 @@ skip_oem:
 /**
  * fcoe_if_destroy() - Tear down a SW FCoE instance
  * @lport: The local port to be destroyed
+ *
+ * Locking: must be called with the RTNL mutex held and RTNL mutex
+ * needed to be dropped by this function since not dropping RTNL
+ * would cause circular locking warning on synchronous fip worker
+ * cancelling thru fcoe_interface_put invoked by this function.
+ *
  */
 static void fcoe_if_destroy(struct fc_lport *lport)
 {
@@ -818,7 +829,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)
        /* Free existing transmit skbs */
        fcoe_clean_pending_queue(lport);
 
-       rtnl_lock();
        if (!is_zero_ether_addr(port->data_src_addr))
                dev_uc_del(netdev, port->data_src_addr);
        rtnl_unlock();
@@ -841,6 +851,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)
 
        /* Release the Scsi_Host */
        scsi_host_put(lport->host);
+       module_put(THIS_MODULE);
 }
 
 /**
@@ -897,7 +908,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
        struct net_device *netdev = fcoe->netdev;
        struct fc_lport *lport = NULL;
        struct fcoe_port *port;
-       struct Scsi_Host *shost;
        int rc;
        /*
         * parent is only a vport if npiv is 1,
@@ -919,7 +929,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
                rc = -ENOMEM;
                goto out;
        }
-       shost = lport->host;
        port = lport_priv(lport);
        port->lport = lport;
        port->fcoe = fcoe;
@@ -934,7 +943,8 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
        }
 
        if (npiv) {
-               FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n",
+               FCOE_NETDEV_DBG(netdev, "Setting vport names, "
+                               "%16.16llx %16.16llx\n",
                                vport->node_name, vport->port_name);
                fc_set_wwnn(lport, vport->node_name);
                fc_set_wwpn(lport, vport->port_name);
@@ -949,7 +959,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
        }
 
        /* configure lport scsi host properties */
-       rc = fcoe_shost_config(lport, shost, parent);
+       rc = fcoe_shost_config(lport, parent);
        if (rc) {
                FCOE_NETDEV_DBG(netdev, "Could not configure shost for the "
                                "interface\n");
@@ -1073,7 +1083,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
        struct sk_buff *skb;
 #ifdef CONFIG_SMP
        struct fcoe_percpu_s *p0;
-       unsigned targ_cpu = smp_processor_id();
+       unsigned targ_cpu = get_cpu();
 #endif /* CONFIG_SMP */
 
        FCOE_DBG("Destroying receive thread for CPU %d\n", cpu);
@@ -1129,6 +1139,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
                        kfree_skb(skb);
                spin_unlock_bh(&p->fcoe_rx_list.lock);
        }
+       put_cpu();
 #else
        /*
         * This a non-SMP scenario where the singular Rx thread is
@@ -1297,8 +1308,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 
        return 0;
 err:
-       fc_lport_get_stats(lport)->ErrorFrames++;
-
+       per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++;
+       put_cpu();
 err2:
        kfree_skb(skb);
        return -1;
@@ -1444,7 +1455,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
                return 0;
        }
 
-       if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
+       if (unlikely(fh->fh_type == FC_TYPE_ELS) &&
            fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb))
                return 0;
 
@@ -1527,9 +1538,10 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
                skb_shinfo(skb)->gso_size = 0;
        }
        /* update tx stats: regardless if LLD fails */
-       stats = fc_lport_get_stats(lport);
+       stats = per_cpu_ptr(lport->dev_stats, get_cpu());
        stats->TxFrames++;
        stats->TxWords += wlen;
+       put_cpu();
 
        /* send down to lld */
        fr_dev(fp) = lport;
@@ -1563,7 +1575,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
        struct fc_frame_header *fh;
        struct fcoe_crc_eof crc_eof;
        struct fc_frame *fp;
-       u8 *mac = NULL;
        struct fcoe_port *port;
        struct fcoe_hdr *hp;
 
@@ -1583,13 +1594,9 @@ static void fcoe_recv_frame(struct sk_buff *skb)
                        skb_end_pointer(skb), skb->csum,
                        skb->dev ? skb->dev->name : "<NULL>");
 
-       /*
-        * Save source MAC address before discarding header.
-        */
        port = lport_priv(lport);
        if (skb_is_nonlinear(skb))
                skb_linearize(skb);     /* not ideal */
-       mac = eth_hdr(skb)->h_source;
 
        /*
         * Frame length checks and setting up the header pointers
@@ -1598,7 +1605,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
        hp = (struct fcoe_hdr *) skb_network_header(skb);
        fh = (struct fc_frame_header *) skb_transport_header(skb);
 
-       stats = fc_lport_get_stats(lport);
+       stats = per_cpu_ptr(lport->dev_stats, get_cpu());
        if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
                if (stats->ErrorFrames < 5)
                        printk(KERN_WARNING "fcoe: FCoE version "
@@ -1607,9 +1614,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
                               "initiator supports version "
                               "%x\n", FC_FCOE_DECAPS_VER(hp),
                               FC_FCOE_VER);
-               stats->ErrorFrames++;
-               kfree_skb(skb);
-               return;
+               goto drop;
        }
 
        skb_pull(skb, sizeof(struct fcoe_hdr));
@@ -1624,16 +1629,12 @@ static void fcoe_recv_frame(struct sk_buff *skb)
        fr_sof(fp) = hp->fcoe_sof;
 
        /* Copy out the CRC and EOF trailer for access */
-       if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
-               kfree_skb(skb);
-               return;
-       }
+       if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof)))
+               goto drop;
        fr_eof(fp) = crc_eof.fcoe_eof;
        fr_crc(fp) = crc_eof.fcoe_crc32;
-       if (pskb_trim(skb, fr_len)) {
-               kfree_skb(skb);
-               return;
-       }
+       if (pskb_trim(skb, fr_len))
+               goto drop;
 
        /*
         * We only check CRC if no offload is available and if it is
@@ -1647,25 +1648,27 @@ static void fcoe_recv_frame(struct sk_buff *skb)
                fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
 
        fh = fc_frame_header_get(fp);
-       if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
-           fh->fh_type == FC_TYPE_FCP) {
-               fc_exch_recv(lport, fp);
-               return;
-       }
-       if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
+       if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA ||
+           fh->fh_type != FC_TYPE_FCP) &&
+           (fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {
                if (le32_to_cpu(fr_crc(fp)) !=
                    ~crc32(~0, skb->data, fr_len)) {
                        if (stats->InvalidCRCCount < 5)
                                printk(KERN_WARNING "fcoe: dropping "
                                       "frame with CRC error\n");
                        stats->InvalidCRCCount++;
-                       stats->ErrorFrames++;
-                       fc_frame_free(fp);
-                       return;
+                       goto drop;
                }
                fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
        }
+       put_cpu();
        fc_exch_recv(lport, fp);
+       return;
+
+drop:
+       stats->ErrorFrames++;
+       put_cpu();
+       kfree_skb(skb);
 }
 
 /**
@@ -1835,11 +1838,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,
                FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
                                "from netdev netlink\n", event);
        }
+
+       fcoe_link_speed_update(lport);
+
        if (link_possible && !fcoe_link_ok(lport))
                fcoe_ctlr_link_up(&fcoe->ctlr);
        else if (fcoe_ctlr_link_down(&fcoe->ctlr)) {
-               stats = fc_lport_get_stats(lport);
+               stats = per_cpu_ptr(lport->dev_stats, get_cpu());
                stats->LinkFailureCount++;
+               put_cpu();
                fcoe_clean_pending_queue(lport);
        }
 out:
@@ -1901,13 +1908,19 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)
                goto out_nodev;
        }
 
-       rtnl_lock();
+       if (!rtnl_trylock()) {
+               dev_put(netdev);
+               mutex_unlock(&fcoe_config_mutex);
+               return restart_syscall();
+       }
+
        fcoe = fcoe_hostlist_lookup_port(netdev);
        rtnl_unlock();
 
-       if (fcoe)
+       if (fcoe) {
                fc_fabric_logoff(fcoe->ctlr.lp);
-       else
+               fcoe_ctlr_link_down(&fcoe->ctlr);
+       } else
                rc = -ENODEV;
 
        dev_put(netdev);
@@ -1950,13 +1963,20 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)
                goto out_nodev;
        }
 
-       rtnl_lock();
+       if (!rtnl_trylock()) {
+               dev_put(netdev);
+               mutex_unlock(&fcoe_config_mutex);
+               return restart_syscall();
+       }
+
        fcoe = fcoe_hostlist_lookup_port(netdev);
        rtnl_unlock();
 
-       if (fcoe)
+       if (fcoe) {
+               if (!fcoe_link_ok(fcoe->ctlr.lp))
+                       fcoe_ctlr_link_up(&fcoe->ctlr);
                rc = fc_fabric_login(fcoe->ctlr.lp);
-       else
+       else
                rc = -ENODEV;
 
        dev_put(netdev);
@@ -1999,7 +2019,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
                goto out_nodev;
        }
 
-       rtnl_lock();
+       if (!rtnl_trylock()) {
+               dev_put(netdev);
+               mutex_unlock(&fcoe_config_mutex);
+               return restart_syscall();
+       }
+
        fcoe = fcoe_hostlist_lookup_port(netdev);
        if (!fcoe) {
                rtnl_unlock();
@@ -2008,9 +2033,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
        }
        list_del(&fcoe->list);
        fcoe_interface_cleanup(fcoe);
-       rtnl_unlock();
+       /* RTNL mutex is dropped by fcoe_if_destroy */
        fcoe_if_destroy(fcoe->ctlr.lp);
-       module_put(THIS_MODULE);
 
 out_putdev:
        dev_put(netdev);
@@ -2029,6 +2053,8 @@ static void fcoe_destroy_work(struct work_struct *work)
 
        port = container_of(work, struct fcoe_port, destroy_work);
        mutex_lock(&fcoe_config_mutex);
+       rtnl_lock();
+       /* RTNL mutex is dropped by fcoe_if_destroy */
        fcoe_if_destroy(port->lport);
        mutex_unlock(&fcoe_config_mutex);
 }
@@ -2050,6 +2076,12 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
        struct net_device *netdev;
 
        mutex_lock(&fcoe_config_mutex);
+
+       if (!rtnl_trylock()) {
+               mutex_unlock(&fcoe_config_mutex);
+               return restart_syscall();
+       }
+
 #ifdef CONFIG_FCOE_MODULE
        /*
         * Make sure the module has been initialized, and is not about to be
@@ -2058,7 +2090,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
         */
        if (THIS_MODULE->state != MODULE_STATE_LIVE) {
                rc = -ENODEV;
-               goto out_nodev;
+               goto out_nomod;
        }
 #endif
 
@@ -2067,7 +2099,6 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
                goto out_nomod;
        }
 
-       rtnl_lock();
        netdev = fcoe_if_to_netdev(buffer);
        if (!netdev) {
                rc = -ENODEV;
@@ -2122,35 +2153,27 @@ out_free:
 out_putdev:
        dev_put(netdev);
 out_nodev:
-       rtnl_unlock();
        module_put(THIS_MODULE);
 out_nomod:
+       rtnl_unlock();
        mutex_unlock(&fcoe_config_mutex);
        return rc;
 }
 
 /**
- * fcoe_link_ok() - Check if the link is OK for a local port
- * @lport: The local port to check link on
- *
- * Any permanently-disqualifying conditions have been previously checked.
- * This also updates the speed setting, which may change with link for 100/1000.
- *
- * This function should probably be checking for PAUSE support at some point
- * in the future. Currently Per-priority-pause is not determinable using
- * ethtool, so we shouldn't be restrictive until that problem is resolved.
- *
- * Returns: 0 if link is OK for use by FCoE.
+ * fcoe_link_speed_update() - Update the supported and actual link speeds
+ * @lport: The local port to update speeds for
  *
+ * Returns: 0 if the ethtool query was successful
+ *          -1 if the ethtool query failed
  */
-int fcoe_link_ok(struct fc_lport *lport)
+int fcoe_link_speed_update(struct fc_lport *lport)
 {
        struct fcoe_port *port = lport_priv(lport);
        struct net_device *netdev = port->fcoe->netdev;
        struct ethtool_cmd ecmd = { ETHTOOL_GSET };
 
-       if ((netdev->flags & IFF_UP) && netif_carrier_ok(netdev) &&
-           (!dev_ethtool_get_settings(netdev, &ecmd))) {
+       if (!dev_ethtool_get_settings(netdev, &ecmd)) {
                lport->link_supported_speeds &=
                        ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
                if (ecmd.supported & (SUPPORTED_1000baseT_Half |
@@ -2170,6 +2193,23 @@ int fcoe_link_ok(struct fc_lport *lport)
 }
 
 /**
+ * fcoe_link_ok() - Check if the link is OK for a local port
+ * @lport: The local port to check link on
+ *
+ * Returns: 0 if link is UP and OK, -1 if not
+ *
+ */
+int fcoe_link_ok(struct fc_lport *lport)
+{
+       struct fcoe_port *port = lport_priv(lport);
+       struct net_device *netdev = port->fcoe->netdev;
+
+       if (netif_oper_up(netdev))
+               return 0;
+       return -1;
+}
+
+/**
  * fcoe_percpu_clean() - Clear all pending skbs for an local port
  * @lport: The local port whose skbs are to be cleared
  *
@@ -2631,3 +2671,25 @@ static void fcoe_get_lesb(struct fc_lport *lport,
        lesb->lesb_miss_fka = htonl(mdac);
        lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);
 }
+
+/**
+ * fcoe_set_port_id() - Callback from libfc when Port_ID is set.
+ * @lport: the local port
+ * @port_id: the port ID
+ * @fp: the received frame, if any, that caused the port_id to be set.
+ *
+ * This routine handles the case where we received a FLOGI and are
+ * entering point-to-point mode.  We need to call fcoe_ctlr_recv_flogi()
+ * so it can set the non-mapped mode and gateway address.
+ *
+ * The FLOGI LS_ACC is handled by fcoe_flogi_resp().
+ */
+static void fcoe_set_port_id(struct fc_lport *lport,
+                            u32 port_id, struct fc_frame *fp)
+{
+       struct fcoe_port *port = lport_priv(lport);
+       struct fcoe_interface *fcoe = port->fcoe;
+
+       if (fp && fc_frame_payload_op(fp) == ELS_FLOGI)
+               fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp);
+}
index 3440da4..50aaa4b 100644 (file)
@@ -51,7 +51,7 @@ MODULE_LICENSE("GPL v2");
 #define        FCOE_CTLR_DEF_FKA       FIP_DEF_FKA     /* default keep alive (mS) */
 
 static void fcoe_ctlr_timeout(unsigned long);
-static void fcoe_ctlr_link_work(struct work_struct *);
+static void fcoe_ctlr_timer_work(struct work_struct *);
 static void fcoe_ctlr_recv_work(struct work_struct *);
 
 static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
@@ -116,7 +116,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)
        spin_lock_init(&fip->lock);
        fip->flogi_oxid = FC_XID_UNKNOWN;
        setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
-       INIT_WORK(&fip->link_work, fcoe_ctlr_link_work);
+       INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
        INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
        skb_queue_head_init(&fip->fip_recv_list);
 }
@@ -164,7 +164,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
        fcoe_ctlr_reset_fcfs(fip);
        spin_unlock_bh(&fip->lock);
        del_timer_sync(&fip->timer);
-       cancel_work_sync(&fip->link_work);
+       cancel_work_sync(&fip->timer_work);
 }
 EXPORT_SYMBOL(fcoe_ctlr_destroy);
 
@@ -257,14 +257,10 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
 {
        spin_lock_bh(&fip->lock);
        if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
-               fip->last_link = 1;
-               fip->link = 1;
                spin_unlock_bh(&fip->lock);
                fc_linkup(fip->lp);
        } else if (fip->state == FIP_ST_LINK_WAIT) {
                fip->state = fip->mode;
-               fip->last_link = 1;
-               fip->link = 1;
                spin_unlock_bh(&fip->lock);
                if (fip->state == FIP_ST_AUTO)
                        LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
@@ -306,9 +302,7 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
        LIBFCOE_FIP_DBG(fip, "link down.\n");
        spin_lock_bh(&fip->lock);
        fcoe_ctlr_reset(fip);
-       link_dropped = fip->link;
-       fip->link = 0;
-       fip->last_link = 0;
+       link_dropped = fip->state != FIP_ST_LINK_WAIT;
        fip->state = FIP_ST_LINK_WAIT;
        spin_unlock_bh(&fip->lock);
 
@@ -349,7 +343,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
 
        fcf = fip->sel_fcf;
        lp = fip->lp;
-       if (!fcf || !fc_host_port_id(lp->host))
+       if (!fcf || !lp->port_id)
                return;
 
        len = sizeof(*kal) + ports * sizeof(*vn);
@@ -380,8 +374,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
                vn->fd_desc.fip_dtype = FIP_DT_VN_ID;
                vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;
                memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-               hton24(vn->fd_fc_id, fc_host_port_id(lp->host));
-               put_unaligned_be64(lp->wwpn, &vn->fd_wwpn);
+               hton24(vn->fd_fc_id, lport->port_id);
+               put_unaligned_be64(lport->wwpn, &vn->fd_wwpn);
        }
        skb_put(skb, len);
        skb->protocol = htons(ETH_P_FIP);
@@ -445,13 +439,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
        cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
 
        mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
-       memset(mac, 0, sizeof(mac));
+       memset(mac, 0, sizeof(*mac));
        mac->fd_desc.fip_dtype = FIP_DT_MAC;
        mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
-       if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC)
+       if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
                memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-       else if (fip->spma)
+       } else if (fip_flags & FIP_FL_SPMA) {
+               LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
                memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
+       } else {
+               LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
+               /* FPMA only FLOGI must leave the MAC desc set to all 0s */
+       }
 
        skb->protocol = htons(ETH_P_FIP);
        skb_reset_mac_header(skb);
@@ -556,7 +555,7 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
  * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller
  * @fip: The FCoE controller to free FCFs on
  *
- * Called with lock held.
+ * Called with lock held and preemption disabled.
  *
  * An FCF is considered old if we have missed three advertisements.
  * That is, there have been no valid advertisement from it for three
@@ -573,17 +572,20 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
        struct fcoe_fcf *next;
        unsigned long sel_time = 0;
        unsigned long mda_time = 0;
+       struct fcoe_dev_stats *stats;
 
        list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
                mda_time = fcf->fka_period + (fcf->fka_period >> 1);
                if ((fip->sel_fcf == fcf) &&
                    (time_after(jiffies, fcf->time + mda_time))) {
                        mod_timer(&fip->timer, jiffies + mda_time);
-                       fc_lport_get_stats(fip->lp)->MissDiscAdvCount++;
+                       stats = per_cpu_ptr(fip->lp->dev_stats,
+                                           smp_processor_id());
+                       stats->MissDiscAdvCount++;
                        printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
-                              "Advertisement for fab %llx count %lld\n",
+                              "Advertisement for fab %16.16llx count %lld\n",
                               fip->lp->host->host_no, fcf->fabric_name,
-                              fc_lport_get_stats(fip->lp)->MissDiscAdvCount);
+                              stats->MissDiscAdvCount);
                }
                if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
                               msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
@@ -593,7 +595,9 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
                        WARN_ON(!fip->fcf_count);
                        fip->fcf_count--;
                        kfree(fcf);
-                       fc_lport_get_stats(fip->lp)->VLinkFailureCount++;
+                       stats = per_cpu_ptr(fip->lp->dev_stats,
+                                           smp_processor_id());
+                       stats->VLinkFailureCount++;
                } else if (fcoe_ctlr_mtu_valid(fcf) &&
                           (!sel_time || time_before(sel_time, fcf->time))) {
                        sel_time = fcf->time;
@@ -776,7 +780,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
        mtu_valid = fcoe_ctlr_mtu_valid(fcf);
        fcf->time = jiffies;
        if (!found) {
-               LIBFCOE_FIP_DBG(fip, "New FCF for fab %llx map %x val %d\n",
+               LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx "
+                               "map %x val %d\n",
                                fcf->fabric_name, fcf->fc_map, mtu_valid);
        }
 
@@ -906,9 +911,10 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
        fr_eof(fp) = FC_EOF_T;
        fr_dev(fp) = lport;
 
-       stats = fc_lport_get_stats(lport);
+       stats = per_cpu_ptr(lport->dev_stats, get_cpu());
        stats->RxFrames++;
        stats->RxWords += skb->len / FIP_BPW;
+       put_cpu();
 
        fc_exch_recv(lport, fp);
        return;
@@ -942,9 +948,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
        u32     desc_mask;
 
        LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
-       if (!fcf)
-               return;
-       if (!fcf || !fc_host_port_id(lport->host))
+
+       if (!fcf || !lport->port_id)
                return;
 
        /*
@@ -982,8 +987,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
                        if (compare_ether_addr(vp->fd_mac,
                                               fip->get_src_addr(lport)) == 0 &&
                            get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
-                           ntoh24(vp->fd_fc_id) ==
-                           fc_host_port_id(lport->host))
+                           ntoh24(vp->fd_fc_id) == lport->port_id)
                                desc_mask &= ~BIT(FIP_DT_VN_ID);
                        break;
                default:
@@ -1006,7 +1010,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
                LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
 
                spin_lock_bh(&fip->lock);
-               fc_lport_get_stats(lport)->VLinkFailureCount++;
+               per_cpu_ptr(lport->dev_stats,
+                           smp_processor_id())->VLinkFailureCount++;
                fcoe_ctlr_reset(fip);
                spin_unlock_bh(&fip->lock);
 
@@ -1102,15 +1107,17 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
        struct fcoe_fcf *best = NULL;
 
        list_for_each_entry(fcf, &fip->fcfs, list) {
-               LIBFCOE_FIP_DBG(fip, "consider FCF for fab %llx VFID %d map %x "
-                               "val %d\n", fcf->fabric_name, fcf->vfid,
+               LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx "
+                               "VFID %d map %x val %d\n",
+                               fcf->fabric_name, fcf->vfid,
                                fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
                if (!fcoe_ctlr_fcf_usable(fcf)) {
-                       LIBFCOE_FIP_DBG(fip, "FCF for fab %llx map %x %svalid "
-                                       "%savailable\n", fcf->fabric_name,
-                                       fcf->fc_map, (fcf->flags & FIP_FL_SOL)
-                                       ? "" : "in", (fcf->flags & FIP_FL_AVAIL)
-                                       ? "" : "un");
+                       LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
+                                       "map %x %svalid %savailable\n",
+                                       fcf->fabric_name, fcf->fc_map,
+                                       (fcf->flags & FIP_FL_SOL) ? "" : "in",
+                                       (fcf->flags & FIP_FL_AVAIL) ?
+                                       "" : "un");
                        continue;
                }
                if (!best) {
@@ -1175,7 +1182,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
                               "Starting FCF discovery.\n",
                               fip->lp->host->host_no);
                        fip->reset_req = 1;
-                       schedule_work(&fip->link_work);
+                       schedule_work(&fip->timer_work);
                }
        }
 
@@ -1201,43 +1208,31 @@ static void fcoe_ctlr_timeout(unsigned long arg)
                mod_timer(&fip->timer, next_timer);
        }
        if (fip->send_ctlr_ka || fip->send_port_ka)
-               schedule_work(&fip->link_work);
+               schedule_work(&fip->timer_work);
        spin_unlock_bh(&fip->lock);
 }
 
 /**
- * fcoe_ctlr_link_work() - Worker thread function for link changes
+ * fcoe_ctlr_timer_work() - Worker thread function for timer work
  * @work: Handle to a FCoE controller
  *
- * See if the link status has changed and if so, report it.
- *
- * This is here because fc_linkup() and fc_linkdown() must not
+ * Sends keep-alives and resets which must not
  * be called from the timer directly, since they use a mutex.
  */
-static void fcoe_ctlr_link_work(struct work_struct *work)
+static void fcoe_ctlr_timer_work(struct work_struct *work)
 {
        struct fcoe_ctlr *fip;
        struct fc_lport *vport;
        u8 *mac;
-       int link;
-       int last_link;
        int reset;
 
-       fip = container_of(work, struct fcoe_ctlr, link_work);
+       fip = container_of(work, struct fcoe_ctlr, timer_work);
        spin_lock_bh(&fip->lock);
-       last_link = fip->last_link;
-       link = fip->link;
-       fip->last_link = link;
        reset = fip->reset_req;
        fip->reset_req = 0;
        spin_unlock_bh(&fip->lock);
 
-       if (last_link != link) {
-               if (link)
-                       fc_linkup(fip->lp);
-               else
-                       fc_linkdown(fip->lp);
-       } else if (reset && link)
+       if (reset)
                fc_lport_reset(fip->lp);
 
        if (fip->send_ctlr_ka) {
@@ -1334,9 +1329,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
                if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
                        memcpy(fip->dest_addr, sa, ETH_ALEN);
                        fip->map_dest = 0;
-                       if (fip->state == FIP_ST_NON_FIP)
-                               LIBFCOE_FIP_DBG(fip, "received FLOGI REQ, "
-                                               "using non-FIP mode\n");
+                       if (fip->state == FIP_ST_AUTO)
+                               LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
+                                               "Setting non-FIP mode\n");
                        fip->state = FIP_ST_NON_FIP;
                }
                spin_unlock_bh(&fip->lock);
index 3966c71..19338e0 100644 (file)
@@ -36,7 +36,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.4.0.98"
+#define DRV_VERSION            "1.4.0.145"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
@@ -45,7 +45,7 @@
 #define        FNIC_IO_LOCKS           64 /* IO locks: power of 2 */
 #define FNIC_DFLT_QUEUE_DEPTH  32
 #define        FNIC_STATS_RATE_LIMIT   4 /* limit rate at which stats are pulled up */
-#define FNIC_MAX_CMD_LEN        16 /* Supported CDB length */
+
 /*
  * Tag bits used for special requests.
  */
index 5259888..2b48d79 100644 (file)
@@ -617,7 +617,7 @@ void fnic_flush_tx(struct fnic *fnic)
        struct sk_buff *skb;
        struct fc_frame *fp;
 
-       while ((skb = skb_dequeue(&fnic->frame_queue))) {
+       while ((skb = skb_dequeue(&fnic->tx_queue))) {
                fp = (struct fc_frame *)skb;
                fnic_send_frame(fnic, fp);
        }
index 97b2125..265e73d 100644 (file)
@@ -556,7 +556,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
        }
        host->max_lun = fnic->config.luns_per_tgt;
        host->max_id = FNIC_MAX_FCP_TARGET;
-       host->max_cmd_len = FNIC_MAX_CMD_LEN;
+       host->max_cmd_len = FCOE_MAX_CMD_LEN;
 
        fnic_get_res_counts(fnic);
 
index 35a4b30..a765fe7 100644 (file)
@@ -3842,7 +3842,7 @@ int __init option_setup(char *str)
 
     TRACE2(("option_setup() str %s\n", str ? str:"NULL")); 
 
-    while (cur && isdigit(*cur) && i <= MAXHA) {
+    while (cur && isdigit(*cur) && i < MAXHA) {
         ints[i++] = simple_strtoul(cur, NULL, 0);
         if ((cur = strchr(cur, ',')) != NULL) cur++;
     }
index 48f4068..18b7102 100644 (file)
 #include "wd33c93.h"
 #include "gvp11.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
-#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
-#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
 
-static irqreturn_t gvp11_intr (int irq, void *_instance)
+#define DMA(ptr)       ((gvp11_scsiregs *)((ptr)->base))
+
+static irqreturn_t gvp11_intr(int irq, void *_instance)
 {
-    unsigned long flags;
-    unsigned int status;
-    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
-
-    status = DMA(instance)->CNTR;
-    if (!(status & GVP11_DMAC_INT_PENDING))
-       return IRQ_NONE;
-
-    spin_lock_irqsave(instance->host_lock, flags);
-    wd33c93_intr(instance);
-    spin_unlock_irqrestore(instance->host_lock, flags);
-    return IRQ_HANDLED;
+       unsigned long flags;
+       unsigned int status;
+       struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
+
+       status = DMA(instance)->CNTR;
+       if (!(status & GVP11_DMAC_INT_PENDING))
+               return IRQ_NONE;
+
+       spin_lock_irqsave(instance->host_lock, flags);
+       wd33c93_intr(instance);
+       spin_unlock_irqrestore(instance->host_lock, flags);
+       return IRQ_HANDLED;
 }
 
 static int gvp11_xfer_mask = 0;
 
-void gvp11_setup (char *str, int *ints)
+void gvp11_setup(char *str, int *ints)
 {
-    gvp11_xfer_mask = ints[1];
+       gvp11_xfer_mask = ints[1];
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-    unsigned short cntr = GVP11_DMAC_INT_ENABLE;
-    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-    int bank_mask;
-    static int scsi_alloc_out_of_range = 0;
-
-    /* use bounce buffer if the physical address is bad */
-    if (addr & HDATA(cmd->device->host)->dma_xfer_mask)
-    {
-       HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
-           & ~0x1ff;
-
-       if( !scsi_alloc_out_of_range ) {
-           HDATA(cmd->device->host)->dma_bounce_buffer =
-               kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL);
-           HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
-       }
+       struct Scsi_Host *instance = cmd->device->host;
+       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       unsigned short cntr = GVP11_DMAC_INT_ENABLE;
+       unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+       int bank_mask;
+       static int scsi_alloc_out_of_range = 0;
+
+       /* use bounce buffer if the physical address is bad */
+       if (addr & hdata->dma_xfer_mask) {
+               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+
+               if (!scsi_alloc_out_of_range) {
+                       hdata->dma_bounce_buffer =
+                               kmalloc(hdata->dma_bounce_len, GFP_KERNEL);
+                       hdata->dma_buffer_pool = BUF_SCSI_ALLOCED;
+               }
 
-       if (scsi_alloc_out_of_range ||
-           !HDATA(cmd->device->host)->dma_bounce_buffer) {
-           HDATA(cmd->device->host)->dma_bounce_buffer =
-               amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
-                                      "GVP II SCSI Bounce Buffer");
+               if (scsi_alloc_out_of_range ||
+                   !hdata->dma_bounce_buffer) {
+                       hdata->dma_bounce_buffer =
+                               amiga_chip_alloc(hdata->dma_bounce_len,
+                                                "GVP II SCSI Bounce Buffer");
 
-           if(!HDATA(cmd->device->host)->dma_bounce_buffer)
-           {
-               HDATA(cmd->device->host)->dma_bounce_len = 0;
-               return 1;
-           }
+                       if (!hdata->dma_bounce_buffer) {
+                               hdata->dma_bounce_len = 0;
+                               return 1;
+                       }
 
-           HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
-       }
+                       hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+               }
 
-       /* check if the address of the bounce buffer is OK */
-       addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
-
-       if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
-           /* fall back to Chip RAM if address out of range */
-           if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
-               kfree (HDATA(cmd->device->host)->dma_bounce_buffer);
-               scsi_alloc_out_of_range = 1;
-           } else {
-               amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer);
-            }
-               
-           HDATA(cmd->device->host)->dma_bounce_buffer =
-               amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
-                                      "GVP II SCSI Bounce Buffer");
-
-           if(!HDATA(cmd->device->host)->dma_bounce_buffer)
-           {
-               HDATA(cmd->device->host)->dma_bounce_len = 0;
-               return 1;
-           }
-
-           addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
-           HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
-       }
-           
-       if (!dir_in) {
-           /* copy to bounce buffer for a write */
-           memcpy (HDATA(cmd->device->host)->dma_bounce_buffer,
-                   cmd->SCp.ptr, cmd->SCp.this_residual);
+               /* check if the address of the bounce buffer is OK */
+               addr = virt_to_bus(hdata->dma_bounce_buffer);
+
+               if (addr & hdata->dma_xfer_mask) {
+                       /* fall back to Chip RAM if address out of range */
+                       if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) {
+                               kfree(hdata->dma_bounce_buffer);
+                               scsi_alloc_out_of_range = 1;
+                       } else {
+                               amiga_chip_free(hdata->dma_bounce_buffer);
+                       }
+
+                       hdata->dma_bounce_buffer =
+                               amiga_chip_alloc(hdata->dma_bounce_len,
+                                                "GVP II SCSI Bounce Buffer");
+
+                       if (!hdata->dma_bounce_buffer) {
+                               hdata->dma_bounce_len = 0;
+                               return 1;
+                       }
+
+                       addr = virt_to_bus(hdata->dma_bounce_buffer);
+                       hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+               }
+
+               if (!dir_in) {
+                       /* copy to bounce buffer for a write */
+                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                              cmd->SCp.this_residual);
+               }
        }
-    }
 
-    /* setup dma direction */
-    if (!dir_in)
-       cntr |= GVP11_DMAC_DIR_WRITE;
+       /* setup dma direction */
+       if (!dir_in)
+               cntr |= GVP11_DMAC_DIR_WRITE;
 
-    HDATA(cmd->device->host)->dma_dir = dir_in;
-    DMA(cmd->device->host)->CNTR = cntr;
+       hdata->dma_dir = dir_in;
+       DMA(cmd->device->host)->CNTR = cntr;
 
-    /* setup DMA *physical* address */
-    DMA(cmd->device->host)->ACR = addr;
+       /* setup DMA *physical* address */
+       DMA(cmd->device->host)->ACR = addr;
 
-    if (dir_in)
-       /* invalidate any cache */
-       cache_clear (addr, cmd->SCp.this_residual);
-    else
-       /* push any dirty cache */
-       cache_push (addr, cmd->SCp.this_residual);
+       if (dir_in) {
+               /* invalidate any cache */
+               cache_clear(addr, cmd->SCp.this_residual);
+       } else {
+               /* push any dirty cache */
+               cache_push(addr, cmd->SCp.this_residual);
+       }
 
-    if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0))
-           DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
+       bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0;
+       if (bank_mask)
+               DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
 
-    /* start DMA */
-    DMA(cmd->device->host)->ST_DMA = 1;
+       /* start DMA */
+       DMA(cmd->device->host)->ST_DMA = 1;
 
-    /* return success */
-    return 0;
+       /* return success */
+       return 0;
 }
 
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-    /* stop DMA */
-    DMA(instance)->SP_DMA = 1;
-    /* remove write bit from CONTROL bits */
-    DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
-
-    /* copy from a bounce buffer, if necessary */
-    if (status && HDATA(instance)->dma_bounce_buffer) {
-       if (HDATA(instance)->dma_dir && SCpnt)
-           memcpy (SCpnt->SCp.ptr, 
-                   HDATA(instance)->dma_bounce_buffer,
-                   SCpnt->SCp.this_residual);
-       
-       if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED)
-           kfree (HDATA(instance)->dma_bounce_buffer);
-       else
-           amiga_chip_free(HDATA(instance)->dma_bounce_buffer);
-       
-       HDATA(instance)->dma_bounce_buffer = NULL;
-       HDATA(instance)->dma_bounce_len = 0;
-    }
+       struct WD33C93_hostdata *hdata = shost_priv(instance);
+
+       /* stop DMA */
+       DMA(instance)->SP_DMA = 1;
+       /* remove write bit from CONTROL bits */
+       DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+
+       /* copy from a bounce buffer, if necessary */
+       if (status && hdata->dma_bounce_buffer) {
+               if (hdata->dma_dir && SCpnt)
+                       memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+                              SCpnt->SCp.this_residual);
+
+               if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED)
+                       kfree(hdata->dma_bounce_buffer);
+               else
+                       amiga_chip_free(hdata->dma_bounce_buffer);
+
+               hdata->dma_bounce_buffer = NULL;
+               hdata->dma_bounce_len = 0;
+       }
 }
 
 #define CHECK_WD33C93
 
 int __init gvp11_detect(struct scsi_host_template *tpnt)
 {
-    static unsigned char called = 0;
-    struct Scsi_Host *instance;
-    unsigned long address;
-    unsigned int epc;
-    struct zorro_dev *z = NULL;
-    unsigned int default_dma_xfer_mask;
-    wd33c93_regs regs;
-    int num_gvp11 = 0;
+       static unsigned char called = 0;
+       struct Scsi_Host *instance;
+       unsigned long address;
+       unsigned int epc;
+       struct zorro_dev *z = NULL;
+       unsigned int default_dma_xfer_mask;
+       struct WD33C93_hostdata *hdata;
+       wd33c93_regs regs;
+       int num_gvp11 = 0;
 #ifdef CHECK_WD33C93
-    volatile unsigned char *sasr_3393, *scmd_3393;
-    unsigned char save_sasr;
-    unsigned char q, qq;
+       volatile unsigned char *sasr_3393, *scmd_3393;
+       unsigned char save_sasr;
+       unsigned char q, qq;
 #endif
 
-    if (!MACH_IS_AMIGA || called)
-       return 0;
-    called = 1;
-
-    tpnt->proc_name = "GVP11";
-    tpnt->proc_info = &wd33c93_proc_info;
-
-    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-       /* 
-        * This should (hopefully) be the correct way to identify
-        * all the different GVP SCSI controllers (except for the
-        * SERIES I though).
-        */
-
-       if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
-           z->id == ZORRO_PROD_GVP_SERIES_II)
-           default_dma_xfer_mask = ~0x00ffffff;
-       else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
-                z->id == ZORRO_PROD_GVP_A530_SCSI ||
-                z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
-           default_dma_xfer_mask = ~0x01ffffff;
-       else if (z->id == ZORRO_PROD_GVP_A1291 ||
-                z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
-           default_dma_xfer_mask = ~0x07ffffff;
-       else
-           continue;
-
-       /*
-        * Rumors state that some GVP ram boards use the same product
-        * code as the SCSI controllers. Therefore if the board-size
-        * is not 64KB we asume it is a ram board and bail out.
-        */
-       if (z->resource.end-z->resource.start != 0xffff)
-               continue;
-
-       address = z->resource.start;
-       if (!request_mem_region(address, 256, "wd33c93"))
-           continue;
+       if (!MACH_IS_AMIGA || called)
+               return 0;
+       called = 1;
+
+       tpnt->proc_name = "GVP11";
+       tpnt->proc_info = &wd33c93_proc_info;
+
+       while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+               /*
+                * This should (hopefully) be the correct way to identify
+                * all the different GVP SCSI controllers (except for the
+                * SERIES I though).
+                */
+
+               if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
+                   z->id == ZORRO_PROD_GVP_SERIES_II)
+                       default_dma_xfer_mask = ~0x00ffffff;
+               else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
+                        z->id == ZORRO_PROD_GVP_A530_SCSI ||
+                        z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
+                       default_dma_xfer_mask = ~0x01ffffff;
+               else if (z->id == ZORRO_PROD_GVP_A1291 ||
+                        z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
+                       default_dma_xfer_mask = ~0x07ffffff;
+               else
+                       continue;
+
+               /*
+                * Rumors state that some GVP ram boards use the same product
+                * code as the SCSI controllers. Therefore if the board-size
+                * is not 64KB we asume it is a ram board and bail out.
+                */
+               if (z->resource.end - z->resource.start != 0xffff)
+                       continue;
+
+               address = z->resource.start;
+               if (!request_mem_region(address, 256, "wd33c93"))
+                       continue;
 
 #ifdef CHECK_WD33C93
 
-       /*
-        * These darn GVP boards are a problem - it can be tough to tell
-        * whether or not they include a SCSI controller. This is the
-        * ultimate Yet-Another-GVP-Detection-Hack in that it actually
-        * probes for a WD33c93 chip: If we find one, it's extremely
-        * likely that this card supports SCSI, regardless of Product_
-        * Code, Board_Size, etc. 
-        */
-
-    /* Get pointers to the presumed register locations and save contents */
-
-       sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
-       scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
-       save_sasr = *sasr_3393;
-
-    /* First test the AuxStatus Reg */
-
-       q = *sasr_3393;         /* read it */
-       if (q & 0x08)           /* bit 3 should always be clear */
-               goto release;
-       *sasr_3393 = WD_AUXILIARY_STATUS;        /* setup indirect address */
-       if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */
-               *sasr_3393 = save_sasr; /* Oops - restore this byte */
-               goto release;
+               /*
+                * These darn GVP boards are a problem - it can be tough to tell
+                * whether or not they include a SCSI controller. This is the
+                * ultimate Yet-Another-GVP-Detection-Hack in that it actually
+                * probes for a WD33c93 chip: If we find one, it's extremely
+                * likely that this card supports SCSI, regardless of Product_
+                * Code, Board_Size, etc.
+                */
+
+               /* Get pointers to the presumed register locations and save contents */
+
+               sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
+               scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
+               save_sasr = *sasr_3393;
+
+               /* First test the AuxStatus Reg */
+
+               q = *sasr_3393; /* read it */
+               if (q & 0x08)   /* bit 3 should always be clear */
+                       goto release;
+               *sasr_3393 = WD_AUXILIARY_STATUS;       /* setup indirect address */
+               if (*sasr_3393 == WD_AUXILIARY_STATUS) {        /* shouldn't retain the write */
+                       *sasr_3393 = save_sasr; /* Oops - restore this byte */
+                       goto release;
                }
-       if (*sasr_3393 != q) {  /* should still read the same */
-               *sasr_3393 = save_sasr; /* Oops - restore this byte */
-               goto release;
+               if (*sasr_3393 != q) {  /* should still read the same */
+                       *sasr_3393 = save_sasr; /* Oops - restore this byte */
+                       goto release;
                }
-       if (*scmd_3393 != q)    /* and so should the image at 0x1f */
-               goto release;
-
-
-    /* Ok, we probably have a wd33c93, but let's check a few other places
-     * for good measure. Make sure that this works for both 'A and 'B    
-     * chip versions.
-     */
-
-       *sasr_3393 = WD_SCSI_STATUS;
-       q = *scmd_3393;
-       *sasr_3393 = WD_SCSI_STATUS;
-       *scmd_3393 = ~q;
-       *sasr_3393 = WD_SCSI_STATUS;
-       qq = *scmd_3393;
-       *sasr_3393 = WD_SCSI_STATUS;
-       *scmd_3393 = q;
-       if (qq != q)                    /* should be read only */
-               goto release;
-       *sasr_3393 = 0x1e;      /* this register is unimplemented */
-       q = *scmd_3393;
-       *sasr_3393 = 0x1e;
-       *scmd_3393 = ~q;
-       *sasr_3393 = 0x1e;
-       qq = *scmd_3393;
-       *sasr_3393 = 0x1e;
-       *scmd_3393 = q;
-       if (qq != q || qq != 0xff)      /* should be read only, all 1's */
-               goto release;
-       *sasr_3393 = WD_TIMEOUT_PERIOD;
-       q = *scmd_3393;
-       *sasr_3393 = WD_TIMEOUT_PERIOD;
-       *scmd_3393 = ~q;
-       *sasr_3393 = WD_TIMEOUT_PERIOD;
-       qq = *scmd_3393;
-       *sasr_3393 = WD_TIMEOUT_PERIOD;
-       *scmd_3393 = q;
-       if (qq != (~q & 0xff))          /* should be read/write */
-               goto release;
+               if (*scmd_3393 != q)    /* and so should the image at 0x1f */
+                       goto release;
+
+               /*
+                * Ok, we probably have a wd33c93, but let's check a few other places
+                * for good measure. Make sure that this works for both 'A and 'B
+                * chip versions.
+                */
+
+               *sasr_3393 = WD_SCSI_STATUS;
+               q = *scmd_3393;
+               *sasr_3393 = WD_SCSI_STATUS;
+               *scmd_3393 = ~q;
+               *sasr_3393 = WD_SCSI_STATUS;
+               qq = *scmd_3393;
+               *sasr_3393 = WD_SCSI_STATUS;
+               *scmd_3393 = q;
+               if (qq != q)    /* should be read only */
+                       goto release;
+               *sasr_3393 = 0x1e;      /* this register is unimplemented */
+               q = *scmd_3393;
+               *sasr_3393 = 0x1e;
+               *scmd_3393 = ~q;
+               *sasr_3393 = 0x1e;
+               qq = *scmd_3393;
+               *sasr_3393 = 0x1e;
+               *scmd_3393 = q;
+               if (qq != q || qq != 0xff)      /* should be read only, all 1's */
+                       goto release;
+               *sasr_3393 = WD_TIMEOUT_PERIOD;
+               q = *scmd_3393;
+               *sasr_3393 = WD_TIMEOUT_PERIOD;
+               *scmd_3393 = ~q;
+               *sasr_3393 = WD_TIMEOUT_PERIOD;
+               qq = *scmd_3393;
+               *sasr_3393 = WD_TIMEOUT_PERIOD;
+               *scmd_3393 = q;
+               if (qq != (~q & 0xff))  /* should be read/write */
+                       goto release;
 #endif
 
-       instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
-       if(instance == NULL)
-               goto release;
-       instance->base = ZTWO_VADDR(address);
-       instance->irq = IRQ_AMIGA_PORTS;
-       instance->unique_id = z->slotaddr;
-
-       if (gvp11_xfer_mask)
-               HDATA(instance)->dma_xfer_mask = gvp11_xfer_mask;
-       else
-               HDATA(instance)->dma_xfer_mask = default_dma_xfer_mask;
-
-
-       DMA(instance)->secret2 = 1;
-       DMA(instance)->secret1 = 0;
-       DMA(instance)->secret3 = 15;
-       while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) ;
-       DMA(instance)->CNTR = 0;
-
-       DMA(instance)->BANK = 0;
-
-       epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
-
-       /*
-        * Check for 14MHz SCSI clock
-        */
-       regs.SASR = &(DMA(instance)->SASR);
-       regs.SCMD = &(DMA(instance)->SCMD);
-       HDATA(instance)->no_sync = 0xff;
-       HDATA(instance)->fast = 0;
-       HDATA(instance)->dma_mode = CTRL_DMA;
-       wd33c93_init(instance, regs, dma_setup, dma_stop,
-                    (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
-                                            : WD33C93_FS_12_15);
-
-       if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI",
-                       instance))
-               goto unregister;
-       DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
-       num_gvp11++;
-       continue;
+               instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+               if (instance == NULL)
+                       goto release;
+               instance->base = ZTWO_VADDR(address);
+               instance->irq = IRQ_AMIGA_PORTS;
+               instance->unique_id = z->slotaddr;
+
+               hdata = shost_priv(instance);
+               if (gvp11_xfer_mask)
+                       hdata->dma_xfer_mask = gvp11_xfer_mask;
+               else
+                       hdata->dma_xfer_mask = default_dma_xfer_mask;
+
+               DMA(instance)->secret2 = 1;
+               DMA(instance)->secret1 = 0;
+               DMA(instance)->secret3 = 15;
+               while (DMA(instance)->CNTR & GVP11_DMAC_BUSY)
+                       ;
+               DMA(instance)->CNTR = 0;
+
+               DMA(instance)->BANK = 0;
+
+               epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
+
+               /*
+                * Check for 14MHz SCSI clock
+                */
+               regs.SASR = &(DMA(instance)->SASR);
+               regs.SCMD = &(DMA(instance)->SCMD);
+               hdata->no_sync = 0xff;
+               hdata->fast = 0;
+               hdata->dma_mode = CTRL_DMA;
+               wd33c93_init(instance, regs, dma_setup, dma_stop,
+                            (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
+                                                    : WD33C93_FS_12_15);
+
+               if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
+                               "GVP11 SCSI", instance))
+                       goto unregister;
+               DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+               num_gvp11++;
+               continue;
 
 unregister:
-       scsi_unregister(instance);
-       wd33c93_release();
+               scsi_unregister(instance);
 release:
-       release_mem_region(address, 256);
-    }
+               release_mem_region(address, 256);
+       }
 
-    return num_gvp11;
+       return num_gvp11;
 }
 
 static int gvp11_bus_reset(struct scsi_cmnd *cmd)
@@ -389,12 +391,11 @@ static struct scsi_host_template driver_template = {
 int gvp11_release(struct Scsi_Host *instance)
 {
 #ifdef MODULE
-    DMA(instance)->CNTR = 0;
-    release_mem_region(ZTWO_PADDR(instance->base), 256);
-    free_irq(IRQ_AMIGA_PORTS, instance);
-    wd33c93_release();
+       DMA(instance)->CNTR = 0;
+       release_mem_region(ZTWO_PADDR(instance->base), 256);
+       free_irq(IRQ_AMIGA_PORTS, instance);
 #endif
-    return 1;
+       return 1;
 }
 
 MODULE_LICENSE("GPL");
index bf22859..e2efdf9 100644 (file)
@@ -15,11 +15,11 @@ int gvp11_detect(struct scsi_host_template *);
 int gvp11_release(struct Scsi_Host *);
 
 #ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
+#define CMD_PER_LUN            2
 #endif
 
 #ifndef CAN_QUEUE
-#define CAN_QUEUE 16
+#define CAN_QUEUE              16
 #endif
 
 #ifndef HOSTS_C
@@ -28,24 +28,24 @@ int gvp11_release(struct Scsi_Host *);
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
-#define GVP11_XFER_MASK  (0xff000001)
+#define GVP11_XFER_MASK                (0xff000001)
 
 typedef struct {
-             unsigned char      pad1[64];
-    volatile unsigned short     CNTR;
-             unsigned char      pad2[31];
-    volatile unsigned char      SASR;
-             unsigned char      pad3;
-    volatile unsigned char      SCMD;
-             unsigned char      pad4[4];
-    volatile unsigned short     BANK;
-             unsigned char      pad5[6];
-    volatile unsigned long      ACR;
-    volatile unsigned short     secret1; /* store 0 here */
-    volatile unsigned short     ST_DMA;
-    volatile unsigned short     SP_DMA;
-    volatile unsigned short     secret2; /* store 1 here */
-    volatile unsigned short     secret3; /* store 15 here */
+                unsigned char  pad1[64];
+       volatile unsigned short CNTR;
+                unsigned char  pad2[31];
+       volatile unsigned char  SASR;
+                unsigned char  pad3;
+       volatile unsigned char  SCMD;
+                unsigned char  pad4[4];
+       volatile unsigned short BANK;
+                unsigned char  pad5[6];
+       volatile unsigned long  ACR;
+       volatile unsigned short secret1; /* store 0 here */
+       volatile unsigned short ST_DMA;
+       volatile unsigned short SP_DMA;
+       volatile unsigned short secret2; /* store 1 here */
+       volatile unsigned short secret3; /* store 15 here */
 } gvp11_scsiregs;
 
 /* bits in CNTR */
index 183d3a4..c016426 100644 (file)
@@ -2708,14 +2708,6 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
                        c->Request.CDB[8] = (size >> 8) & 0xFF;
                        c->Request.CDB[9] = size & 0xFF;
                        break;
-
-               case HPSA_READ_CAPACITY:
-                       c->Request.CDBLen = 10;
-                       c->Request.Type.Attribute = ATTR_SIMPLE;
-                       c->Request.Type.Direction = XFER_READ;
-                       c->Request.Timeout = 0;
-                       c->Request.CDB[0] = cmd;
-                       break;
                case HPSA_CACHE_FLUSH:
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
index 56fb982..78de9b6 100644 (file)
@@ -152,21 +152,6 @@ struct SenseSubsystem_info {
        u8 reserved1[1108];
 };
 
-#define HPSA_READ_CAPACITY 0x25 /* Read Capacity */
-struct ReadCapdata {
-       u8 total_size[4];       /* Total size in blocks */
-       u8 block_size[4];       /* Size of blocks in bytes */
-};
-
-#if 0
-/* 12 byte commands not implemented in firmware yet. */
-#define HPSA_READ      0xa8
-#define HPSA_WRITE     0xaa
-#endif
-
-#define HPSA_READ   0x28    /* Read(10) */
-#define HPSA_WRITE  0x2a    /* Write(10) */
-
 /* BMIC commands */
 #define BMIC_READ 0x26
 #define BMIC_WRITE 0x27
index c2eea71..d18f45c 100644 (file)
@@ -2245,7 +2245,7 @@ static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,
        DECLARE_COMPLETION_ONSTACK(comp);
        int wait;
        unsigned long flags;
-       signed long timeout = init_timeout * HZ;
+       signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ;
 
        ENTER;
        do {
@@ -3013,6 +3013,7 @@ static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost)
        if (crq->valid & 0x80) {
                if (++async_crq->cur == async_crq->size)
                        async_crq->cur = 0;
+               rmb();
        } else
                crq = NULL;
 
@@ -3035,6 +3036,7 @@ static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost)
        if (crq->valid & 0x80) {
                if (++queue->cur == queue->size)
                        queue->cur = 0;
+               rmb();
        } else
                crq = NULL;
 
@@ -3083,12 +3085,14 @@ static void ibmvfc_tasklet(void *data)
                while ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
                        ibmvfc_handle_async(async, vhost);
                        async->valid = 0;
+                       wmb();
                }
 
                /* Pull all the valid messages off the CRQ */
                while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
                        ibmvfc_handle_crq(crq, vhost);
                        crq->valid = 0;
+                       wmb();
                }
 
                vio_enable_interrupts(vdev);
@@ -3096,10 +3100,12 @@ static void ibmvfc_tasklet(void *data)
                        vio_disable_interrupts(vdev);
                        ibmvfc_handle_async(async, vhost);
                        async->valid = 0;
+                       wmb();
                } else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
                        vio_disable_interrupts(vdev);
                        ibmvfc_handle_crq(crq, vhost);
                        crq->valid = 0;
+                       wmb();
                } else
                        done = 1;
        }
index d25106a..7e97427 100644 (file)
@@ -38,6 +38,7 @@
 #define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT       \
                (IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT)
 #define IBMVFC_INIT_TIMEOUT            120
+#define IBMVFC_ABORT_WAIT_TIMEOUT      40
 #define IBMVFC_MAX_REQUESTS_DEFAULT    100
 
 #define IBMVFC_DEBUG                   0
index 9eae04a..7608310 100644 (file)
@@ -206,8 +206,10 @@ static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn)
 }
 
 static void
-iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_sw_tcp_conn *tcp_sw_conn)
+iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)
 {
+       struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+       struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
        struct sock *sk = tcp_sw_conn->sock->sk;
 
        /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
@@ -555,7 +557,7 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)
                return;
 
        sock_hold(sock->sk);
-       iscsi_sw_tcp_conn_restore_callbacks(tcp_sw_conn);
+       iscsi_sw_tcp_conn_restore_callbacks(conn);
        sock_put(sock->sk);
 
        spin_lock_bh(&session->lock);
index ca6b7bc..94644ba 100644 (file)
@@ -36,7 +36,6 @@ struct iscsi_sw_tcp_send {
 };
 
 struct iscsi_sw_tcp_conn {
-       struct iscsi_conn       *iscsi_conn;
        struct socket           *sock;
 
        struct iscsi_sw_tcp_send out;
index 1087a7f..c7985da 100644 (file)
@@ -132,7 +132,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
                switch (fmt) {
                case ELS_ADDR_FMT_PORT:
                        FC_DISC_DBG(disc, "Port address format for port "
-                                   "(%6x)\n", ntoh24(pp->rscn_fid));
+                                   "(%6.6x)\n", ntoh24(pp->rscn_fid));
                        dp = kzalloc(sizeof(*dp), GFP_KERNEL);
                        if (!dp) {
                                redisc = 1;
@@ -440,7 +440,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
                ids.port_id = ntoh24(np->fp_fid);
                ids.port_name = ntohll(np->fp_wwpn);
 
-               if (ids.port_id != fc_host_port_id(lport->host) &&
+               if (ids.port_id != lport->port_id &&
                    ids.port_name != lport->wwpn) {
                        rdata = lport->tt.rport_create(lport, ids.port_id);
                        if (rdata) {
@@ -449,7 +449,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
                        } else {
                                printk(KERN_WARNING "libfc: Failed to allocate "
                                       "memory for the newly discovered port "
-                                      "(%6x)\n", ids.port_id);
+                                      "(%6.6x)\n", ids.port_id);
                                error = -ENOMEM;
                        }
                }
@@ -607,7 +607,7 @@ static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
                        rdata->ids.port_name = port_name;
                else if (rdata->ids.port_name != port_name) {
                        FC_DISC_DBG(disc, "GPN_ID accepted.  WWPN changed. "
-                                   "Port-id %x wwpn %llx\n",
+                                   "Port-id %6.6x wwpn %16.16llx\n",
                                    rdata->ids.port_id, port_name);
                        lport->tt.rport_logoff(rdata);
 
index 5374872..e9412b7 100644 (file)
@@ -63,7 +63,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
                return NULL;
        }
 
-       fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type,
+       fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type,
                       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
        return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);
index e5df0d4..104e0fb 100644 (file)
@@ -488,7 +488,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
         */
        spin_lock_bh(&ep->ex_lock);
        ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ;   /* not first seq */
-       if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT))
+       if (f_ctl & FC_FC_SEQ_INIT)
                ep->esb_stat &= ~ESB_ST_SEQ_INIT;
        spin_unlock_bh(&ep->ex_lock);
        return error;
@@ -676,9 +676,10 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
        }
        memset(ep, 0, sizeof(*ep));
 
-       cpu = smp_processor_id();
+       cpu = get_cpu();
        pool = per_cpu_ptr(mp->pool, cpu);
        spin_lock_bh(&pool->lock);
+       put_cpu();
        index = pool->next_index;
        /* allocate new exch from pool */
        while (fc_exch_ptr_get(pool, index)) {
@@ -734,19 +735,14 @@ err:
  * EM is selected when a NULL match function pointer is encountered
  * or when a call to a match function returns true.
  */
-static struct fc_exch *fc_exch_alloc(struct fc_lport *lport,
-                                    struct fc_frame *fp)
+static inline struct fc_exch *fc_exch_alloc(struct fc_lport *lport,
+                                           struct fc_frame *fp)
 {
        struct fc_exch_mgr_anchor *ema;
-       struct fc_exch *ep;
 
-       list_for_each_entry(ema, &lport->ema_list, ema_list) {
-               if (!ema->match || ema->match(fp)) {
-                       ep = fc_exch_em_alloc(lport, ema->mp);
-                       if (ep)
-                               return ep;
-               }
-       }
+       list_for_each_entry(ema, &lport->ema_list, ema_list)
+               if (!ema->match || ema->match(fp))
+                       return fc_exch_em_alloc(lport, ema->mp);
        return NULL;
 }
 
@@ -920,13 +916,9 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport,
         * Find or create the sequence.
         */
        if (fc_sof_is_init(fr_sof(fp))) {
-               sp = fc_seq_start_next(&ep->seq);
-               if (!sp) {
-                       reject = FC_RJT_SEQ_XS; /* exchange shortage */
-                       goto rel;
-               }
-               sp->id = fh->fh_seq_id;
+               sp = &ep->seq;
                sp->ssb_stat |= SSB_ST_RESP;
+               sp->id = fh->fh_seq_id;
        } else {
                sp = &ep->seq;
                if (sp->id != fh->fh_seq_id) {
@@ -1250,9 +1242,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
        struct fc_frame_header *fh = fc_frame_header_get(fp);
        struct fc_seq *sp = NULL;
        struct fc_exch *ep = NULL;
-       enum fc_sof sof;
-       enum fc_eof eof;
-       u32 f_ctl;
        enum fc_pf_rjt_reason reject;
 
        /* We can have the wrong fc_lport at this point with NPIV, which is a
@@ -1269,9 +1258,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
        if (reject == FC_RJT_NONE) {
                sp = fr_seq(fp);        /* sequence will be held */
                ep = fc_seq_exch(sp);
-               sof = fr_sof(fp);
-               eof = fr_eof(fp);
-               f_ctl = ntoh24(fh->fh_f_ctl);
                fc_seq_send_ack(sp, fp);
 
                /*
@@ -1336,17 +1322,15 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
                goto rel;
        }
        sof = fr_sof(fp);
+       sp = &ep->seq;
        if (fc_sof_is_init(sof)) {
-               sp = fc_seq_start_next(&ep->seq);
-               sp->id = fh->fh_seq_id;
                sp->ssb_stat |= SSB_ST_RESP;
-       } else {
-               sp = &ep->seq;
-               if (sp->id != fh->fh_seq_id) {
-                       atomic_inc(&mp->stats.seq_not_found);
-                       goto rel;
-               }
+               sp->id = fh->fh_seq_id;
+       } else if (sp->id != fh->fh_seq_id) {
+               atomic_inc(&mp->stats.seq_not_found);
+               goto rel;
        }
+
        f_ctl = ntoh24(fh->fh_f_ctl);
        fr_seq(fp) = sp;
        if (f_ctl & FC_FC_SEQ_INIT)
@@ -1763,7 +1747,6 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
                fc_exch_done(sp);
                goto out;
        }
-       sp = fc_seq_start_next(sp);
        acc = fc_frame_payload_get(fp, sizeof(*acc));
        memset(acc, 0, sizeof(*acc));
        acc->reca_cmd = ELS_LS_ACC;
@@ -1944,7 +1927,7 @@ static void fc_exch_rrq(struct fc_exch *ep)
                did = ep->sid;
 
        fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, did,
-                      fc_host_port_id(lport->host), FC_TYPE_ELS,
+                      lport->port_id, FC_TYPE_ELS,
                       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
        if (fc_exch_seq_send(lport, fp, fc_exch_rrq_resp, NULL, ep,
index 17396c7..ec1f66c 100644 (file)
@@ -97,7 +97,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);
 static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
 static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
 static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
-static void fc_timeout_error(struct fc_fcp_pkt *);
+static void fc_fcp_recovery(struct fc_fcp_pkt *);
 static void fc_fcp_timeout(unsigned long);
 static void fc_fcp_rec(struct fc_fcp_pkt *);
 static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
@@ -121,7 +121,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);
 #define FC_DATA_UNDRUN         7
 #define FC_ERROR               8
 #define FC_HRD_ERROR           9
-#define FC_CMD_TIME_OUT                10
+#define FC_CMD_RECOVERY                10
 
 /*
  * Error recovery timeout values.
@@ -446,9 +446,16 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
        len = fr_len(fp) - sizeof(*fh);
        buf = fc_frame_payload_get(fp, 0);
 
-       /* if this I/O is ddped, update xfer len */
-       fc_fcp_ddp_done(fsp);
-
+       /*
+        * if this I/O is ddped then clear it
+        * and initiate recovery since data
+        * frames are expected to be placed
+        * directly in that case.
+        */
+       if (fsp->xfer_ddp != FC_XID_UNKNOWN) {
+               fc_fcp_ddp_done(fsp);
+               goto err;
+       }
        if (offset + len > fsp->data_len) {
                /* this should never happen */
                if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) &&
@@ -456,8 +463,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                        goto crc_err;
                FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "
                           "data_len %x\n", len, offset, fsp->data_len);
-               fc_fcp_retry_cmd(fsp);
-               return;
+               goto err;
        }
        if (offset != fsp->xfer_len)
                fsp->state |= FC_SRB_DISCONTIG;
@@ -478,13 +484,14 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 
                if (~crc != le32_to_cpu(fr_crc(fp))) {
 crc_err:
-                       stats = fc_lport_get_stats(lport);
+                       stats = per_cpu_ptr(lport->dev_stats, get_cpu());
                        stats->ErrorFrames++;
-                       /* FIXME - per cpu count, not total count! */
+                       /* per cpu count, not total count, but OK for limit */
                        if (stats->InvalidCRCCount++ < 5)
                                printk(KERN_WARNING "libfc: CRC error on data "
-                                      "frame for port (%6x)\n",
-                                      fc_host_port_id(lport->host));
+                                      "frame for port (%6.6x)\n",
+                                      lport->port_id);
+                       put_cpu();
                        /*
                         * Assume the frame is total garbage.
                         * We may have copied it over the good part
@@ -493,7 +500,7 @@ crc_err:
                         * Otherwise, ignore it.
                         */
                        if (fsp->state & FC_SRB_DISCONTIG)
-                               fc_fcp_retry_cmd(fsp);
+                               goto err;
                        return;
                }
        }
@@ -509,6 +516,9 @@ crc_err:
        if (unlikely(fsp->state & FC_SRB_RCV_STATUS) &&
            fsp->xfer_len == fsp->data_len - fsp->scsi_resid)
                fc_fcp_complete_locked(fsp);
+       return;
+err:
+       fc_fcp_recovery(fsp);
 }
 
 /**
@@ -834,8 +844,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                                         * exit here
                                         */
                                        return;
-                               } else
-                                       goto err;
+                               }
                        }
                        if (flags & FCP_SNS_LEN_VAL) {
                                snsl = ntohl(rp_ex->fr_sns_len);
@@ -885,7 +894,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                        return;
                }
                fsp->status_code = FC_DATA_OVRRUN;
-               FC_FCP_DBG(fsp, "tgt %6x xfer len %zx greater than expected, "
+               FC_FCP_DBG(fsp, "tgt %6.6x xfer len %zx greater than expected, "
                           "len %x, data len %x\n",
                           fsp->rport->port_id,
                           fsp->xfer_len, expected_len, fsp->data_len);
@@ -1100,7 +1109,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
        rpriv = rport->dd_data;
 
        fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id,
-                      fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
+                      rpriv->local_port->port_id, FC_TYPE_FCP,
                       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
        seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy,
@@ -1341,7 +1350,7 @@ static void fc_fcp_timeout(unsigned long data)
        else if (fsp->state & FC_SRB_RCV_STATUS)
                fc_fcp_complete_locked(fsp);
        else
-               fc_timeout_error(fsp);
+               fc_fcp_recovery(fsp);
        fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;
 unlock:
        fc_fcp_unlock_pkt(fsp);
@@ -1373,7 +1382,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
 
        fr_seq(fp) = fsp->seq_ptr;
        fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
-                      fc_host_port_id(rpriv->local_port->host), FC_TYPE_ELS,
+                      rpriv->local_port->port_id, FC_TYPE_ELS,
                       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
        if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
                                 fc_fcp_rec_resp, fsp,
@@ -1385,7 +1394,7 @@ retry:
        if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
                fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
        else
-               fc_timeout_error(fsp);
+               fc_fcp_recovery(fsp);
 }
 
 /**
@@ -1454,7 +1463,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
                                fc_fcp_retry_cmd(fsp);
                                break;
                        }
-                       fc_timeout_error(fsp);
+                       fc_fcp_recovery(fsp);
                        break;
                }
        } else if (opcode == ELS_LS_ACC) {
@@ -1553,7 +1562,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                break;
 
        default:
-               FC_FCP_DBG(fsp, "REC %p fid %x error unexpected error %d\n",
+               FC_FCP_DBG(fsp, "REC %p fid %6.6x error unexpected error %d\n",
                           fsp, fsp->rport->port_id, error);
                fsp->status_code = FC_CMD_PLOGO;
                /* fall through */
@@ -1563,13 +1572,13 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                 * Assume REC or LS_ACC was lost.
                 * The exchange manager will have aborted REC, so retry.
                 */
-               FC_FCP_DBG(fsp, "REC fid %x error error %d retry %d/%d\n",
+               FC_FCP_DBG(fsp, "REC fid %6.6x error error %d retry %d/%d\n",
                           fsp->rport->port_id, error, fsp->recov_retry,
                           FC_MAX_RECOV_RETRY);
                if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
                        fc_fcp_rec(fsp);
                else
-                       fc_timeout_error(fsp);
+                       fc_fcp_recovery(fsp);
                break;
        }
        fc_fcp_unlock_pkt(fsp);
@@ -1578,12 +1587,12 @@ out:
 }
 
 /**
- * fc_timeout_error() - Handler for fcp_pkt timeouts
- * @fsp: The FCP packt that has timed out
+ * fc_fcp_recovery() - Handler for fcp_pkt recovery
+ * @fsp: The FCP pkt that needs to be aborted
  */
-static void fc_timeout_error(struct fc_fcp_pkt *fsp)
+static void fc_fcp_recovery(struct fc_fcp_pkt *fsp)
 {
-       fsp->status_code = FC_CMD_TIME_OUT;
+       fsp->status_code = FC_CMD_RECOVERY;
        fsp->cdb_status = 0;
        fsp->io_status = 0;
        /*
@@ -1631,7 +1640,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
        srr->srr_rel_off = htonl(offset);
 
        fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id,
-                      fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
+                      rpriv->local_port->port_id, FC_TYPE_FCP,
                       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
        seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
@@ -1689,7 +1698,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
                break;
        case ELS_LS_RJT:
        default:
-               fc_timeout_error(fsp);
+               fc_fcp_recovery(fsp);
                break;
        }
        fc_fcp_unlock_pkt(fsp);
@@ -1715,7 +1724,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
                if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
                        fc_fcp_rec(fsp);
                else
-                       fc_timeout_error(fsp);
+                       fc_fcp_recovery(fsp);
                break;
        case -FC_EX_CLOSED:                     /* e.g., link failure */
                /* fall through */
@@ -1810,7 +1819,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
        /*
         * setup the data direction
         */
-       stats = fc_lport_get_stats(lport);
+       stats = per_cpu_ptr(lport->dev_stats, get_cpu());
        if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
                fsp->req_flags = FC_SRB_READ;
                stats->InputRequests++;
@@ -1823,6 +1832,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
                fsp->req_flags = 0;
                stats->ControlRequests++;
        }
+       put_cpu();
 
        fsp->tgt_flags = rpriv->flags;
 
@@ -1907,6 +1917,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
                }
                break;
        case FC_ERROR:
+               FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+                          "due to FC_ERROR\n");
                sc_cmd->result = DID_ERROR << 16;
                break;
        case FC_DATA_UNDRUN:
@@ -1915,12 +1927,19 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
                         * scsi status is good but transport level
                         * underrun.
                         */
-                       sc_cmd->result = (fsp->state & FC_SRB_RCV_STATUS ?
-                                         DID_OK : DID_ERROR) << 16;
+                       if (fsp->state & FC_SRB_RCV_STATUS) {
+                               sc_cmd->result = DID_OK << 16;
+                       } else {
+                               FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml"
+                                          " due to FC_DATA_UNDRUN (trans)\n");
+                               sc_cmd->result = DID_ERROR << 16;
+                       }
                } else {
                        /*
                         * scsi got underrun, this is an error
                         */
+                       FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+                                  "due to FC_DATA_UNDRUN (scsi)\n");
                        CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid;
                        sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
                }
@@ -1929,12 +1948,16 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
                /*
                 * overrun is an error
                 */
+               FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+                          "due to FC_DATA_OVRRUN\n");
                sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
                break;
        case FC_CMD_ABORTED:
+               FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+                          "due to FC_CMD_ABORTED\n");
                sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
                break;
-       case FC_CMD_TIME_OUT:
+       case FC_CMD_RECOVERY:
                sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
                break;
        case FC_CMD_RESET:
@@ -1944,6 +1967,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
                sc_cmd->result = (DID_NO_CONNECT << 16);
                break;
        default:
+               FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+                          "due to unknown error\n");
                sc_cmd->result = (DID_ERROR << 16);
                break;
        }
@@ -2028,7 +2053,7 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
        if (lport->state != LPORT_ST_READY)
                return rc;
 
-       FC_SCSI_DBG(lport, "Resetting rport (%6x)\n", rport->port_id);
+       FC_SCSI_DBG(lport, "Resetting rport (%6.6x)\n", rport->port_id);
 
        fsp = fc_fcp_pkt_alloc(lport, GFP_NOIO);
        if (fsp == NULL) {
@@ -2076,12 +2101,12 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
 
        if (fc_fcp_lport_queue_ready(lport)) {
                shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded "
-                            "on port (%6x)\n", fc_host_port_id(lport->host));
+                            "on port (%6.6x)\n", lport->port_id);
                return SUCCESS;
        } else {
                shost_printk(KERN_INFO, shost, "libfc: Host reset failed, "
-                            "port (%6x) is not ready.\n",
-                            fc_host_port_id(lport->host));
+                            "port (%6.6x) is not ready.\n",
+                            lport->port_id);
                return FAILED;
        }
 }
@@ -2166,7 +2191,7 @@ void fc_fcp_destroy(struct fc_lport *lport)
 
        if (!list_empty(&si->scsi_pkt_queue))
                printk(KERN_ERR "libfc: Leaked SCSI packets when destroying "
-                      "port (%6x)\n", fc_host_port_id(lport->host));
+                      "port (%6.6x)\n", lport->port_id);
 
        mempool_destroy(si->scsi_pkt_pool);
        kfree(si);
index 741fd5c..f5c0ca4 100644 (file)
@@ -45,9 +45,9 @@ extern unsigned int fc_debug_logging;
 
 #define FC_LPORT_DBG(lport, fmt, args...)                              \
        FC_CHECK_LOGGING(FC_LPORT_LOGGING,                              \
-                        printk(KERN_INFO "host%u: lport %6x: " fmt,    \
+                        printk(KERN_INFO "host%u: lport %6.6x: " fmt,  \
                                (lport)->host->host_no,                 \
-                               fc_host_port_id((lport)->host), ##args))
+                               (lport)->port_id, ##args))
 
 #define FC_DISC_DBG(disc, fmt, args...)                                \
        FC_CHECK_LOGGING(FC_DISC_LOGGING,                       \
@@ -57,7 +57,7 @@ extern unsigned int fc_debug_logging;
 
 #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...)                  \
        FC_CHECK_LOGGING(FC_RPORT_LOGGING,                              \
-                        printk(KERN_INFO "host%u: rport %6x: " fmt,    \
+                        printk(KERN_INFO "host%u: rport %6.6x: " fmt,  \
                                (lport)->host->host_no,                 \
                                (port_id), ##args))
 
@@ -66,7 +66,7 @@ extern unsigned int fc_debug_logging;
 
 #define FC_FCP_DBG(pkt, fmt, args...)                                  \
        FC_CHECK_LOGGING(FC_FCP_LOGGING,                                \
-                        printk(KERN_INFO "host%u: fcp: %6x: " fmt,     \
+                        printk(KERN_INFO "host%u: fcp: %6.6x: " fmt,   \
                                (pkt)->lp->host->host_no,               \
                                pkt->rport->port_id, ##args))
 
index d126ecf..79c9e3c 100644 (file)
@@ -172,7 +172,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
                                    struct fc_rport_priv *rdata,
                                    enum fc_rport_event event)
 {
-       FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event,
+       FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event,
                     rdata->ids.port_id);
 
        mutex_lock(&lport->lp_mutex);
@@ -183,7 +183,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
                        fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
                } else {
                        FC_LPORT_DBG(lport, "Received an READY event "
-                                    "on port (%6x) for the directory "
+                                    "on port (%6.6x) for the directory "
                                     "server, but the lport is not "
                                     "in the DNS state, it's in the "
                                     "%d state", rdata->ids.port_id,
@@ -228,9 +228,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
                               u64 remote_wwnn)
 {
        mutex_lock(&lport->disc.disc_mutex);
-       if (lport->ptp_rdata)
+       if (lport->ptp_rdata) {
                lport->tt.rport_logoff(lport->ptp_rdata);
+               kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
+       }
        lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid);
+       kref_get(&lport->ptp_rdata->kref);
        lport->ptp_rdata->ids.port_name = remote_wwpn;
        lport->ptp_rdata->ids.node_name = remote_wwnn;
        mutex_unlock(&lport->disc.disc_mutex);
@@ -241,17 +244,6 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
 }
 
 /**
- * fc_get_host_port_type() - Return the port type of the given Scsi_Host
- * @shost: The SCSI host whose port type is to be determined
- */
-void fc_get_host_port_type(struct Scsi_Host *shost)
-{
-       /* TODO - currently just NPORT */
-       fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
-}
-EXPORT_SYMBOL(fc_get_host_port_type);
-
-/**
  * fc_get_host_port_state() - Return the port state of the given Scsi_Host
  * @shost:  The SCSI host whose port state is to be determined
  */
@@ -572,8 +564,8 @@ void __fc_linkup(struct fc_lport *lport)
  */
 void fc_linkup(struct fc_lport *lport)
 {
-       printk(KERN_INFO "host%d: libfc: Link up on port (%6x)\n",
-              lport->host->host_no, fc_host_port_id(lport->host));
+       printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n",
+              lport->host->host_no, lport->port_id);
 
        mutex_lock(&lport->lp_mutex);
        __fc_linkup(lport);
@@ -602,8 +594,8 @@ void __fc_linkdown(struct fc_lport *lport)
  */
 void fc_linkdown(struct fc_lport *lport)
 {
-       printk(KERN_INFO "host%d: libfc: Link down on port (%6x)\n",
-              lport->host->host_no, fc_host_port_id(lport->host));
+       printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n",
+              lport->host->host_no, lport->port_id);
 
        mutex_lock(&lport->lp_mutex);
        __fc_linkdown(lport);
@@ -704,8 +696,8 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
                break;
        case DISC_EV_FAILED:
                printk(KERN_ERR "host%d: libfc: "
-                      "Discovery failed for port (%6x)\n",
-                      lport->host->host_no, fc_host_port_id(lport->host));
+                      "Discovery failed for port (%6.6x)\n",
+                      lport->host->host_no, lport->port_id);
                mutex_lock(&lport->lp_mutex);
                fc_lport_enter_reset(lport);
                mutex_unlock(&lport->lp_mutex);
@@ -750,10 +742,14 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
                                 struct fc_frame *fp)
 {
        if (port_id)
-               printk(KERN_INFO "host%d: Assigned Port ID %6x\n",
+               printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n",
                       lport->host->host_no, port_id);
 
+       lport->port_id = port_id;
+
+       /* Update the fc_host */
        fc_host_port_id(lport->host) = port_id;
+
        if (lport->tt.lport_set_port_id)
                lport->tt.lport_set_port_id(lport, port_id, fp);
 }
@@ -797,11 +793,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
        remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);
        if (remote_wwpn == lport->wwpn) {
                printk(KERN_WARNING "host%d: libfc: Received FLOGI from port "
-                      "with same WWPN %llx\n",
+                      "with same WWPN %16.16llx\n",
                       lport->host->host_no, remote_wwpn);
                goto out;
        }
-       FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn);
+       FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn);
 
        /*
         * XXX what is the right thing to do for FIDs?
@@ -832,7 +828,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
                 */
                f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
                ep = fc_seq_exch(sp);
-               fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
+               fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,
                               FC_TYPE_ELS, f_ctl, 0);
                lport->tt.seq_send(lport, sp, fp);
 
@@ -947,14 +943,18 @@ static void fc_lport_reset_locked(struct fc_lport *lport)
        if (lport->dns_rdata)
                lport->tt.rport_logoff(lport->dns_rdata);
 
-       lport->ptp_rdata = NULL;
+       if (lport->ptp_rdata) {
+               lport->tt.rport_logoff(lport->ptp_rdata);
+               kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
+               lport->ptp_rdata = NULL;
+       }
 
        lport->tt.disc_stop(lport);
 
        lport->tt.exch_mgr_reset(lport, 0, 0);
        fc_host_fabric_name(lport->host) = 0;
 
-       if (fc_host_port_id(lport->host))
+       if (lport->port_id)
                fc_lport_set_port_id(lport, 0, NULL);
 }
 
@@ -1492,7 +1492,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
                                lport->r_a_tov = 2 * e_d_tov;
                                fc_lport_set_port_id(lport, did, fp);
                                printk(KERN_INFO "host%d: libfc: "
-                                      "Port (%6x) entered "
+                                      "Port (%6.6x) entered "
                                       "point-to-point mode\n",
                                       lport->host->host_no, did);
                                fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
@@ -1699,7 +1699,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
        fh = fc_frame_header_get(fp);
        fh->fh_r_ctl = FC_RCTL_ELS_REQ;
        hton24(fh->fh_d_id, did);
-       hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+       hton24(fh->fh_s_id, lport->port_id);
        fh->fh_type = FC_TYPE_ELS;
        hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
               FC_FC_END_SEQ | FC_FC_SEQ_INIT);
@@ -1759,7 +1759,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,
        fh = fc_frame_header_get(fp);
        fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL;
        hton24(fh->fh_d_id, did);
-       hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+       hton24(fh->fh_s_id, lport->port_id);
        fh->fh_type = FC_TYPE_CT;
        hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
               FC_FC_END_SEQ | FC_FC_SEQ_INIT);
index c68f6c7..dd2b43b 100644 (file)
@@ -69,12 +69,15 @@ struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id)
        struct fc_lport *lport = NULL;
        struct fc_lport *vn_port;
 
-       if (fc_host_port_id(n_port->host) == port_id)
+       if (n_port->port_id == port_id)
                return n_port;
 
+       if (port_id == FC_FID_FLOGI)
+               return n_port;          /* for point-to-point */
+
        mutex_lock(&n_port->lp_mutex);
        list_for_each_entry(vn_port, &n_port->vports, list) {
-               if (fc_host_port_id(vn_port->host) == port_id) {
+               if (vn_port->port_id == port_id) {
                        lport = vn_port;
                        break;
                }
index b37d0ff..39e440f 100644 (file)
@@ -1442,136 +1442,115 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
        struct fc_els_spp *spp; /* response spp */
        unsigned int len;
        unsigned int plen;
-       enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
-       enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
        enum fc_els_spp_resp resp;
        struct fc_seq_els_data rjt_data;
        u32 f_ctl;
        u32 fcp_parm;
        u32 roles = FC_RPORT_ROLE_UNKNOWN;
-       rjt_data.fp = NULL;
 
+       rjt_data.fp = NULL;
        fh = fc_frame_header_get(rx_fp);
 
        FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
                     fc_rport_state(rdata));
 
-       switch (rdata->rp_state) {
-       case RPORT_ST_PRLI:
-       case RPORT_ST_RTV:
-       case RPORT_ST_READY:
-       case RPORT_ST_ADISC:
-               reason = ELS_RJT_NONE;
-               break;
-       default:
-               fc_frame_free(rx_fp);
-               return;
-               break;
-       }
        len = fr_len(rx_fp) - sizeof(*fh);
        pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
-       if (pp == NULL) {
-               reason = ELS_RJT_PROT;
-               explan = ELS_EXPL_INV_LEN;
-       } else {
-               plen = ntohs(pp->prli.prli_len);
-               if ((plen % 4) != 0 || plen > len) {
-                       reason = ELS_RJT_PROT;
-                       explan = ELS_EXPL_INV_LEN;
-               } else if (plen < len) {
-                       len = plen;
-               }
-               plen = pp->prli.prli_spp_len;
-               if ((plen % 4) != 0 || plen < sizeof(*spp) ||
-                   plen > len || len < sizeof(*pp)) {
-                       reason = ELS_RJT_PROT;
-                       explan = ELS_EXPL_INV_LEN;
-               }
-               rspp = &pp->spp;
+       if (!pp)
+               goto reject_len;
+       plen = ntohs(pp->prli.prli_len);
+       if ((plen % 4) != 0 || plen > len || plen < 16)
+               goto reject_len;
+       if (plen < len)
+               len = plen;
+       plen = pp->prli.prli_spp_len;
+       if ((plen % 4) != 0 || plen < sizeof(*spp) ||
+           plen > len || len < sizeof(*pp) || plen < 12)
+               goto reject_len;
+       rspp = &pp->spp;
+
+       fp = fc_frame_alloc(lport, len);
+       if (!fp) {
+               rjt_data.reason = ELS_RJT_UNAB;
+               rjt_data.explan = ELS_EXPL_INSUF_RES;
+               goto reject;
        }
-       if (reason != ELS_RJT_NONE ||
-           (fp = fc_frame_alloc(lport, len)) == NULL) {
-               rjt_data.reason = reason;
-               rjt_data.explan = explan;
-               lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
-       } else {
-               sp = lport->tt.seq_start_next(sp);
-               WARN_ON(!sp);
-               pp = fc_frame_payload_get(fp, len);
-               WARN_ON(!pp);
-               memset(pp, 0, len);
-               pp->prli.prli_cmd = ELS_LS_ACC;
-               pp->prli.prli_spp_len = plen;
-               pp->prli.prli_len = htons(len);
-               len -= sizeof(struct fc_els_prli);
-
-               /* reinitialize remote port roles */
-               rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
-
-               /*
-                * Go through all the service parameter pages and build
-                * response.  If plen indicates longer SPP than standard,
-                * use that.  The entire response has been pre-cleared above.
-                */
-               spp = &pp->spp;
-               while (len >= plen) {
-                       spp->spp_type = rspp->spp_type;
-                       spp->spp_type_ext = rspp->spp_type_ext;
-                       spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
-                       resp = FC_SPP_RESP_ACK;
-                       if (rspp->spp_flags & FC_SPP_RPA_VAL)
-                               resp = FC_SPP_RESP_NO_PA;
-                       switch (rspp->spp_type) {
-                       case 0: /* common to all FC-4 types */
-                               break;
-                       case FC_TYPE_FCP:
-                               fcp_parm = ntohl(rspp->spp_params);
-                               if (fcp_parm & FCP_SPPF_RETRY)
-                                       rdata->flags |= FC_RP_FLAGS_RETRY;
-                               rdata->supported_classes = FC_COS_CLASS3;
-                               if (fcp_parm & FCP_SPPF_INIT_FCN)
-                                       roles |= FC_RPORT_ROLE_FCP_INITIATOR;
-                               if (fcp_parm & FCP_SPPF_TARG_FCN)
-                                       roles |= FC_RPORT_ROLE_FCP_TARGET;
-                               rdata->ids.roles = roles;
-
-                               spp->spp_params =
-                                       htonl(lport->service_params);
-                               break;
-                       default:
-                               resp = FC_SPP_RESP_INVL;
-                               break;
-                       }
-                       spp->spp_flags |= resp;
-                       len -= plen;
-                       rspp = (struct fc_els_spp *)((char *)rspp + plen);
-                       spp = (struct fc_els_spp *)((char *)spp + plen);
-               }
+       sp = lport->tt.seq_start_next(sp);
+       WARN_ON(!sp);
+       pp = fc_frame_payload_get(fp, len);
+       WARN_ON(!pp);
+       memset(pp, 0, len);
+       pp->prli.prli_cmd = ELS_LS_ACC;
+       pp->prli.prli_spp_len = plen;
+       pp->prli.prli_len = htons(len);
+       len -= sizeof(struct fc_els_prli);
 
-               /*
-                * Send LS_ACC.  If this fails, the originator should retry.
-                */
-               f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
-               f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
-               ep = fc_seq_exch(sp);
-               fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-                              FC_TYPE_ELS, f_ctl, 0);
-               lport->tt.seq_send(lport, sp, fp);
+       /* reinitialize remote port roles */
+       rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
 
-               /*
-                * Get lock and re-check state.
-                */
-               switch (rdata->rp_state) {
-               case RPORT_ST_PRLI:
-                       fc_rport_enter_ready(rdata);
+       /*
+        * Go through all the service parameter pages and build
+        * response.  If plen indicates longer SPP than standard,
+        * use that.  The entire response has been pre-cleared above.
+        */
+       spp = &pp->spp;
+       while (len >= plen) {
+               spp->spp_type = rspp->spp_type;
+               spp->spp_type_ext = rspp->spp_type_ext;
+               spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
+               resp = FC_SPP_RESP_ACK;
+
+               switch (rspp->spp_type) {
+               case 0: /* common to all FC-4 types */
                        break;
-               case RPORT_ST_READY:
-               case RPORT_ST_ADISC:
+               case FC_TYPE_FCP:
+                       fcp_parm = ntohl(rspp->spp_params);
+                       if (fcp_parm & FCP_SPPF_RETRY)
+                               rdata->flags |= FC_RP_FLAGS_RETRY;
+                       rdata->supported_classes = FC_COS_CLASS3;
+                       if (fcp_parm & FCP_SPPF_INIT_FCN)
+                               roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+                       if (fcp_parm & FCP_SPPF_TARG_FCN)
+                               roles |= FC_RPORT_ROLE_FCP_TARGET;
+                       rdata->ids.roles = roles;
+
+                       spp->spp_params = htonl(lport->service_params);
                        break;
                default:
+                       resp = FC_SPP_RESP_INVL;
                        break;
                }
+               spp->spp_flags |= resp;
+               len -= plen;
+               rspp = (struct fc_els_spp *)((char *)rspp + plen);
+               spp = (struct fc_els_spp *)((char *)spp + plen);
+       }
+
+       /*
+        * Send LS_ACC.  If this fails, the originator should retry.
+        */
+       f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
+       f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
+       ep = fc_seq_exch(sp);
+       fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
+                      FC_TYPE_ELS, f_ctl, 0);
+       lport->tt.seq_send(lport, sp, fp);
+
+       switch (rdata->rp_state) {
+       case RPORT_ST_PRLI:
+               fc_rport_enter_ready(rdata);
+               break;
+       default:
+               break;
        }
+       goto drop;
+
+reject_len:
+       rjt_data.reason = ELS_RJT_PROT;
+       rjt_data.explan = ELS_EXPL_INV_LEN;
+reject:
+       lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+drop:
        fc_frame_free(rx_fp);
 }
 
index 5c92620..8eeb39f 100644 (file)
@@ -421,7 +421,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
        struct iscsi_conn *conn = tcp_conn->iscsi_conn;
        struct hash_desc *rx_hash = NULL;
 
-       if (conn->datadgst_en &
+       if (conn->datadgst_en &&
            !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
                rx_hash = tcp_conn->rx_hash;
 
index 88f7446..8c496b5 100644 (file)
@@ -395,12 +395,13 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev,
 void sas_ata_task_abort(struct sas_task *task)
 {
        struct ata_queued_cmd *qc = task->uldd_task;
-       struct request_queue *q = qc->scsicmd->device->request_queue;
        struct completion *waiting;
-       unsigned long flags;
 
        /* Bounce SCSI-initiated commands to the SCSI EH */
        if (qc->scsicmd) {
+               struct request_queue *q = qc->scsicmd->device->request_queue;
+               unsigned long flags;
+
                spin_lock_irqsave(q->queue_lock, flags);
                blk_abort_request(qc->scsicmd->request);
                spin_unlock_irqrestore(q->queue_lock, flags);
index b71b6d4..a7890c6 100644 (file)
@@ -1030,8 +1030,6 @@ int __sas_task_abort(struct sas_task *task)
 void sas_task_abort(struct sas_task *task)
 {
        struct scsi_cmnd *sc = task->uldd_task;
-       struct request_queue *q = sc->device->request_queue;
-       unsigned long flags;
 
        /* Escape for libsas internal commands */
        if (!sc) {
@@ -1043,13 +1041,15 @@ void sas_task_abort(struct sas_task *task)
 
        if (dev_is_sata(task->dev)) {
                sas_ata_task_abort(task);
-               return;
-       }
+       } else {
+               struct request_queue *q = sc->device->request_queue;
+               unsigned long flags;
 
-       spin_lock_irqsave(q->queue_lock, flags);
-       blk_abort_request(sc->request);
-       spin_unlock_irqrestore(q->queue_lock, flags);
-       scsi_schedule_eh(sc->device->host);
+               spin_lock_irqsave(q->queue_lock, flags);
+               blk_abort_request(sc->request);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+               scsi_schedule_eh(sc->device->host);
+       }
 }
 
 int sas_slave_alloc(struct scsi_device *scsi_dev)
index 565e16d..e35a4c7 100644 (file)
@@ -310,7 +310,9 @@ struct lpfc_vport {
 #define FC_NLP_MORE             0x40    /* More node to process in node tbl */
 #define FC_OFFLINE_MODE         0x80    /* Interface is offline for diag */
 #define FC_FABRIC               0x100   /* We are fabric attached */
+#define FC_VPORT_LOGO_RCVD      0x200    /* LOGO received on vport */
 #define FC_RSCN_DISCOVERY       0x400   /* Auth all devices after RSCN */
+#define FC_LOGO_RCVD_DID_CHNG   0x800    /* FDISC on phys port detect DID chng*/
 #define FC_SCSI_SCAN_TMO        0x4000  /* scsi scan timer running */
 #define FC_ABORT_DISCOVERY      0x8000  /* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000         /* NPort discovery active */
@@ -554,6 +556,7 @@ struct lpfc_hba {
        struct lpfc_dmabuf slim2p;
 
        MAILBOX_t *mbox;
+       uint32_t *mbox_ext;
        uint32_t *inb_ha_copy;
        uint32_t *inb_counter;
        uint32_t inb_last_counter;
@@ -622,6 +625,7 @@ struct lpfc_hba {
        uint32_t cfg_enable_hba_reset;
        uint32_t cfg_enable_hba_heartbeat;
        uint32_t cfg_enable_bg;
+       uint32_t cfg_hostmem_hgp;
        uint32_t cfg_log_verbose;
        uint32_t cfg_aer_support;
        uint32_t cfg_suppress_link_up;
index 1849e33..2e5f376 100644 (file)
@@ -869,6 +869,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
        LPFC_MBOXQ_t *pmboxq;
        MAILBOX_t *pmb;
        int rc = 0;
+       uint32_t max_vpi;
 
        /*
         * prevent udev from issuing mailbox commands until the port is
@@ -916,11 +917,17 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
                if (axri)
                        *axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) -
                                        phba->sli4_hba.max_cfg_param.xri_used;
+
+               /* Account for differences with SLI-3.  Get vpi count from
+                * mailbox data and subtract one for max vpi value.
+                */
+               max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ?
+                       (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0;
+
                if (mvpi)
-                       *mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
+                       *mvpi = max_vpi;
                if (avpi)
-                       *avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) -
-                                       phba->sli4_hba.max_cfg_param.vpi_used;
+                       *avpi = max_vpi - phba->sli4_hba.max_cfg_param.vpi_used;
        } else {
                if (mrpi)
                        *mrpi = pmb->un.varRdConfig.max_rpi;
@@ -1925,13 +1932,12 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
                 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
                 " 3 - select SLI-3");
 
-int lpfc_enable_npiv = 0;
+int lpfc_enable_npiv = 1;
 module_param(lpfc_enable_npiv, int, 0);
 MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
 lpfc_param_show(enable_npiv);
-lpfc_param_init(enable_npiv, 0, 0, 1);
-static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
-                        lpfc_enable_npiv_show, NULL);
+lpfc_param_init(enable_npiv, 1, 0, 1);
+static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
 
 /*
 # lpfc_suppress_link_up:  Bring link up at initialization
index d62b3e4..dcf0882 100644 (file)
@@ -79,6 +79,12 @@ struct lpfc_bsg_iocb {
 struct lpfc_bsg_mbox {
        LPFC_MBOXQ_t *pmboxq;
        MAILBOX_t *mb;
+       struct lpfc_dmabuf *rxbmp; /* for BIU diags */
+       struct lpfc_dmabufext *dmp; /* for BIU diags */
+       uint8_t *ext; /* extended mailbox data */
+       uint32_t mbOffset; /* from app */
+       uint32_t inExtWLen; /* from app */
+       uint32_t outExtWLen; /* from app */
 
        /* job waiting for this mbox command to finish */
        struct fc_bsg_job *set_job;
@@ -1708,21 +1714,26 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
        dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
        if (dmabuf) {
                dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys);
-               INIT_LIST_HEAD(&dmabuf->list);
-               bpl = (struct ulp_bde64 *) dmabuf->virt;
-               memset(bpl, 0, sizeof(*bpl));
-               ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
-               bpl->addrHigh =
-                       le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl)));
-               bpl->addrLow =
-                       le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl)));
-               bpl->tus.f.bdeFlags = 0;
-               bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
-               bpl->tus.w = le32_to_cpu(bpl->tus.w);
+               if (dmabuf->virt) {
+                       INIT_LIST_HEAD(&dmabuf->list);
+                       bpl = (struct ulp_bde64 *) dmabuf->virt;
+                       memset(bpl, 0, sizeof(*bpl));
+                       ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
+                       bpl->addrHigh =
+                               le32_to_cpu(putPaddrHigh(dmabuf->phys +
+                                       sizeof(*bpl)));
+                       bpl->addrLow =
+                               le32_to_cpu(putPaddrLow(dmabuf->phys +
+                                       sizeof(*bpl)));
+                       bpl->tus.f.bdeFlags = 0;
+                       bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
+                       bpl->tus.w = le32_to_cpu(bpl->tus.w);
+               }
        }
 
        if (cmdiocbq == NULL || rspiocbq == NULL ||
-           dmabuf == NULL || bpl == NULL || ctreq == NULL) {
+           dmabuf == NULL || bpl == NULL || ctreq == NULL ||
+               dmabuf->virt == NULL) {
                ret_val = ENOMEM;
                goto err_get_xri_exit;
        }
@@ -1918,9 +1929,11 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
        rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
        if (rxbmp != NULL) {
                rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-               INIT_LIST_HEAD(&rxbmp->list);
-               rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-               rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
+               if (rxbmp->virt) {
+                       INIT_LIST_HEAD(&rxbmp->list);
+                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+                       rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
+               }
        }
 
        if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) {
@@ -2174,14 +2187,16 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
 
        if (txbmp) {
                txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys);
-               INIT_LIST_HEAD(&txbmp->list);
-               txbpl = (struct ulp_bde64 *) txbmp->virt;
-               if (txbpl)
+               if (txbmp->virt) {
+                       INIT_LIST_HEAD(&txbmp->list);
+                       txbpl = (struct ulp_bde64 *) txbmp->virt;
                        txbuffer = diag_cmd_data_alloc(phba,
                                                        txbpl, full_size, 0);
+               }
        }
 
-       if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) {
+       if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer ||
+               !txbmp->virt) {
                rc = -ENOMEM;
                goto err_loopback_test_exit;
        }
@@ -2377,35 +2392,90 @@ void
 lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
        struct bsg_job_data *dd_data;
-       MAILBOX_t *pmb;
-       MAILBOX_t *mb;
        struct fc_bsg_job *job;
        uint32_t size;
        unsigned long flags;
+       uint8_t *to;
+       uint8_t *from;
 
        spin_lock_irqsave(&phba->ct_ev_lock, flags);
        dd_data = pmboxq->context1;
+       /* job already timed out? */
        if (!dd_data) {
                spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
                return;
        }
 
-       pmb = &dd_data->context_un.mbox.pmboxq->u.mb;
-       mb = dd_data->context_un.mbox.mb;
+       /* build the outgoing buffer to do an sg copy
+        * the format is the response mailbox followed by any extended
+        * mailbox data
+        */
+       from = (uint8_t *)&pmboxq->u.mb;
+       to = (uint8_t *)dd_data->context_un.mbox.mb;
+       memcpy(to, from, sizeof(MAILBOX_t));
+       if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) {
+               /* copy the extended data if any, count is in words */
+               if (dd_data->context_un.mbox.outExtWLen) {
+                       from = (uint8_t *)dd_data->context_un.mbox.ext;
+                       to += sizeof(MAILBOX_t);
+                       size = dd_data->context_un.mbox.outExtWLen *
+                                       sizeof(uint32_t);
+                       memcpy(to, from, size);
+               } else if (pmboxq->u.mb.mbxCommand == MBX_RUN_BIU_DIAG64) {
+                       from = (uint8_t *)dd_data->context_un.mbox.
+                                               dmp->dma.virt;
+                       to += sizeof(MAILBOX_t);
+                       size = dd_data->context_un.mbox.dmp->size;
+                       memcpy(to, from, size);
+               } else if ((phba->sli_rev == LPFC_SLI_REV4) &&
+                       (pmboxq->u.mb.mbxCommand == MBX_DUMP_MEMORY)) {
+                       from = (uint8_t *)dd_data->context_un.mbox.dmp->dma.
+                                               virt;
+                       to += sizeof(MAILBOX_t);
+                       size = pmboxq->u.mb.un.varWords[5];
+                       memcpy(to, from, size);
+               } else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) {
+                       from = (uint8_t *)dd_data->context_un.
+                                               mbox.dmp->dma.virt;
+                       to += sizeof(MAILBOX_t);
+                       size = dd_data->context_un.mbox.dmp->size;
+                       memcpy(to, from, size);
+               }
+       }
+
+       from = (uint8_t *)dd_data->context_un.mbox.mb;
        job = dd_data->context_un.mbox.set_job;
-       memcpy(mb, pmb, sizeof(*pmb));
-       size = job->request_payload.payload_len;
+       size = job->reply_payload.payload_len;
        job->reply->reply_payload_rcv_len =
                sg_copy_from_buffer(job->reply_payload.sg_list,
                                job->reply_payload.sg_cnt,
-                               mb, size);
+                               from, size);
        job->reply->result = 0;
+
        dd_data->context_un.mbox.set_job = NULL;
        job->dd_data = NULL;
        job->job_done(job);
+       /* need to hold the lock until we call job done to hold off
+        * the timeout handler returning to the midlayer while
+        * we are stillprocessing the job
+        */
        spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+       kfree(dd_data->context_un.mbox.mb);
        mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
-       kfree(mb);
+       kfree(dd_data->context_un.mbox.ext);
+       if (dd_data->context_un.mbox.dmp) {
+               dma_free_coherent(&phba->pcidev->dev,
+                       dd_data->context_un.mbox.dmp->size,
+                       dd_data->context_un.mbox.dmp->dma.virt,
+                       dd_data->context_un.mbox.dmp->dma.phys);
+               kfree(dd_data->context_un.mbox.dmp);
+       }
+       if (dd_data->context_un.mbox.rxbmp) {
+               lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt,
+                       dd_data->context_un.mbox.rxbmp->phys);
+               kfree(dd_data->context_un.mbox.rxbmp);
+       }
        kfree(dd_data);
        return;
 }
@@ -2464,10 +2534,12 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
        case MBX_SET_DEBUG:
        case MBX_WRITE_WWN:
        case MBX_SLI4_CONFIG:
+       case MBX_READ_EVENT_LOG:
        case MBX_READ_EVENT_LOG_STATUS:
        case MBX_WRITE_EVENT_LOG:
        case MBX_PORT_CAPABILITIES:
        case MBX_PORT_IOV_CONTROL:
+       case MBX_RUN_BIU_DIAG64:
                break;
        case MBX_SET_VARIABLE:
                lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -2482,8 +2554,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
                        phba->fc_topology = TOPOLOGY_PT_PT;
                }
                break;
-       case MBX_RUN_BIU_DIAG64:
-       case MBX_READ_EVENT_LOG:
        case MBX_READ_SPARM64:
        case MBX_READ_LA:
        case MBX_READ_LA64:
@@ -2518,97 +2588,365 @@ static uint32_t
 lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
        struct lpfc_vport *vport)
 {
-       LPFC_MBOXQ_t *pmboxq;
-       MAILBOX_t *pmb;
-       MAILBOX_t *mb;
-       struct bsg_job_data *dd_data;
+       LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */
+       MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */
+       /* a 4k buffer to hold the mb and extended data from/to the bsg */
+       MAILBOX_t *mb = NULL;
+       struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */
        uint32_t size;
+       struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */
+       struct lpfc_dmabufext *dmp = NULL; /* for biu diag */
+       struct ulp_bde64 *rxbpl = NULL;
+       struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *)
+               job->request->rqst_data.h_vendor.vendor_cmd;
+       uint8_t *ext = NULL;
        int rc = 0;
+       uint8_t *from;
+
+       /* in case no data is transferred */
+       job->reply->reply_payload_rcv_len = 0;
+
+       /* check if requested extended data lengths are valid */
+       if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) ||
+               (mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) {
+               rc = -ERANGE;
+               goto job_done;
+       }
 
        /* allocate our bsg tracking structure */
        dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
        if (!dd_data) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
                                "2727 Failed allocation of dd_data\n");
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto job_done;
        }
 
-       mb = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       mb = kzalloc(BSG_MBOX_SIZE, GFP_KERNEL);
        if (!mb) {
-               kfree(dd_data);
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto job_done;
        }
 
        pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!pmboxq) {
-               kfree(dd_data);
-               kfree(mb);
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto job_done;
        }
+       memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
 
        size = job->request_payload.payload_len;
-       job->reply->reply_payload_rcv_len =
-               sg_copy_to_buffer(job->request_payload.sg_list,
-                               job->request_payload.sg_cnt,
-                               mb, size);
+       sg_copy_to_buffer(job->request_payload.sg_list,
+                       job->request_payload.sg_cnt,
+                       mb, size);
 
        rc = lpfc_bsg_check_cmd_access(phba, mb, vport);
-       if (rc != 0) {
-               kfree(dd_data);
-               kfree(mb);
-               mempool_free(pmboxq, phba->mbox_mem_pool);
-               return rc; /* must be negative */
-       }
+       if (rc != 0)
+               goto job_done; /* must be negative */
 
-       memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
        pmb = &pmboxq->u.mb;
        memcpy(pmb, mb, sizeof(*pmb));
        pmb->mbxOwner = OWN_HOST;
-       pmboxq->context1 = NULL;
        pmboxq->vport = vport;
 
-       if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-           (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
-               rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
-               if (rc != MBX_SUCCESS) {
-                       if (rc != MBX_TIMEOUT) {
-                               kfree(dd_data);
-                               kfree(mb);
-                               mempool_free(pmboxq, phba->mbox_mem_pool);
+       /* If HBA encountered an error attention, allow only DUMP
+        * or RESTART mailbox commands until the HBA is restarted.
+        */
+       if (phba->pport->stopped &&
+           pmb->mbxCommand != MBX_DUMP_MEMORY &&
+           pmb->mbxCommand != MBX_RESTART &&
+           pmb->mbxCommand != MBX_WRITE_VPARMS &&
+           pmb->mbxCommand != MBX_WRITE_WWN)
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+                               "2797 mbox: Issued mailbox cmd "
+                               "0x%x while in stopped state.\n",
+                               pmb->mbxCommand);
+
+       /* Don't allow mailbox commands to be sent when blocked
+        * or when in the middle of discovery
+        */
+       if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
+               rc = -EAGAIN;
+               goto job_done;
+       }
+
+       /* extended mailbox commands will need an extended buffer */
+       if (mbox_req->inExtWLen || mbox_req->outExtWLen) {
+               ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL);
+               if (!ext) {
+                       rc = -ENOMEM;
+                       goto job_done;
+               }
+
+               /* any data for the device? */
+               if (mbox_req->inExtWLen) {
+                       from = (uint8_t *)mb;
+                       from += sizeof(MAILBOX_t);
+                       memcpy((uint8_t *)ext, from,
+                               mbox_req->inExtWLen * sizeof(uint32_t));
+               }
+
+               pmboxq->context2 = ext;
+               pmboxq->in_ext_byte_len =
+                       mbox_req->inExtWLen *
+                       sizeof(uint32_t);
+               pmboxq->out_ext_byte_len =
+                       mbox_req->outExtWLen *
+                       sizeof(uint32_t);
+               pmboxq->mbox_offset_word =
+                       mbox_req->mbOffset;
+               pmboxq->context2 = ext;
+               pmboxq->in_ext_byte_len =
+                       mbox_req->inExtWLen * sizeof(uint32_t);
+               pmboxq->out_ext_byte_len =
+                       mbox_req->outExtWLen * sizeof(uint32_t);
+               pmboxq->mbox_offset_word = mbox_req->mbOffset;
+       }
+
+       /* biu diag will need a kernel buffer to transfer the data
+        * allocate our own buffer and setup the mailbox command to
+        * use ours
+        */
+       if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) {
+               uint32_t transmit_length = pmb->un.varWords[1];
+               uint32_t receive_length = pmb->un.varWords[4];
+               /* transmit length cannot be greater than receive length or
+                * mailbox extension size
+                */
+               if ((transmit_length > receive_length) ||
+                       (transmit_length > MAILBOX_EXT_SIZE)) {
+                       rc = -ERANGE;
+                       goto job_done;
+               }
+
+               rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+               if (!rxbmp) {
+                       rc = -ENOMEM;
+                       goto job_done;
+               }
+
+               rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+               if (!rxbmp->virt) {
+                       rc = -ENOMEM;
+                       goto job_done;
+               }
+
+               INIT_LIST_HEAD(&rxbmp->list);
+               rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+               dmp = diag_cmd_data_alloc(phba, rxbpl, transmit_length, 0);
+               if (!dmp) {
+                       rc = -ENOMEM;
+                       goto job_done;
+               }
+
+               INIT_LIST_HEAD(&dmp->dma.list);
+               pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
+                       putPaddrHigh(dmp->dma.phys);
+               pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
+                       putPaddrLow(dmp->dma.phys);
+
+               pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
+                       putPaddrHigh(dmp->dma.phys +
+                               pmb->un.varBIUdiag.un.s2.
+                                       xmit_bde64.tus.f.bdeSize);
+               pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
+                       putPaddrLow(dmp->dma.phys +
+                               pmb->un.varBIUdiag.un.s2.
+                                       xmit_bde64.tus.f.bdeSize);
+
+               /* copy the transmit data found in the mailbox extension area */
+               from = (uint8_t *)mb;
+               from += sizeof(MAILBOX_t);
+               memcpy((uint8_t *)dmp->dma.virt, from, transmit_length);
+       } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) {
+               struct READ_EVENT_LOG_VAR *rdEventLog =
+                       &pmb->un.varRdEventLog ;
+               uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize;
+               uint32_t mode =  bf_get(lpfc_event_log, rdEventLog);
+
+               /* receive length cannot be greater than mailbox
+                * extension size
+                */
+               if (receive_length > MAILBOX_EXT_SIZE) {
+                       rc = -ERANGE;
+                       goto job_done;
+               }
+
+               /* mode zero uses a bde like biu diags command */
+               if (mode == 0) {
+
+                       /* rebuild the command for sli4 using our own buffers
+                       * like we do for biu diags
+                       */
+
+                       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+                       if (!rxbmp) {
+                               rc = -ENOMEM;
+                               goto job_done;
                        }
-                       return  (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
+
+                       rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+                       if (rxbpl) {
+                               INIT_LIST_HEAD(&rxbmp->list);
+                               dmp = diag_cmd_data_alloc(phba, rxbpl,
+                                       receive_length, 0);
+                       }
+
+                       if (!dmp) {
+                               rc = -ENOMEM;
+                               goto job_done;
+                       }
+
+                       INIT_LIST_HEAD(&dmp->dma.list);
+                       pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
+                       pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
                }
+       } else if (phba->sli_rev == LPFC_SLI_REV4) {
+               if (pmb->mbxCommand == MBX_DUMP_MEMORY) {
+                       /* rebuild the command for sli4 using our own buffers
+                       * like we do for biu diags
+                       */
+                       uint32_t receive_length = pmb->un.varWords[2];
+                       /* receive length cannot be greater than mailbox
+                        * extension size
+                        */
+                       if ((receive_length == 0) ||
+                               (receive_length > MAILBOX_EXT_SIZE)) {
+                               rc = -ERANGE;
+                               goto job_done;
+                       }
 
-               memcpy(mb, pmb, sizeof(*pmb));
-               job->reply->reply_payload_rcv_len =
-                       sg_copy_from_buffer(job->reply_payload.sg_list,
-                                       job->reply_payload.sg_cnt,
-                                       mb, size);
-               kfree(dd_data);
-               kfree(mb);
-               mempool_free(pmboxq, phba->mbox_mem_pool);
-               /* not waiting mbox already done */
-               return 0;
+                       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+                       if (!rxbmp) {
+                               rc = -ENOMEM;
+                               goto job_done;
+                       }
+
+                       rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+                       if (!rxbmp->virt) {
+                               rc = -ENOMEM;
+                               goto job_done;
+                       }
+
+                       INIT_LIST_HEAD(&rxbmp->list);
+                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+                       dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length,
+                                               0);
+                       if (!dmp) {
+                               rc = -ENOMEM;
+                               goto job_done;
+                       }
+
+                       INIT_LIST_HEAD(&dmp->dma.list);
+                       pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
+                       pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
+               } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) &&
+                       pmb->un.varUpdateCfg.co) {
+                       struct ulp_bde64 *bde =
+                               (struct ulp_bde64 *)&pmb->un.varWords[4];
+
+                       /* bde size cannot be greater than mailbox ext size */
+                       if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) {
+                               rc = -ERANGE;
+                               goto job_done;
+                       }
+
+                       rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+                       if (!rxbmp) {
+                               rc = -ENOMEM;
+                               goto job_done;
+                       }
+
+                       rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+                       if (!rxbmp->virt) {
+                               rc = -ENOMEM;
+                               goto job_done;
+                       }
+
+                       INIT_LIST_HEAD(&rxbmp->list);
+                       rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+                       dmp = diag_cmd_data_alloc(phba, rxbpl,
+                                       bde->tus.f.bdeSize, 0);
+                       if (!dmp) {
+                               rc = -ENOMEM;
+                               goto job_done;
+                       }
+
+                       INIT_LIST_HEAD(&dmp->dma.list);
+                       bde->addrHigh = putPaddrHigh(dmp->dma.phys);
+                       bde->addrLow = putPaddrLow(dmp->dma.phys);
+
+                       /* copy the transmit data found in the mailbox
+                        * extension area
+                        */
+                       from = (uint8_t *)mb;
+                       from += sizeof(MAILBOX_t);
+                       memcpy((uint8_t *)dmp->dma.virt, from,
+                               bde->tus.f.bdeSize);
+               }
        }
 
+       dd_data->context_un.mbox.rxbmp = rxbmp;
+       dd_data->context_un.mbox.dmp = dmp;
+
        /* setup wake call as IOCB callback */
        pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait;
+
        /* setup context field to pass wait_queue pointer to wake function */
        pmboxq->context1 = dd_data;
        dd_data->type = TYPE_MBOX;
        dd_data->context_un.mbox.pmboxq = pmboxq;
        dd_data->context_un.mbox.mb = mb;
        dd_data->context_un.mbox.set_job = job;
+       dd_data->context_un.mbox.ext = ext;
+       dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset;
+       dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen;
+       dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen;
        job->dd_data = dd_data;
+
+       if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+           (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
+               rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+               if (rc != MBX_SUCCESS) {
+                       rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
+                       goto job_done;
+               }
+
+               /* job finished, copy the data */
+               memcpy(mb, pmb, sizeof(*pmb));
+               job->reply->reply_payload_rcv_len =
+                       sg_copy_from_buffer(job->reply_payload.sg_list,
+                                       job->reply_payload.sg_cnt,
+                                       mb, size);
+               /* not waiting mbox already done */
+               rc = 0;
+               goto job_done;
+       }
+
        rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
-       if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
-               kfree(dd_data);
-               kfree(mb);
+       if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY))
+               return 1; /* job started */
+
+job_done:
+       /* common exit for error or job completed inline */
+       kfree(mb);
+       if (pmboxq)
                mempool_free(pmboxq, phba->mbox_mem_pool);
-               return -EIO;
+       kfree(ext);
+       if (dmp) {
+               dma_free_coherent(&phba->pcidev->dev,
+                       dmp->size, dmp->dma.virt,
+                               dmp->dma.phys);
+               kfree(dmp);
        }
+       if (rxbmp) {
+               lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
+               kfree(rxbmp);
+       }
+       kfree(dd_data);
 
-       return 1;
+       return rc;
 }
 
 /**
@@ -2633,7 +2971,12 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
                goto job_error;
        }
 
-       if (job->request_payload.payload_len != PAGE_SIZE) {
+       if (job->request_payload.payload_len != BSG_MBOX_SIZE) {
+               rc = -EINVAL;
+               goto job_error;
+       }
+
+       if (job->reply_payload.payload_len != BSG_MBOX_SIZE) {
                rc = -EINVAL;
                goto job_error;
        }
@@ -3094,6 +3437,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
                job->dd_data = NULL;
                job->reply->reply_payload_rcv_len = 0;
                job->reply->result = -EAGAIN;
+               /* the mbox completion handler can now be run */
                spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
                job->job_done(job);
                break;
index 5bc6308..a2c33e7 100644 (file)
@@ -91,11 +91,12 @@ struct get_mgmt_rev_reply {
        struct MgmtRevInfo info;
 };
 
+#define BSG_MBOX_SIZE 4096 /* mailbox command plus extended data */
 struct dfc_mbox_req {
        uint32_t command;
+       uint32_t mbOffset;
        uint32_t inExtWLen;
        uint32_t outExtWLen;
-       uint8_t mbOffset;
 };
 
 /* Used for menlo command or menlo data. The xri is only used for menlo data */
index 5087c42..fbc9bae 100644 (file)
@@ -65,6 +65,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
+void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
 
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
index 2851d75..36257a6 100644 (file)
@@ -38,6 +38,7 @@ enum lpfc_work_type {
        LPFC_EVT_ELS_RETRY,
        LPFC_EVT_DEV_LOSS,
        LPFC_EVT_FASTPATH_MGMT_EVT,
+       LPFC_EVT_RESET_HBA,
 };
 
 /* structure used to queue event to the discovery tasklet */
index 5fbdb22..c4c7f0a 100644 (file)
@@ -584,6 +584,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        spin_unlock_irq(shost->host_lock);
                        lpfc_unreg_rpi(vport, np);
                }
+               lpfc_cleanup_pending_mbox(vport);
                if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                        lpfc_mbx_unreg_vpi(vport);
                        spin_lock_irq(shost->host_lock);
@@ -864,6 +865,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        }
        spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+       vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
        spin_unlock_irq(shost->host_lock);
 
        /*
@@ -893,11 +895,14 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
                if (!rc) {
                        /* Mark the FCF discovery process done */
-                       lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | LOG_ELS,
-                                        "2769 FLOGI successful on FCF record: "
-                                        "current_fcf_index:x%x, terminate FCF "
-                                        "round robin failover process\n",
-                                        phba->fcf.current_rec.fcf_indx);
+                       if (phba->hba_flag & HBA_FIP_SUPPORT)
+                               lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP |
+                                               LOG_ELS,
+                                               "2769 FLOGI successful on FCF "
+                                               "record: current_fcf_index:"
+                                               "x%x, terminate FCF round "
+                                               "robin failover process\n",
+                                               phba->fcf.current_rec.fcf_indx);
                        spin_lock_irq(&phba->hbalock);
                        phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
                        spin_unlock_irq(&phba->hbalock);
@@ -5366,7 +5371,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba,
                        sizeof(struct lpfc_name));
                pcmd = (uint32_t *) (((struct lpfc_dmabuf *)
                        cmdiocbp->context2)->virt);
-               lsrjt_event.command = *pcmd;
+               lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0;
                stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]);
                lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode;
                lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp;
@@ -6050,7 +6055,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                        spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
                        spin_unlock_irq(shost->host_lock);
-                       if (vport->port_type == LPFC_PHYSICAL_PORT)
+                       if (vport->port_type == LPFC_PHYSICAL_PORT
+                               && !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
                                lpfc_initial_flogi(vport);
                        else
                                lpfc_initial_fdisc(vport);
@@ -6286,6 +6292,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        }
        spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+       vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
        vport->fc_flag |= FC_FABRIC;
        if (vport->phba->fc_topology == TOPOLOGY_LOOP)
                vport->fc_flag |=  FC_PUBLIC_LOOP;
@@ -6310,11 +6317,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        spin_unlock_irq(shost->host_lock);
                        lpfc_unreg_rpi(vport, np);
                }
+               lpfc_cleanup_pending_mbox(vport);
                lpfc_mbx_unreg_vpi(vport);
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
                if (phba->sli_rev == LPFC_SLI_REV4)
                        vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+               else
+                       vport->fc_flag |= FC_LOGO_RCVD_DID_CHNG;
                spin_unlock_irq(shost->host_lock);
        }
 
index e1466ee..1f87b4f 100644 (file)
@@ -475,6 +475,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)
                        lpfc_send_fastpath_evt(phba, evtp);
                        free_evt = 0;
                        break;
+               case LPFC_EVT_RESET_HBA:
+                       if (!(phba->pport->load_flag & FC_UNLOADING))
+                               lpfc_reset_hba(phba);
+                       break;
                }
                if (free_evt)
                        kfree(evtp);
@@ -1531,7 +1535,37 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
 }
 
 /**
- * lpfc_sli4_fcf_rec_mbox_parse - parse non-embedded fcf record mailbox command
+ * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_cnt: number of eligible fcf record seen so far.
+ *
+ * This function makes an running random selection decision on FCF record to
+ * use through a sequence of @fcf_cnt eligible FCF records with equal
+ * probability. To perform integer manunipulation of random numbers with
+ * size unit32_t, the lower 16 bits of the 32-bit random number returned
+ * from random32() are taken as the random random number generated.
+ *
+ * Returns true when outcome is for the newly read FCF record should be
+ * chosen; otherwise, return false when outcome is for keeping the previously
+ * chosen FCF record.
+ **/
+static bool
+lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
+{
+       uint32_t rand_num;
+
+       /* Get 16-bit uniform random number */
+       rand_num = (0xFFFF & random32());
+
+       /* Decision with probability 1/fcf_cnt */
+       if ((fcf_cnt * rand_num) < 0xFFFF)
+               return true;
+       else
+               return false;
+}
+
+/**
+ * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
  * @phba: pointer to lpfc hba data structure.
  * @mboxq: pointer to mailbox object.
  * @next_fcf_index: pointer to holder of next fcf index.
@@ -1592,7 +1626,9 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
        new_fcf_record = (struct fcf_record *)(virt_addr +
                          sizeof(struct lpfc_mbx_read_fcf_tbl));
        lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record,
-                             sizeof(struct fcf_record));
+                               offsetof(struct fcf_record, vlan_bitmap));
+       new_fcf_record->word137 = le32_to_cpu(new_fcf_record->word137);
+       new_fcf_record->word138 = le32_to_cpu(new_fcf_record->word138);
 
        return new_fcf_record;
 }
@@ -1679,6 +1715,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        uint16_t fcf_index, next_fcf_index;
        struct lpfc_fcf_rec *fcf_rec = NULL;
        uint16_t vlan_id;
+       uint32_t seed;
+       bool select_new_fcf;
        int rc;
 
        /* If there is pending FCoE event restart FCF table scan */
@@ -1809,9 +1847,21 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                 * than the driver FCF record, use the new record.
                 */
                if (new_fcf_record->fip_priority < fcf_rec->priority) {
-                       /* Choose this FCF record */
+                       /* Choose the new FCF record with lower priority */
                        __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
                                        addr_mode, vlan_id, 0);
+                       /* Reset running random FCF selection count */
+                       phba->fcf.eligible_fcf_cnt = 1;
+               } else if (new_fcf_record->fip_priority == fcf_rec->priority) {
+                       /* Update running random FCF selection count */
+                       phba->fcf.eligible_fcf_cnt++;
+                       select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
+                                               phba->fcf.eligible_fcf_cnt);
+                       if (select_new_fcf)
+                               /* Choose the new FCF by random selection */
+                               __lpfc_update_fcf_record(phba, fcf_rec,
+                                                        new_fcf_record,
+                                                        addr_mode, vlan_id, 0);
                }
                spin_unlock_irq(&phba->hbalock);
                goto read_next_fcf;
@@ -1825,6 +1875,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                                         addr_mode, vlan_id, (boot_flag ?
                                         BOOT_ENABLE : 0));
                phba->fcf.fcf_flag |= FCF_AVAILABLE;
+               /* Setup initial running random FCF selection count */
+               phba->fcf.eligible_fcf_cnt = 1;
+               /* Seeding the random number generator for random selection */
+               seed = (uint32_t)(0xFFFFFFFF & jiffies);
+               srandom32(seed);
        }
        spin_unlock_irq(&phba->hbalock);
        goto read_next_fcf;
@@ -2686,11 +2741,18 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        switch (mb->mbxStatus) {
        case 0x0011:
        case 0x0020:
-       case 0x9700:
                lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
                                 "0911 cmpl_unreg_vpi, mb status = 0x%x\n",
                                 mb->mbxStatus);
                break;
+       /* If VPI is busy, reset the HBA */
+       case 0x9700:
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
+                       "2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n",
+                       vport->vpi, mb->mbxStatus);
+               if (!(phba->pport->load_flag & FC_UNLOADING))
+                       lpfc_workq_post_event(phba, NULL, NULL,
+                               LPFC_EVT_RESET_HBA);
        }
        spin_lock_irq(shost->host_lock);
        vport->vpi_state &= ~LPFC_VPI_REGISTERED;
@@ -2965,7 +3027,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
        if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
-               lpfc_start_fdiscs(phba);
+               /* when physical port receive logo donot start
+                * vport discovery */
+               if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
+                       lpfc_start_fdiscs(phba);
+               else
+                       vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ;
                lpfc_do_scr_ns_plogi(phba, vport);
        }
 
@@ -3177,7 +3244,6 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
        if (new_state == NLP_STE_UNMAPPED_NODE) {
-               ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
                ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
                ndlp->nlp_type |= NLP_FC_NODE;
        }
@@ -4935,6 +5001,7 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
                        ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
                        if (ndlp)
                                lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
+                       lpfc_cleanup_pending_mbox(vports[i]);
                        lpfc_mbx_unreg_vpi(vports[i]);
                        shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(shost->host_lock);
index 89ff7c0..e654d01 100644 (file)
@@ -1565,95 +1565,83 @@ enum lpfc_protgrp_type {
 };
 
 /* PDE Descriptors */
-#define LPFC_PDE1_DESCRIPTOR           0x81
-#define LPFC_PDE2_DESCRIPTOR           0x82
-#define LPFC_PDE3_DESCRIPTOR           0x83
-
-/* BlockGuard Profiles */
-enum lpfc_bg_prof_codes {
-       LPFC_PROF_INVALID,
-       LPFC_PROF_A1    = 128,  /* Full Protection                            */
-       LPFC_PROF_A2,           /* Disabled Protection Checks:A2~A4           */
-       LPFC_PROF_A3,
-       LPFC_PROF_A4,
-       LPFC_PROF_B1,           /* Embedded DIFs: B1~B3                       */
-       LPFC_PROF_B2,
-       LPFC_PROF_B3,
-       LPFC_PROF_C1,           /* Separate DIFs: C1~C3                       */
-       LPFC_PROF_C2,
-       LPFC_PROF_C3,
-       LPFC_PROF_D1,           /* Full Protection                            */
-       LPFC_PROF_D2,           /* Partial Protection & Check Disabling       */
-       LPFC_PROF_D3,
-       LPFC_PROF_E1,           /* E1~E4:out - check-only, in - update apptag */
-       LPFC_PROF_E2,
-       LPFC_PROF_E3,
-       LPFC_PROF_E4,
-       LPFC_PROF_F1,           /* Full Translation - F1 Prot Descriptor      */
-                               /* F1 Translation BDE                         */
-       LPFC_PROF_ANT1,         /* TCP checksum, DIF inline with data buffers */
-       LPFC_PROF_AST1,         /* TCP checksum, DIF split from data buffer   */
-       LPFC_PROF_ANT2,
-       LPFC_PROF_AST2
+#define LPFC_PDE5_DESCRIPTOR           0x85
+#define LPFC_PDE6_DESCRIPTOR           0x86
+#define LPFC_PDE7_DESCRIPTOR           0x87
+
+/* BlockGuard Opcodes */
+#define BG_OP_IN_NODIF_OUT_CRC         0x0
+#define        BG_OP_IN_CRC_OUT_NODIF          0x1
+#define        BG_OP_IN_NODIF_OUT_CSUM         0x2
+#define        BG_OP_IN_CSUM_OUT_NODIF         0x3
+#define        BG_OP_IN_CRC_OUT_CRC            0x4
+#define        BG_OP_IN_CSUM_OUT_CSUM          0x5
+#define        BG_OP_IN_CRC_OUT_CSUM           0x6
+#define        BG_OP_IN_CSUM_OUT_CRC           0x7
+
+struct lpfc_pde5 {
+       uint32_t word0;
+#define pde5_type_SHIFT                24
+#define pde5_type_MASK         0x000000ff
+#define pde5_type_WORD         word0
+#define pde5_rsvd0_SHIFT       0
+#define pde5_rsvd0_MASK                0x00ffffff
+#define pde5_rsvd0_WORD                word0
+       uint32_t reftag;        /* Reference Tag Value                  */
+       uint32_t reftagtr;      /* Reference Tag Translation Value      */
 };
 
-/* BlockGuard error-control defines */
-#define BG_EC_STOP_ERR                 0x00
-#define BG_EC_CONT_ERR                 0x01
-#define BG_EC_IGN_UNINIT_STOP_ERR      0x10
-#define BG_EC_IGN_UNINIT_CONT_ERR      0x11
-
-/* PDE (Protection Descriptor Entry) word 0 bit masks and shifts */
-#define PDE_DESC_TYPE_MASK             0xff000000
-#define PDE_DESC_TYPE_SHIFT            24
-#define PDE_BG_PROFILE_MASK            0x00ff0000
-#define PDE_BG_PROFILE_SHIFT           16
-#define PDE_BLOCK_LEN_MASK             0x0000fffc
-#define PDE_BLOCK_LEN_SHIFT            2
-#define PDE_ERR_CTRL_MASK              0x00000003
-#define PDE_ERR_CTRL_SHIFT             0
-/* PDE word 1 bit masks and shifts */
-#define PDE_APPTAG_MASK_MASK           0xffff0000
-#define PDE_APPTAG_MASK_SHIFT          16
-#define PDE_APPTAG_VAL_MASK            0x0000ffff
-#define PDE_APPTAG_VAL_SHIFT           0
-struct lpfc_pde {
-       uint32_t parms;     /* bitfields of descriptor, prof, len, and ec */
-       uint32_t apptag;    /* bitfields of app tag maskand app tag value */
-       uint32_t reftag;    /* reference tag occupying all 32 bits        */
+struct lpfc_pde6 {
+       uint32_t word0;
+#define pde6_type_SHIFT                24
+#define pde6_type_MASK         0x000000ff
+#define pde6_type_WORD         word0
+#define pde6_rsvd0_SHIFT       0
+#define pde6_rsvd0_MASK                0x00ffffff
+#define pde6_rsvd0_WORD                word0
+       uint32_t word1;
+#define pde6_rsvd1_SHIFT       26
+#define pde6_rsvd1_MASK                0x0000003f
+#define pde6_rsvd1_WORD                word1
+#define pde6_na_SHIFT          25
+#define pde6_na_MASK           0x00000001
+#define pde6_na_WORD           word1
+#define pde6_rsvd2_SHIFT       16
+#define pde6_rsvd2_MASK                0x000001FF
+#define pde6_rsvd2_WORD                word1
+#define pde6_apptagtr_SHIFT    0
+#define pde6_apptagtr_MASK     0x0000ffff
+#define pde6_apptagtr_WORD     word1
+       uint32_t word2;
+#define pde6_optx_SHIFT                28
+#define pde6_optx_MASK         0x0000000f
+#define pde6_optx_WORD         word2
+#define pde6_oprx_SHIFT                24
+#define pde6_oprx_MASK         0x0000000f
+#define pde6_oprx_WORD         word2
+#define pde6_nr_SHIFT          23
+#define pde6_nr_MASK           0x00000001
+#define pde6_nr_WORD           word2
+#define pde6_ce_SHIFT          22
+#define pde6_ce_MASK           0x00000001
+#define pde6_ce_WORD           word2
+#define pde6_re_SHIFT          21
+#define pde6_re_MASK           0x00000001
+#define pde6_re_WORD           word2
+#define pde6_ae_SHIFT          20
+#define pde6_ae_MASK           0x00000001
+#define pde6_ae_WORD           word2
+#define pde6_ai_SHIFT          19
+#define pde6_ai_MASK           0x00000001
+#define pde6_ai_WORD           word2
+#define pde6_bs_SHIFT          16
+#define pde6_bs_MASK           0x00000007
+#define pde6_bs_WORD           word2
+#define pde6_apptagval_SHIFT   0
+#define pde6_apptagval_MASK    0x0000ffff
+#define pde6_apptagval_WORD    word2
 };
 
-/* inline function to set fields in parms of PDE */
-static inline void
-lpfc_pde_set_bg_parms(struct lpfc_pde *p, u8 desc, u8 prof, u16 len, u8 ec)
-{
-       uint32_t *wp = &p->parms;
-
-       /* spec indicates that adapter appends two 0's to length field */
-       len = len >> 2;
-
-       *wp &= 0;
-       *wp |= ((desc << PDE_DESC_TYPE_SHIFT) & PDE_DESC_TYPE_MASK);
-       *wp |= ((prof << PDE_BG_PROFILE_SHIFT) & PDE_BG_PROFILE_MASK);
-       *wp |= ((len << PDE_BLOCK_LEN_SHIFT) & PDE_BLOCK_LEN_MASK);
-       *wp |= ((ec << PDE_ERR_CTRL_SHIFT) & PDE_ERR_CTRL_MASK);
-       *wp = le32_to_cpu(*wp);
-}
-
-/* inline function to set apptag and reftag fields of PDE */
-static inline void
-lpfc_pde_set_dif_parms(struct lpfc_pde *p, u16 apptagmask, u16 apptagval,
-               u32 reftag)
-{
-       uint32_t *wp = &p->apptag;
-       *wp &= 0;
-       *wp |= ((apptagmask << PDE_APPTAG_MASK_SHIFT) & PDE_APPTAG_MASK_MASK);
-       *wp |= ((apptagval << PDE_APPTAG_VAL_SHIFT) & PDE_APPTAG_VAL_MASK);
-       *wp = le32_to_cpu(*wp);
-       wp = &p->reftag;
-       *wp = le32_to_cpu(reftag);
-}
-
 
 /* Structure for MB Command LOAD_SM and DOWN_LOAD */
 
@@ -1744,6 +1732,17 @@ typedef struct {
        } un;
 } BIU_DIAG_VAR;
 
+/* Structure for MB command READ_EVENT_LOG (0x38) */
+struct READ_EVENT_LOG_VAR {
+       uint32_t word1;
+#define lpfc_event_log_SHIFT   29
+#define lpfc_event_log_MASK    0x00000001
+#define lpfc_event_log_WORD    word1
+#define USE_MAILBOX_RESPONSE   1
+       uint32_t offset;
+       struct ulp_bde64 rcv_bde64;
+};
+
 /* Structure for MB Command INIT_LINK (05) */
 
 typedef struct {
@@ -2487,8 +2486,8 @@ typedef struct {
 #define  DMP_VPORT_REGION_SIZE  0x200
 #define  DMP_MBOX_OFFSET_WORD   0x5
 
-#define  DMP_REGION_23          0x17   /* fcoe param  and port state region */
-#define  DMP_RGN23_SIZE                 0x400
+#define  DMP_REGION_23          0x17   /* fcoe param  and port state region */
+#define  DMP_RGN23_SIZE                 0x400
 
 #define  WAKE_UP_PARMS_REGION_ID    4
 #define  WAKE_UP_PARMS_WORD_SIZE   15
@@ -2503,9 +2502,9 @@ struct vport_rec {
 #define VPORT_INFO_REV 0x1
 #define MAX_STATIC_VPORT_COUNT 16
 struct static_vport_info {
-       uint32_t                signature;
+       uint32_t                signature;
        uint32_t                rev;
-       struct vport_rec        vport_list[MAX_STATIC_VPORT_COUNT];
+       struct vport_rec        vport_list[MAX_STATIC_VPORT_COUNT];
        uint32_t                resvd[66];
 };
 
@@ -2934,6 +2933,12 @@ typedef struct {
 /* Union of all Mailbox Command types */
 #define MAILBOX_CMD_WSIZE      32
 #define MAILBOX_CMD_SIZE       (MAILBOX_CMD_WSIZE * sizeof(uint32_t))
+/* ext_wsize times 4 bytes should not be greater than max xmit size */
+#define MAILBOX_EXT_WSIZE      512
+#define MAILBOX_EXT_SIZE       (MAILBOX_EXT_WSIZE * sizeof(uint32_t))
+#define MAILBOX_HBA_EXT_OFFSET  0x100
+/* max mbox xmit size is a page size for sysfs IO operations */
+#define MAILBOX_MAX_XMIT_SIZE   PAGE_SIZE
 
 typedef union {
        uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
@@ -2972,6 +2977,9 @@ typedef union {
        REG_VPI_VAR varRegVpi;          /* cmd = 0x96 (REG_VPI) */
        UNREG_VPI_VAR varUnregVpi;      /* cmd = 0x97 (UNREG_VPI) */
        ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
+       struct READ_EVENT_LOG_VAR varRdEventLog;        /* cmd = 0x38
+                                                        * (READ_EVENT_LOG)
+                                                        */
        struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI)     */
 } MAILVARIANTS;
 
@@ -3652,7 +3660,8 @@ typedef struct _IOCB {    /* IOCB structure */
 /* Maximum IOCBs that will fit in SLI2 slim */
 #define MAX_SLI2_IOCB    498
 #define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
-                           (sizeof(MAILBOX_t) + sizeof(PCB_t)))
+                           (sizeof(MAILBOX_t) + sizeof(PCB_t) + \
+                           sizeof(uint32_t) * MAILBOX_EXT_WSIZE))
 
 /* HBQ entries are 4 words each = 4k */
 #define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) *  \
@@ -3660,6 +3669,7 @@ typedef struct _IOCB {    /* IOCB structure */
 
 struct lpfc_sli2_slim {
        MAILBOX_t mbx;
+       uint32_t  mbx_ext_words[MAILBOX_EXT_WSIZE];
        PCB_t pcb;
        IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
 };
index 820015f..bbdcf96 100644 (file)
  * Or clear that bit field:
  *     bf_set(example_bit_field, &t1, 0);
  */
+#define bf_get_le32(name, ptr) \
+       ((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK)
 #define bf_get(name, ptr) \
        (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK)
+#define bf_set_le32(name, ptr, value) \
+       ((ptr)->name##_WORD = cpu_to_le32(((((value) & \
+       name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \
+       ~(name##_MASK << name##_SHIFT)))))
 #define bf_set(name, ptr, value) \
        ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \
                 ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT))))
@@ -781,6 +787,7 @@ struct mbox_header {
 #define LPFC_MBOX_OPCODE_EQ_DESTROY            0x37
 #define LPFC_MBOX_OPCODE_QUERY_FW_CFG          0x3A
 #define LPFC_MBOX_OPCODE_FUNCTION_RESET                0x3D
+#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT         0x5A
 
 /* FCoE Opcodes */
 #define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE                        0x01
@@ -1102,6 +1109,39 @@ struct lpfc_mbx_mq_create {
        } u;
 };
 
+struct lpfc_mbx_mq_create_ext {
+       struct mbox_header header;
+       union {
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_mq_create_ext_num_pages_SHIFT         0
+#define lpfc_mbx_mq_create_ext_num_pages_MASK          0x0000FFFF
+#define lpfc_mbx_mq_create_ext_num_pages_WORD          word0
+                       uint32_t async_evt_bmap;
+#define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT    LPFC_TRAILER_CODE_LINK
+#define lpfc_mbx_mq_create_ext_async_evt_link_MASK     0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_link_WORD     async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_fcfste_SHIFT  LPFC_TRAILER_CODE_FCOE
+#define lpfc_mbx_mq_create_ext_async_evt_fcfste_MASK   0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_fcfste_WORD   async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_group5_SHIFT  LPFC_TRAILER_CODE_GRP5
+#define lpfc_mbx_mq_create_ext_async_evt_group5_MASK   0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_group5_WORD   async_evt_bmap
+                       struct mq_context context;
+                       struct dma_address page[LPFC_MAX_MQ_PAGE];
+               } request;
+               struct {
+                       uint32_t word0;
+#define lpfc_mbx_mq_create_q_id_SHIFT  0
+#define lpfc_mbx_mq_create_q_id_MASK   0x0000FFFF
+#define lpfc_mbx_mq_create_q_id_WORD   word0
+               } response;
+       } u;
+#define LPFC_ASYNC_EVENT_LINK_STATE    0x2
+#define LPFC_ASYNC_EVENT_FCF_STATE     0x4
+#define LPFC_ASYNC_EVENT_GROUP5                0x20
+};
+
 struct lpfc_mbx_mq_destroy {
        struct mbox_header header;
        union {
@@ -1428,8 +1468,8 @@ struct lpfc_mbx_reg_vfi {
 #define lpfc_reg_vfi_fcfi_WORD         word2
        uint32_t wwn[2];
        struct ulp_bde64 bde;
-       uint32_t word8_rsvd;
-       uint32_t word9_rsvd;
+       uint32_t e_d_tov;
+       uint32_t r_a_tov;
        uint32_t word10;
 #define lpfc_reg_vfi_nport_id_SHIFT            0
 #define lpfc_reg_vfi_nport_id_MASK             0x00FFFFFF
@@ -1940,6 +1980,7 @@ struct lpfc_mbx_sli4_params {
 #define rdma_MASK                              0x00000001
 #define rdma_WORD                              word3
        uint32_t sge_supp_len;
+#define SLI4_PAGE_SIZE 4096
        uint32_t word5;
 #define if_page_sz_SHIFT                       0
 #define if_page_sz_MASK                                0x0000ffff
@@ -2041,6 +2082,7 @@ struct lpfc_mqe {
                struct lpfc_mbx_reg_fcfi reg_fcfi;
                struct lpfc_mbx_unreg_fcfi unreg_fcfi;
                struct lpfc_mbx_mq_create mq_create;
+               struct lpfc_mbx_mq_create_ext mq_create_ext;
                struct lpfc_mbx_eq_create eq_create;
                struct lpfc_mbx_cq_create cq_create;
                struct lpfc_mbx_wq_create wq_create;
@@ -2099,6 +2141,7 @@ struct lpfc_mcqe {
 #define LPFC_TRAILER_CODE_LINK 0x1
 #define LPFC_TRAILER_CODE_FCOE 0x2
 #define LPFC_TRAILER_CODE_DCBX 0x3
+#define LPFC_TRAILER_CODE_GRP5 0x5
 };
 
 struct lpfc_acqe_link {
@@ -2168,6 +2211,19 @@ struct lpfc_acqe_dcbx {
        uint32_t trailer;
 };
 
+struct lpfc_acqe_grp5 {
+       uint32_t word0;
+#define lpfc_acqe_grp5_pport_SHIFT     0
+#define lpfc_acqe_grp5_pport_MASK      0x000000FF
+#define lpfc_acqe_grp5_pport_WORD      word0
+       uint32_t word1;
+#define lpfc_acqe_grp5_llink_spd_SHIFT 16
+#define lpfc_acqe_grp5_llink_spd_MASK  0x0000FFFF
+#define lpfc_acqe_grp5_llink_spd_WORD  word1
+       uint32_t event_tag;
+       uint32_t trailer;
+};
+
 /*
  * Define the bootstrap mailbox (bmbx) region used to communicate
  * mailbox command between the host and port. The mailbox consists
index 774663e..cd9697e 100644 (file)
@@ -2566,7 +2566,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        shost->max_cmd_len = 16;
        if (phba->sli_rev == LPFC_SLI_REV4) {
                shost->dma_boundary =
-                       phba->sli4_hba.pc_sli4_params.sge_supp_len;
+                       phba->sli4_hba.pc_sli4_params.sge_supp_len-1;
                shost->sg_tablesize = phba->cfg_sg_seg_cnt;
        }
 
@@ -2600,15 +2600,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
        init_timer(&vport->els_tmofunc);
        vport->els_tmofunc.function = lpfc_els_timeout;
        vport->els_tmofunc.data = (unsigned long)vport;
-       if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) {
-               phba->menlo_flag |= HBA_MENLO_SUPPORT;
-               /* check for menlo minimum sg count */
-               if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) {
-                       phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT;
-                       shost->sg_tablesize = phba->cfg_sg_seg_cnt;
-               }
-       }
-
        error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
        if (error)
                goto out_put_shost;
@@ -3236,12 +3227,26 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
 
        if (!vport)
                return NULL;
-       ndlp = lpfc_findnode_did(vport, Fabric_DID);
-       if (!ndlp)
-               return NULL;
        phba = vport->phba;
        if (!phba)
                return NULL;
+       ndlp = lpfc_findnode_did(vport, Fabric_DID);
+       if (!ndlp) {
+               /* Cannot find existing Fabric ndlp, so allocate a new one */
+               ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+               if (!ndlp)
+                       return 0;
+               lpfc_nlp_init(vport, ndlp, Fabric_DID);
+               /* Set the node type */
+               ndlp->nlp_type |= NLP_FABRIC;
+               /* Put ndlp onto node list */
+               lpfc_enqueue_node(vport, ndlp);
+       } else if (!NLP_CHK_NODE_ACT(ndlp)) {
+               /* re-setup ndlp without removing from node list */
+               ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
+               if (!ndlp)
+                       return 0;
+       }
        if (phba->pport->port_state <= LPFC_FLOGI)
                return NULL;
        /* If virtual link is not yet instantiated ignore CVL */
@@ -3304,11 +3309,20 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
        switch (event_type) {
        case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
        case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD:
-               lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
-                       "2546 New FCF found/FCF parameter modified event: "
-                       "evt_tag:x%x, fcf_index:x%x\n",
-                       acqe_fcoe->event_tag, acqe_fcoe->index);
-
+               if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF)
+                       lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
+                                       LOG_DISCOVERY,
+                                       "2546 New FCF found event: "
+                                       "evt_tag:x%x, fcf_index:x%x\n",
+                                       acqe_fcoe->event_tag,
+                                       acqe_fcoe->index);
+               else
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_FIP |
+                                       LOG_DISCOVERY,
+                                       "2788 FCF parameter modified event: "
+                                       "evt_tag:x%x, fcf_index:x%x\n",
+                                       acqe_fcoe->event_tag,
+                                       acqe_fcoe->index);
                spin_lock_irq(&phba->hbalock);
                if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
                    (phba->hba_flag & FCF_DISC_INPROGRESS)) {
@@ -3517,6 +3531,32 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba,
 }
 
 /**
+ * lpfc_sli4_async_grp5_evt - Process the asynchronous group5 event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async grp5 completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous grp5 event. A grp5 event
+ * is an asynchronous notified of a logical link speed change.  The Port
+ * reports the logical link speed in units of 10Mbps.
+ **/
+static void
+lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba,
+                        struct lpfc_acqe_grp5 *acqe_grp5)
+{
+       uint16_t prev_ll_spd;
+
+       phba->fc_eventTag = acqe_grp5->event_tag;
+       phba->fcoe_eventtag = acqe_grp5->event_tag;
+       prev_ll_spd = phba->sli4_hba.link_state.logical_speed;
+       phba->sli4_hba.link_state.logical_speed =
+               (bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5));
+       lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+                       "2789 GRP5 Async Event: Updating logical link speed "
+                       "from %dMbps to %dMbps\n", (prev_ll_spd * 10),
+                       (phba->sli4_hba.link_state.logical_speed*10));
+}
+
+/**
  * lpfc_sli4_async_event_proc - Process all the pending asynchronous event
  * @phba: pointer to lpfc hba data structure.
  *
@@ -3552,6 +3592,10 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
                        lpfc_sli4_async_dcbx_evt(phba,
                                                 &cq_event->cqe.acqe_dcbx);
                        break;
+               case LPFC_TRAILER_CODE_GRP5:
+                       lpfc_sli4_async_grp5_evt(phba,
+                                                &cq_event->cqe.acqe_grp5);
+                       break;
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                        "1804 Invalid asynchrous event code: "
@@ -3813,6 +3857,13 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
 
        /* Get all the module params for configuring this host */
        lpfc_get_cfgparam(phba);
+       if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) {
+               phba->menlo_flag |= HBA_MENLO_SUPPORT;
+               /* check for menlo minimum sg count */
+               if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT)
+                       phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT;
+       }
+
        /*
         * Since the sg_tablesize is module parameter, the sg_dma_buf_size
         * used to create the sg_dma_buf_pool must be dynamically calculated.
@@ -4030,6 +4081,43 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        if (unlikely(rc))
                goto out_free_bsmbx;
 
+       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+                                                      GFP_KERNEL);
+       if (!mboxq) {
+               rc = -ENOMEM;
+               goto out_free_bsmbx;
+       }
+
+       /* Get the Supported Pages. It is always available. */
+       lpfc_supported_pages(mboxq);
+       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+       if (unlikely(rc)) {
+               rc = -EIO;
+               mempool_free(mboxq, phba->mbox_mem_pool);
+               goto out_free_bsmbx;
+       }
+
+       mqe = &mboxq->u.mqe;
+       memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
+              LPFC_MAX_SUPPORTED_PAGES);
+       for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
+               switch (pn_page[i]) {
+               case LPFC_SLI4_PARAMETERS:
+                       phba->sli4_hba.pc_sli4_params.supported = 1;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* Read the port's SLI4 Parameters capabilities if supported. */
+       if (phba->sli4_hba.pc_sli4_params.supported)
+               rc = lpfc_pc_sli4_params_get(phba, mboxq);
+       mempool_free(mboxq, phba->mbox_mem_pool);
+       if (rc) {
+               rc = -EIO;
+               goto out_free_bsmbx;
+       }
        /* Create all the SLI4 queues */
        rc = lpfc_sli4_queue_create(phba);
        if (rc)
@@ -4090,43 +4178,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                goto out_free_fcp_eq_hdl;
        }
 
-       mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
-                                                      GFP_KERNEL);
-       if (!mboxq) {
-               rc = -ENOMEM;
-               goto out_free_fcp_eq_hdl;
-       }
-
-       /* Get the Supported Pages. It is always available. */
-       lpfc_supported_pages(mboxq);
-       rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
-       if (unlikely(rc)) {
-               rc = -EIO;
-               mempool_free(mboxq, phba->mbox_mem_pool);
-               goto out_free_fcp_eq_hdl;
-       }
-
-       mqe = &mboxq->u.mqe;
-       memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
-              LPFC_MAX_SUPPORTED_PAGES);
-       for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
-               switch (pn_page[i]) {
-               case LPFC_SLI4_PARAMETERS:
-                       phba->sli4_hba.pc_sli4_params.supported = 1;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* Read the port's SLI4 Parameters capabilities if supported. */
-       if (phba->sli4_hba.pc_sli4_params.supported)
-               rc = lpfc_pc_sli4_params_get(phba, mboxq);
-       mempool_free(mboxq, phba->mbox_mem_pool);
-       if (rc) {
-               rc = -EIO;
-               goto out_free_fcp_eq_hdl;
-       }
        return rc;
 
 out_free_fcp_eq_hdl:
@@ -5050,6 +5101,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)
 
        memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
        phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
+       phba->mbox_ext = (phba->slim2p.virt +
+               offsetof(struct lpfc_sli2_slim, mbx_ext_words));
        phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
        phba->IOCBs = (phba->slim2p.virt +
                       offsetof(struct lpfc_sli2_slim, IOCBs));
@@ -7753,21 +7806,23 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is called to prepare the SLI3 device for PCI slot recover. It
- * aborts and stops all the on-going I/Os on the pci device.
+ * aborts all the outstanding SCSI I/Os to the pci device.
  **/
 static void
 lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)
 {
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring  *pring;
+
        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "2723 PCI channel I/O abort preparing for recovery\n");
-       /* Prepare for bringing HBA offline */
-       lpfc_offline_prep(phba);
-       /* Clear sli active flag to prevent sysfs access to HBA */
-       spin_lock_irq(&phba->hbalock);
-       phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE;
-       spin_unlock_irq(&phba->hbalock);
-       /* Stop and flush all I/Os and bring HBA offline */
-       lpfc_offline(phba);
+
+       /*
+        * There may be errored I/Os through HBA, abort all I/Os on txcmplq
+        * and let the SCSI mid-layer to retry them to recover.
+        */
+       pring = &psli->ring[psli->fcp_ring];
+       lpfc_sli_abort_iocb_ring(phba, pring);
 }
 
 /**
@@ -7781,21 +7836,20 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)
 static void
 lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
 {
-       struct lpfc_sli *psli = &phba->sli;
-       struct lpfc_sli_ring  *pring;
-
        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "2710 PCI channel disable preparing for reset\n");
+
+       /* Block all SCSI devices' I/Os on the host */
+       lpfc_scsi_dev_block(phba);
+
+       /* stop all timers */
+       lpfc_stop_hba_timers(phba);
+
        /* Disable interrupt and pci device */
        lpfc_sli_disable_intr(phba);
        pci_disable_device(phba->pcidev);
-       /*
-        * There may be I/Os dropped by the firmware.
-        * Error iocb (I/O) on txcmplq and let the SCSI layer
-        * retry it after re-establishing link.
-        */
-       pring = &psli->ring[psli->fcp_ring];
-       lpfc_sli_abort_iocb_ring(phba, pring);
+       /* Flush all driver's outstanding SCSI I/Os as we are to reset */
+       lpfc_sli_flush_fcp_rings(phba);
 }
 
 /**
@@ -7811,6 +7865,12 @@ lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
 {
        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                        "2711 PCI channel permanent disable for failure\n");
+       /* Block all SCSI devices' I/Os on the host */
+       lpfc_scsi_dev_block(phba);
+
+       /* stop all timers */
+       lpfc_stop_hba_timers(phba);
+
        /* Clean up all driver's outstanding SCSI I/Os */
        lpfc_sli_flush_fcp_rings(phba);
 }
@@ -7839,9 +7899,6 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
-       /* Block all SCSI devices' I/Os on the host */
-       lpfc_scsi_dev_block(phba);
-
        switch (state) {
        case pci_channel_io_normal:
                /* Non-fatal error, prepare for recovery */
@@ -7948,7 +8005,7 @@ lpfc_io_resume_s3(struct pci_dev *pdev)
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
-       /* Bring the device online */
+       /* Bring device online, it will be no-op for non-fatal error resume */
        lpfc_online(phba);
 
        /* Clean up Advanced Error Reporting (AER) if needed */
index 72e6adb..e84dc33 100644 (file)
@@ -1216,7 +1216,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        phba->pcb->feature = FEATURE_INITIAL_SLI2;
 
        /* Setup Mailbox pointers */
-       phba->pcb->mailBoxSize = sizeof(MAILBOX_t);
+       phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE;
        offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt;
        pdma_addr = phba->slim2p.phys + offset;
        phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr);
@@ -1272,28 +1272,41 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
         *
         */
 
-       if (phba->sli_rev == 3) {
-               phba->host_gp = &mb_slim->us.s3.host[0];
-               phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
-       } else {
-               phba->host_gp = &mb_slim->us.s2.host[0];
+       if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) {
+               phba->host_gp = &phba->mbox->us.s2.host[0];
                phba->hbq_put = NULL;
-       }
+               offset = (uint8_t *)&phba->mbox->us.s2.host -
+                       (uint8_t *)phba->slim2p.virt;
+               pdma_addr = phba->slim2p.phys + offset;
+               phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr);
+               phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr);
+       } else {
+               /* Always Host Group Pointer is in SLIM */
+               mb->un.varCfgPort.hps = 1;
 
-       /* mask off BAR0's flag bits 0 - 3 */
-       phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
-               (void __iomem *)phba->host_gp -
-               (void __iomem *)phba->MBslimaddr;
-       if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
-               phba->pcb->hgpAddrHigh = bar_high;
-       else
-               phba->pcb->hgpAddrHigh = 0;
-       /* write HGP data to SLIM at the required longword offset */
-       memset(&hgp, 0, sizeof(struct lpfc_hgp));
+               if (phba->sli_rev == 3) {
+                       phba->host_gp = &mb_slim->us.s3.host[0];
+                       phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
+               } else {
+                       phba->host_gp = &mb_slim->us.s2.host[0];
+                       phba->hbq_put = NULL;
+               }
 
-       for (i=0; i < phba->sli.num_rings; i++) {
-               lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
+               /* mask off BAR0's flag bits 0 - 3 */
+               phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
+                       (void __iomem *)phba->host_gp -
+                       (void __iomem *)phba->MBslimaddr;
+               if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
+                       phba->pcb->hgpAddrHigh = bar_high;
+               else
+                       phba->pcb->hgpAddrHigh = 0;
+               /* write HGP data to SLIM at the required longword offset */
+               memset(&hgp, 0, sizeof(struct lpfc_hgp));
+
+               for (i = 0; i < phba->sli.num_rings; i++) {
+                       lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
                                    sizeof(*phba->host_gp));
+               }
        }
 
        /* Setup Port Group offset */
@@ -1598,7 +1611,7 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
        for (sgentry = 0; sgentry < sgecount; sgentry++) {
                lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge);
                phyaddr = getPaddr(sge.pa_hi, sge.pa_lo);
-               dma_free_coherent(&phba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
                                  mbox->sge_array->addr[sgentry], phyaddr);
        }
        /* Free the sge address array memory */
@@ -1656,7 +1669,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
        }
 
        /* Setup for the none-embedded mbox command */
-       pcount = (PAGE_ALIGN(length))/PAGE_SIZE;
+       pcount = (PAGE_ALIGN(length))/SLI4_PAGE_SIZE;
        pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ?
                                LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount;
        /* Allocate record for keeping SGE virtual addresses */
@@ -1671,24 +1684,24 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
        for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) {
                /* The DMA memory is always allocated in the length of a
                 * page even though the last SGE might not fill up to a
-                * page, this is used as a priori size of PAGE_SIZE for
+                * page, this is used as a priori size of SLI4_PAGE_SIZE for
                 * the later DMA memory free.
                 */
-               viraddr = dma_alloc_coherent(&phba->pcidev->dev, PAGE_SIZE,
+               viraddr = dma_alloc_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
                                             &phyaddr, GFP_KERNEL);
                /* In case of malloc fails, proceed with whatever we have */
                if (!viraddr)
                        break;
-               memset(viraddr, 0, PAGE_SIZE);
+               memset(viraddr, 0, SLI4_PAGE_SIZE);
                mbox->sge_array->addr[pagen] = viraddr;
                /* Keep the first page for later sub-header construction */
                if (pagen == 0)
                        cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr;
                resid_len = length - alloc_len;
-               if (resid_len > PAGE_SIZE) {
+               if (resid_len > SLI4_PAGE_SIZE) {
                        lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
-                                             PAGE_SIZE);
-                       alloc_len += PAGE_SIZE;
+                                             SLI4_PAGE_SIZE);
+                       alloc_len += SLI4_PAGE_SIZE;
                } else {
                        lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
                                              resid_len);
@@ -1886,6 +1899,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
        memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));
        reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);
        reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
+       reg_vfi->e_d_tov = vport->phba->fc_edtov;
+       reg_vfi->r_a_tov = vport->phba->fc_ratov;
        reg_vfi->bde.addrHigh = putPaddrHigh(phys);
        reg_vfi->bde.addrLow = putPaddrLow(phys);
        reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
index e331204..b90820a 100644 (file)
@@ -493,6 +493,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
              struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
 {
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+       struct lpfc_hba    *phba = vport->phba;
+       struct lpfc_vport **vports;
+       int i, active_vlink_present = 0 ;
 
        /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
        /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
@@ -505,15 +508,44 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
        else
                lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
-       if ((ndlp->nlp_DID == Fabric_DID) &&
-               vport->port_type == LPFC_NPIV_PORT) {
+       if (ndlp->nlp_DID == Fabric_DID) {
+               if (vport->port_state <= LPFC_FDISC)
+                       goto out;
                lpfc_linkdown_port(vport);
-               mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
                spin_lock_irq(shost->host_lock);
-               ndlp->nlp_flag |= NLP_DELAY_TMO;
+               vport->fc_flag |= FC_VPORT_LOGO_RCVD;
                spin_unlock_irq(shost->host_lock);
+               vports = lpfc_create_vport_work_array(phba);
+               if (vports) {
+                       for (i = 0; i <= phba->max_vports && vports[i] != NULL;
+                                       i++) {
+                               if ((!(vports[i]->fc_flag &
+                                       FC_VPORT_LOGO_RCVD)) &&
+                                       (vports[i]->port_state > LPFC_FDISC)) {
+                                       active_vlink_present = 1;
+                                       break;
+                               }
+                       }
+                       lpfc_destroy_vport_work_array(phba, vports);
+               }
 
-               ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
+               if (active_vlink_present) {
+                       /*
+                        * If there are other active VLinks present,
+                        * re-instantiate the Vlink using FDISC.
+                        */
+                       mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+                       spin_lock_irq(shost->host_lock);
+                       ndlp->nlp_flag |= NLP_DELAY_TMO;
+                       spin_unlock_irq(shost->host_lock);
+                       ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
+                       vport->port_state = LPFC_FDISC;
+               } else {
+                       spin_lock_irq(shost->host_lock);
+                       phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG;
+                       spin_unlock_irq(shost->host_lock);
+                       lpfc_retry_pport_discovery(phba);
+               }
        } else if ((!(ndlp->nlp_type & NLP_FABRIC) &&
                ((ndlp->nlp_type & NLP_FCP_TARGET) ||
                !(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
@@ -526,6 +558,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
                ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
        }
+out:
        ndlp->nlp_prev_state = ndlp->nlp_state;
        lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 
@@ -604,11 +637,55 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        lpfc_unreg_rpi(vport, ndlp);
        return 0;
 }
+/**
+ * lpfc_release_rpi - Release a RPI by issueing unreg_login mailbox cmd.
+ * @phba : Pointer to lpfc_hba structure.
+ * @vport: Pointer to lpfc_vport structure.
+ * @rpi  : rpi to be release.
+ *
+ * This function will send a unreg_login mailbox command to the firmware
+ * to release a rpi.
+ **/
+void
+lpfc_release_rpi(struct lpfc_hba *phba,
+               struct lpfc_vport *vport,
+               uint16_t rpi)
+{
+       LPFC_MBOXQ_t *pmb;
+       int rc;
+
+       pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+                       GFP_KERNEL);
+       if (!pmb)
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+                       "2796 mailbox memory allocation failed \n");
+       else {
+               lpfc_unreg_login(phba, vport->vpi, rpi, pmb);
+               pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+               if (rc == MBX_NOT_FINISHED)
+                       mempool_free(pmb, phba->mbox_mem_pool);
+       }
+}
 
 static uint32_t
 lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                  void *arg, uint32_t evt)
 {
+       struct lpfc_hba *phba;
+       LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+       MAILBOX_t *mb;
+       uint16_t rpi;
+
+       phba = vport->phba;
+       /* Release the RPI if reglogin completing */
+       if (!(phba->pport->load_flag & FC_UNLOADING) &&
+               (evt == NLP_EVT_CMPL_REG_LOGIN) &&
+               (!pmb->u.mb.mbxStatus)) {
+               mb = &pmb->u.mb;
+               rpi = pmb->u.mb.un.varWords[0];
+               lpfc_release_rpi(phba, vport, rpi);
+       }
        lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
                         "0271 Illegal State Transition: node x%x "
                         "event x%x, state x%x Data: x%x x%x\n",
@@ -944,6 +1021,18 @@ static uint32_t
 lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
        struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
 {
+       struct lpfc_hba *phba;
+       LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+       MAILBOX_t *mb = &pmb->u.mb;
+       uint16_t rpi;
+
+       phba = vport->phba;
+       /* Release the RPI */
+       if (!(phba->pport->load_flag & FC_UNLOADING) &&
+               !mb->mbxStatus) {
+               rpi = pmb->u.mb.un.varWords[0];
+               lpfc_release_rpi(phba, vport, rpi);
+       }
        return ndlp->nlp_state;
 }
 
index dccdb82..f4a3b2e 100644 (file)
@@ -1141,37 +1141,47 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 }
 
 /*
- * Given a scsi cmnd, determine the BlockGuard profile to be used
- * with the cmd
+ * Given a scsi cmnd, determine the BlockGuard opcodes to be used with it
+ * @sc: The SCSI command to examine
+ * @txopt: (out) BlockGuard operation for transmitted data
+ * @rxopt: (out) BlockGuard operation for received data
+ *
+ * Returns: zero on success; non-zero if tx and/or rx op cannot be determined
+ *
  */
 static int
-lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
+lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
+               uint8_t *txop, uint8_t *rxop)
 {
        uint8_t guard_type = scsi_host_get_guard(sc->device->host);
-       uint8_t ret_prof = LPFC_PROF_INVALID;
+       uint8_t ret = 0;
 
        if (guard_type == SHOST_DIX_GUARD_IP) {
                switch (scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_INSERT:
                case SCSI_PROT_WRITE_STRIP:
-                       ret_prof = LPFC_PROF_AST2;
+                       *txop = BG_OP_IN_CSUM_OUT_NODIF;
+                       *rxop = BG_OP_IN_NODIF_OUT_CSUM;
                        break;
 
                case SCSI_PROT_READ_STRIP:
                case SCSI_PROT_WRITE_INSERT:
-                       ret_prof = LPFC_PROF_A1;
+                       *txop = BG_OP_IN_NODIF_OUT_CRC;
+                       *rxop = BG_OP_IN_CRC_OUT_NODIF;
                        break;
 
                case SCSI_PROT_READ_PASS:
                case SCSI_PROT_WRITE_PASS:
-                       ret_prof = LPFC_PROF_AST1;
+                       *txop = BG_OP_IN_CSUM_OUT_CRC;
+                       *rxop = BG_OP_IN_CRC_OUT_CSUM;
                        break;
 
                case SCSI_PROT_NORMAL:
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-                               "9063 BLKGRD:Bad op/guard:%d/%d combination\n",
+                               "9063 BLKGRD: Bad op/guard:%d/%d combination\n",
                                        scsi_get_prot_op(sc), guard_type);
+                       ret = 1;
                        break;
 
                }
@@ -1179,12 +1189,14 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
                switch (scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_STRIP:
                case SCSI_PROT_WRITE_INSERT:
-                       ret_prof = LPFC_PROF_A1;
+                       *txop = BG_OP_IN_NODIF_OUT_CRC;
+                       *rxop = BG_OP_IN_CRC_OUT_NODIF;
                        break;
 
                case SCSI_PROT_READ_PASS:
                case SCSI_PROT_WRITE_PASS:
-                       ret_prof = LPFC_PROF_C1;
+                       *txop = BG_OP_IN_CRC_OUT_CRC;
+                       *rxop = BG_OP_IN_CRC_OUT_CRC;
                        break;
 
                case SCSI_PROT_READ_INSERT:
@@ -1194,6 +1206,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
                                "9075 BLKGRD: Bad op/guard:%d/%d combination\n",
                                        scsi_get_prot_op(sc), guard_type);
+                       ret = 1;
                        break;
                }
        } else {
@@ -1201,7 +1214,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
                BUG();
        }
 
-       return ret_prof;
+       return ret;
 }
 
 struct scsi_dif_tuple {
@@ -1266,7 +1279,9 @@ lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
  * The buffer list consists of just one protection group described
  * below:
  *                                +-------------------------+
- *   start of prot group  -->     |          PDE_1          |
+ *   start of prot group  -->     |          PDE_5          |
+ *                                +-------------------------+
+ *                                |          PDE_6          |
  *                                +-------------------------+
  *                                |         Data BDE        |
  *                                +-------------------------+
@@ -1284,30 +1299,49 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                struct ulp_bde64 *bpl, int datasegcnt)
 {
        struct scatterlist *sgde = NULL; /* s/g data entry */
-       struct lpfc_pde *pde1 = NULL;
+       struct lpfc_pde5 *pde5 = NULL;
+       struct lpfc_pde6 *pde6 = NULL;
        dma_addr_t physaddr;
-       int i = 0, num_bde = 0;
+       int i = 0, num_bde = 0, status;
        int datadir = sc->sc_data_direction;
-       int prof = LPFC_PROF_INVALID;
        unsigned blksize;
        uint32_t reftag;
        uint16_t apptagmask, apptagval;
+       uint8_t txop, rxop;
 
-       pde1 = (struct lpfc_pde *) bpl;
-       prof = lpfc_sc_to_sli_prof(phba, sc);
-
-       if (prof == LPFC_PROF_INVALID)
+       status  = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+       if (status)
                goto out;
 
-       /* extract some info from the scsi command for PDE1*/
+       /* extract some info from the scsi command for pde*/
        blksize = lpfc_cmd_blksize(sc);
        lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
 
-       /* setup PDE1 with what we have */
-       lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize,
-                       BG_EC_STOP_ERR);
-       lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag);
+       /* setup PDE5 with what we have */
+       pde5 = (struct lpfc_pde5 *) bpl;
+       memset(pde5, 0, sizeof(struct lpfc_pde5));
+       bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
+       pde5->reftag = reftag;
 
+       /* advance bpl and increment bde count */
+       num_bde++;
+       bpl++;
+       pde6 = (struct lpfc_pde6 *) bpl;
+
+       /* setup PDE6 with the rest of the info */
+       memset(pde6, 0, sizeof(struct lpfc_pde6));
+       bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
+       bf_set(pde6_optx, pde6, txop);
+       bf_set(pde6_oprx, pde6, rxop);
+       if (datadir == DMA_FROM_DEVICE) {
+               bf_set(pde6_ce, pde6, 1);
+               bf_set(pde6_re, pde6, 1);
+               bf_set(pde6_ae, pde6, 1);
+       }
+       bf_set(pde6_ai, pde6, 1);
+       bf_set(pde6_apptagval, pde6, apptagval);
+
+       /* advance bpl and increment bde count */
        num_bde++;
        bpl++;
 
@@ -1342,15 +1376,17 @@ out:
  * The buffer list for this type consists of one or more of the
  * protection groups described below:
  *                                    +-------------------------+
- *   start of first prot group  -->   |          PDE_1          |
+ *   start of first prot group  -->   |          PDE_5          |
+ *                                    +-------------------------+
+ *                                    |          PDE_6          |
  *                                    +-------------------------+
- *                                    |      PDE_3 (Prot BDE)   |
+ *                                    |      PDE_7 (Prot BDE)   |
  *                                    +-------------------------+
  *                                    |        Data BDE         |
  *                                    +-------------------------+
  *                                    |more Data BDE's ... (opt)|
  *                                    +-------------------------+
- *   start of new  prot group  -->    |          PDE_1          |
+ *   start of new  prot group  -->    |          PDE_5          |
  *                                    +-------------------------+
  *                                    |          ...            |
  *                                    +-------------------------+
@@ -1369,19 +1405,21 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 {
        struct scatterlist *sgde = NULL; /* s/g data entry */
        struct scatterlist *sgpe = NULL; /* s/g prot entry */
-       struct lpfc_pde *pde1 = NULL;
+       struct lpfc_pde5 *pde5 = NULL;
+       struct lpfc_pde6 *pde6 = NULL;
        struct ulp_bde64 *prot_bde = NULL;
        dma_addr_t dataphysaddr, protphysaddr;
        unsigned short curr_data = 0, curr_prot = 0;
        unsigned int split_offset, protgroup_len;
        unsigned int protgrp_blks, protgrp_bytes;
        unsigned int remainder, subtotal;
-       int prof = LPFC_PROF_INVALID;
+       int status;
        int datadir = sc->sc_data_direction;
        unsigned char pgdone = 0, alldone = 0;
        unsigned blksize;
        uint32_t reftag;
        uint16_t apptagmask, apptagval;
+       uint8_t txop, rxop;
        int num_bde = 0;
 
        sgpe = scsi_prot_sglist(sc);
@@ -1394,31 +1432,47 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                return 0;
        }
 
-       prof = lpfc_sc_to_sli_prof(phba, sc);
-       if (prof == LPFC_PROF_INVALID)
+       status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+       if (status)
                goto out;
 
-       /* extract some info from the scsi command for PDE1*/
+       /* extract some info from the scsi command */
        blksize = lpfc_cmd_blksize(sc);
        lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
 
        split_offset = 0;
        do {
-               /* setup the first PDE_1 */
-               pde1 = (struct lpfc_pde *) bpl;
-
-               lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize,
-                               BG_EC_STOP_ERR);
-               lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag);
+               /* setup PDE5 with what we have */
+               pde5 = (struct lpfc_pde5 *) bpl;
+               memset(pde5, 0, sizeof(struct lpfc_pde5));
+               bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
+               pde5->reftag = reftag;
 
+               /* advance bpl and increment bde count */
+               num_bde++;
+               bpl++;
+               pde6 = (struct lpfc_pde6 *) bpl;
+
+               /* setup PDE6 with the rest of the info */
+               memset(pde6, 0, sizeof(struct lpfc_pde6));
+               bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
+               bf_set(pde6_optx, pde6, txop);
+               bf_set(pde6_oprx, pde6, rxop);
+               bf_set(pde6_ce, pde6, 1);
+               bf_set(pde6_re, pde6, 1);
+               bf_set(pde6_ae, pde6, 1);
+               bf_set(pde6_ai, pde6, 1);
+               bf_set(pde6_apptagval, pde6, apptagval);
+
+               /* advance bpl and increment bde count */
                num_bde++;
                bpl++;
 
                /* setup the first BDE that points to protection buffer */
                prot_bde = (struct ulp_bde64 *) bpl;
                protphysaddr = sg_dma_address(sgpe);
-               prot_bde->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));
-               prot_bde->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr));
+               prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
+               prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
                protgroup_len = sg_dma_len(sgpe);
 
 
@@ -1429,10 +1483,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                protgrp_bytes = protgrp_blks * blksize;
 
                prot_bde->tus.f.bdeSize = protgroup_len;
-               if (datadir == DMA_TO_DEVICE)
-                       prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-               else
-                       prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+               prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR;
                prot_bde->tus.w = le32_to_cpu(bpl->tus.w);
 
                curr_prot++;
@@ -1484,6 +1535,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
                        /* Move to the next s/g segment if possible */
                        sgde = sg_next(sgde);
+
                }
 
                /* are we done ? */
@@ -1506,7 +1558,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
 out:
 
-
        return num_bde;
 }
 /*
@@ -1828,8 +1879,8 @@ out:
  * field of @lpfc_cmd for device with SLI-4 interface spec.
  *
  * Return codes:
- *     1 - Error
- *     0 - Success
+ *     1 - Error
+ *     0 - Success
  **/
 static int
 lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
@@ -1937,8 +1988,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
  * lpfc_hba struct.
  *
  * Return codes:
- *     1 - Error
- *     0 - Success
+ *     1 - Error
+ *     0 - Success
  **/
 static inline int
 lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
index 049fb9a..7a61455 100644 (file)
@@ -212,7 +212,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
        struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe;
 
        /* If the next EQE is not valid then we are done */
-       if (!bf_get(lpfc_eqe_valid, eqe))
+       if (!bf_get_le32(lpfc_eqe_valid, eqe))
                return NULL;
        /* If the host has not yet processed the next entry then we are done */
        if (((q->hba_index + 1) % q->entry_count) == q->host_index)
@@ -247,7 +247,7 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
        /* while there are valid entries */
        while (q->hba_index != q->host_index) {
                temp_eqe = q->qe[q->host_index].eqe;
-               bf_set(lpfc_eqe_valid, temp_eqe, 0);
+               bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
                released++;
                q->host_index = ((q->host_index + 1) % q->entry_count);
        }
@@ -285,7 +285,7 @@ lpfc_sli4_cq_get(struct lpfc_queue *q)
        struct lpfc_cqe *cqe;
 
        /* If the next CQE is not valid then we are done */
-       if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
+       if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
                return NULL;
        /* If the host has not yet processed the next entry then we are done */
        if (((q->hba_index + 1) % q->entry_count) == q->host_index)
@@ -321,7 +321,7 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
        /* while there are valid entries */
        while (q->hba_index != q->host_index) {
                temp_qe = q->qe[q->host_index].cqe;
-               bf_set(lpfc_cqe_valid, temp_qe, 0);
+               bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
                released++;
                q->host_index = ((q->host_index + 1) % q->entry_count);
        }
@@ -1659,6 +1659,8 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_INIT_VPI:
        case MBX_INIT_VFI:
        case MBX_RESUME_RPI:
+       case MBX_READ_EVENT_LOG_STATUS:
+       case MBX_READ_EVENT_LOG:
                ret = mbxCommand;
                break;
        default:
@@ -4296,7 +4298,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                        "2570 Failed to read FCoE parameters\n");
 
        /* Issue READ_REV to collect vpd and FW information. */
-       vpd_size = PAGE_SIZE;
+       vpd_size = SLI4_PAGE_SIZE;
        vpd = kzalloc(vpd_size, GFP_KERNEL);
        if (!vpd) {
                rc = -ENOMEM;
@@ -4891,9 +4893,34 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
        mb->mbxOwner = OWN_CHIP;
 
        if (psli->sli_flag & LPFC_SLI_ACTIVE) {
-               /* First copy command data to host SLIM area */
+               /* Populate mbox extension offset word. */
+               if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) {
+                       *(((uint32_t *)mb) + pmbox->mbox_offset_word)
+                               = (uint8_t *)phba->mbox_ext
+                                 - (uint8_t *)phba->mbox;
+               }
+
+               /* Copy the mailbox extension data */
+               if (pmbox->in_ext_byte_len && pmbox->context2) {
+                       lpfc_sli_pcimem_bcopy(pmbox->context2,
+                               (uint8_t *)phba->mbox_ext,
+                               pmbox->in_ext_byte_len);
+               }
+               /* Copy command data to host SLIM area */
                lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
        } else {
+               /* Populate mbox extension offset word. */
+               if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len)
+                       *(((uint32_t *)mb) + pmbox->mbox_offset_word)
+                               = MAILBOX_HBA_EXT_OFFSET;
+
+               /* Copy the mailbox extension data */
+               if (pmbox->in_ext_byte_len && pmbox->context2) {
+                       lpfc_memcpy_to_slim(phba->MBslimaddr +
+                               MAILBOX_HBA_EXT_OFFSET,
+                               pmbox->context2, pmbox->in_ext_byte_len);
+
+               }
                if (mb->mbxCommand == MBX_CONFIG_PORT) {
                        /* copy command data into host mbox for cmpl */
                        lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
@@ -5003,15 +5030,22 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
                if (psli->sli_flag & LPFC_SLI_ACTIVE) {
                        /* copy results back to user */
                        lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
+                       /* Copy the mailbox extension data */
+                       if (pmbox->out_ext_byte_len && pmbox->context2) {
+                               lpfc_sli_pcimem_bcopy(phba->mbox_ext,
+                                                     pmbox->context2,
+                                                     pmbox->out_ext_byte_len);
+                       }
                } else {
                        /* First copy command data */
                        lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
                                                        MAILBOX_CMD_SIZE);
-                       if ((mb->mbxCommand == MBX_DUMP_MEMORY) &&
-                               pmbox->context2) {
-                               lpfc_memcpy_from_slim((void *)pmbox->context2,
-                                     phba->MBslimaddr + DMP_RSP_OFFSET,
-                                                     mb->un.varDmp.word_cnt);
+                       /* Copy the mailbox extension data */
+                       if (pmbox->out_ext_byte_len && pmbox->context2) {
+                               lpfc_memcpy_from_slim(pmbox->context2,
+                                       phba->MBslimaddr +
+                                       MAILBOX_HBA_EXT_OFFSET,
+                                       pmbox->out_ext_byte_len);
                        }
                }
 
@@ -7104,13 +7138,11 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                         */
                        list_del_init(&abort_iocb->list);
                        pring->txcmplq_cnt--;
-                       spin_unlock_irq(&phba->hbalock);
 
                        /* Firmware could still be in progress of DMAing
                         * payload, so don't free data buffer till after
                         * a hbeat.
                         */
-                       spin_lock_irq(&phba->hbalock);
                        abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
                        abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
                        spin_unlock_irq(&phba->hbalock);
@@ -7118,7 +7150,8 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
                        abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED;
                        (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
-               }
+               } else
+                       spin_unlock_irq(&phba->hbalock);
        }
 
        lpfc_sli_release_iocbq(phba, cmdiocb);
@@ -8133,6 +8166,12 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id)
                                if (pmb->mbox_cmpl) {
                                        lpfc_sli_pcimem_bcopy(mbox, pmbox,
                                                        MAILBOX_CMD_SIZE);
+                                       if (pmb->out_ext_byte_len &&
+                                               pmb->context2)
+                                               lpfc_sli_pcimem_bcopy(
+                                               phba->mbox_ext,
+                                               pmb->context2,
+                                               pmb->out_ext_byte_len);
                                }
                                if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
                                        pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
@@ -8983,17 +9022,17 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
        int ecount = 0;
        uint16_t cqid;
 
-       if (bf_get(lpfc_eqe_major_code, eqe) != 0) {
+       if (bf_get_le32(lpfc_eqe_major_code, eqe) != 0) {
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                "0359 Not a valid slow-path completion "
                                "event: majorcode=x%x, minorcode=x%x\n",
-                               bf_get(lpfc_eqe_major_code, eqe),
-                               bf_get(lpfc_eqe_minor_code, eqe));
+                               bf_get_le32(lpfc_eqe_major_code, eqe),
+                               bf_get_le32(lpfc_eqe_minor_code, eqe));
                return;
        }
 
        /* Get the reference to the corresponding CQ */
-       cqid = bf_get(lpfc_eqe_resource_id, eqe);
+       cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
 
        /* Search for completion queue pointer matching this cqid */
        speq = phba->sli4_hba.sp_eq;
@@ -9221,12 +9260,12 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
        uint16_t cqid;
        int ecount = 0;
 
-       if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0)) {
+       if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                "0366 Not a valid fast-path completion "
                                "event: majorcode=x%x, minorcode=x%x\n",
-                               bf_get(lpfc_eqe_major_code, eqe),
-                               bf_get(lpfc_eqe_minor_code, eqe));
+                               bf_get_le32(lpfc_eqe_major_code, eqe),
+                               bf_get_le32(lpfc_eqe_minor_code, eqe));
                return;
        }
 
@@ -9239,7 +9278,7 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
        }
 
        /* Get the reference to the corresponding CQ */
-       cqid = bf_get(lpfc_eqe_resource_id, eqe);
+       cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
        if (unlikely(cqid != cq->queue_id)) {
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
                                "0368 Miss-matched fast-path completion "
@@ -9506,7 +9545,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
        while (!list_empty(&queue->page_list)) {
                list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
                                 list);
-               dma_free_coherent(&queue->phba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&queue->phba->pcidev->dev, SLI4_PAGE_SIZE,
                                  dmabuf->virt, dmabuf->phys);
                kfree(dmabuf);
        }
@@ -9532,13 +9571,17 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
        struct lpfc_dmabuf *dmabuf;
        int x, total_qe_count;
        void *dma_pointer;
+       uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
 
+       if (!phba->sli4_hba.pc_sli4_params.supported)
+               hw_page_size = SLI4_PAGE_SIZE;
 
        queue = kzalloc(sizeof(struct lpfc_queue) +
                        (sizeof(union sli4_qe) * entry_count), GFP_KERNEL);
        if (!queue)
                return NULL;
-       queue->page_count = (PAGE_ALIGN(entry_size * entry_count))/PAGE_SIZE;
+       queue->page_count = (ALIGN(entry_size * entry_count,
+                       hw_page_size))/hw_page_size;
        INIT_LIST_HEAD(&queue->list);
        INIT_LIST_HEAD(&queue->page_list);
        INIT_LIST_HEAD(&queue->child_list);
@@ -9547,19 +9590,19 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
                if (!dmabuf)
                        goto out_fail;
                dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
-                                                 PAGE_SIZE, &dmabuf->phys,
+                                                 hw_page_size, &dmabuf->phys,
                                                  GFP_KERNEL);
                if (!dmabuf->virt) {
                        kfree(dmabuf);
                        goto out_fail;
                }
-               memset(dmabuf->virt, 0, PAGE_SIZE);
+               memset(dmabuf->virt, 0, hw_page_size);
                dmabuf->buffer_tag = x;
                list_add_tail(&dmabuf->list, &queue->page_list);
                /* initialize queue's entry array */
                dma_pointer = dmabuf->virt;
                for (; total_qe_count < entry_count &&
-                    dma_pointer < (PAGE_SIZE + dmabuf->virt);
+                    dma_pointer < (hw_page_size + dmabuf->virt);
                     total_qe_count++, dma_pointer += entry_size) {
                        queue->qe[total_qe_count].address = dma_pointer;
                }
@@ -9604,6 +9647,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
        uint16_t dmult;
+       uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+       if (!phba->sli4_hba.pc_sli4_params.supported)
+               hw_page_size = SLI4_PAGE_SIZE;
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox)
@@ -9653,6 +9700,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
                break;
        }
        list_for_each_entry(dmabuf, &eq->page_list, list) {
+               memset(dmabuf->virt, 0, hw_page_size);
                eq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
                                        putPaddrLow(dmabuf->phys);
                eq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -9715,6 +9763,11 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
        int rc, length, status = 0;
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
+       uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+       if (!phba->sli4_hba.pc_sli4_params.supported)
+               hw_page_size = SLI4_PAGE_SIZE;
+
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox)
@@ -9752,6 +9805,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
                break;
        }
        list_for_each_entry(dmabuf, &cq->page_list, list) {
+               memset(dmabuf->virt, 0, hw_page_size);
                cq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
                                        putPaddrLow(dmabuf->phys);
                cq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -9791,9 +9845,70 @@ out:
 }
 
 /**
+ * lpfc_mq_create_fb_init - Send MCC_CREATE without async events registration
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @mq: The queue structure to use to create the mailbox queue.
+ * @mbox: An allocated pointer to type LPFC_MBOXQ_t
+ * @cq: The completion queue to associate with this cq.
+ *
+ * This function provides failback (fb) functionality when the
+ * mq_create_ext fails on older FW generations.  It's purpose is identical
+ * to mq_create_ext otherwise.
+ *
+ * This routine cannot fail as all attributes were previously accessed and
+ * initialized in mq_create_ext.
+ **/
+static void
+lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq,
+                      LPFC_MBOXQ_t *mbox, struct lpfc_queue *cq)
+{
+       struct lpfc_mbx_mq_create *mq_create;
+       struct lpfc_dmabuf *dmabuf;
+       int length;
+
+       length = (sizeof(struct lpfc_mbx_mq_create) -
+                 sizeof(struct lpfc_sli4_cfg_mhdr));
+       lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                        LPFC_MBOX_OPCODE_MQ_CREATE,
+                        length, LPFC_SLI4_MBX_EMBED);
+       mq_create = &mbox->u.mqe.un.mq_create;
+       bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
+              mq->page_count);
+       bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
+              cq->queue_id);
+       bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
+       switch (mq->entry_count) {
+       case 16:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_16);
+               break;
+       case 32:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_32);
+               break;
+       case 64:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_64);
+               break;
+       case 128:
+               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+                      LPFC_MQ_CNT_128);
+               break;
+       }
+       list_for_each_entry(dmabuf, &mq->page_list, list) {
+               mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+                       putPaddrLow(dmabuf->phys);
+               mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+                       putPaddrHigh(dmabuf->phys);
+       }
+}
+
+/**
  * lpfc_mq_create - Create a mailbox Queue on the HBA
  * @phba: HBA structure that indicates port to create a queue on.
  * @mq: The queue structure to use to create the mailbox queue.
+ * @cq: The completion queue to associate with this cq.
+ * @subtype: The queue's subtype.
  *
  * This function creates a mailbox queue, as detailed in @mq, on a port,
  * described by @phba by sending a MQ_CREATE mailbox command to the HBA.
@@ -9809,31 +9924,43 @@ out:
  * memory this function will return ENOMEM. If the queue create mailbox command
  * fails this function will return ENXIO.
  **/
-uint32_t
+int32_t
 lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
               struct lpfc_queue *cq, uint32_t subtype)
 {
        struct lpfc_mbx_mq_create *mq_create;
+       struct lpfc_mbx_mq_create_ext *mq_create_ext;
        struct lpfc_dmabuf *dmabuf;
        LPFC_MBOXQ_t *mbox;
        int rc, length, status = 0;
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
+       uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+       if (!phba->sli4_hba.pc_sli4_params.supported)
+               hw_page_size = SLI4_PAGE_SIZE;
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox)
                return -ENOMEM;
-       length = (sizeof(struct lpfc_mbx_mq_create) -
+       length = (sizeof(struct lpfc_mbx_mq_create_ext) -
                  sizeof(struct lpfc_sli4_cfg_mhdr));
        lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
-                        LPFC_MBOX_OPCODE_MQ_CREATE,
+                        LPFC_MBOX_OPCODE_MQ_CREATE_EXT,
                         length, LPFC_SLI4_MBX_EMBED);
-       mq_create = &mbox->u.mqe.un.mq_create;
-       bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
+
+       mq_create_ext = &mbox->u.mqe.un.mq_create_ext;
+       bf_set(lpfc_mbx_mq_create_ext_num_pages, &mq_create_ext->u.request,
                    mq->page_count);
-       bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
-                   cq->queue_id);
-       bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
+       bf_set(lpfc_mbx_mq_create_ext_async_evt_link, &mq_create_ext->u.request,
+              1);
+       bf_set(lpfc_mbx_mq_create_ext_async_evt_fcfste,
+              &mq_create_ext->u.request, 1);
+       bf_set(lpfc_mbx_mq_create_ext_async_evt_group5,
+              &mq_create_ext->u.request, 1);
+       bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context,
+              cq->queue_id);
+       bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1);
        switch (mq->entry_count) {
        default:
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@@ -9843,31 +9970,47 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
                        return -EINVAL;
                /* otherwise default to smallest count (drop through) */
        case 16:
-               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+               bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
                       LPFC_MQ_CNT_16);
                break;
        case 32:
-               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+               bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
                       LPFC_MQ_CNT_32);
                break;
        case 64:
-               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+               bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
                       LPFC_MQ_CNT_64);
                break;
        case 128:
-               bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+               bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
                       LPFC_MQ_CNT_128);
                break;
        }
        list_for_each_entry(dmabuf, &mq->page_list, list) {
-               mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+               memset(dmabuf->virt, 0, hw_page_size);
+               mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_lo =
                                        putPaddrLow(dmabuf->phys);
-               mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+               mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_hi =
                                        putPaddrHigh(dmabuf->phys);
        }
        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr;
+       mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
+                             &mq_create_ext->u.response);
+       if (rc != MBX_SUCCESS) {
+               lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+                               "2795 MQ_CREATE_EXT failed with "
+                               "status x%x. Failback to MQ_CREATE.\n",
+                               rc);
+               lpfc_mq_create_fb_init(phba, mq, mbox, cq);
+               mq_create = &mbox->u.mqe.un.mq_create;
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+               shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
+               mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
+                                     &mq_create->u.response);
+       }
+
        /* The IOCTL status is embedded in the mailbox subheader. */
-       shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
        shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
        shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
        if (shdr_status || shdr_add_status || rc) {
@@ -9878,7 +10021,6 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
                status = -ENXIO;
                goto out;
        }
-       mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create->u.response);
        if (mq->queue_id == 0xFFFF) {
                status = -ENXIO;
                goto out;
@@ -9927,6 +10069,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
        int rc, length, status = 0;
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
+       uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+       if (!phba->sli4_hba.pc_sli4_params.supported)
+               hw_page_size = SLI4_PAGE_SIZE;
 
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        if (!mbox)
@@ -9942,6 +10088,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
        bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
                    cq->queue_id);
        list_for_each_entry(dmabuf, &wq->page_list, list) {
+               memset(dmabuf->virt, 0, hw_page_size);
                wq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
                                        putPaddrLow(dmabuf->phys);
                wq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -10010,6 +10157,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
        int rc, length, status = 0;
        uint32_t shdr_status, shdr_add_status;
        union lpfc_sli4_cfg_shdr *shdr;
+       uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+       if (!phba->sli4_hba.pc_sli4_params.supported)
+               hw_page_size = SLI4_PAGE_SIZE;
 
        if (hrq->entry_count != drq->entry_count)
                return -EINVAL;
@@ -10054,6 +10205,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
        bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
               LPFC_HDR_BUF_SIZE);
        list_for_each_entry(dmabuf, &hrq->page_list, list) {
+               memset(dmabuf->virt, 0, hw_page_size);
                rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
                                        putPaddrLow(dmabuf->phys);
                rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -10626,7 +10778,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
 
        reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
                 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
-       if (reqlen > PAGE_SIZE) {
+       if (reqlen > SLI4_PAGE_SIZE) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
                                "2559 Block sgl registration required DMA "
                                "size (%d) great than a page\n", reqlen);
@@ -10732,7 +10884,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
        /* Calculate the requested length of the dma memory */
        reqlen = cnt * sizeof(struct sgl_page_pairs) +
                 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
-       if (reqlen > PAGE_SIZE) {
+       if (reqlen > SLI4_PAGE_SIZE) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
                                "0217 Block sgl registration required DMA "
                                "size (%d) great than a page\n", reqlen);
@@ -11568,8 +11720,8 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
  *
  * This routine is invoked to post rpi header templates to the
  * HBA consistent with the SLI-4 interface spec.  This routine
- * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
+ * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
+ * SLI4_PAGE_SIZE modulo 64 rpi context headers.
  *
  * This routine does not require any locks.  It's usage is expected
  * to be driver load or reset recovery when the driver is
@@ -11672,8 +11824,8 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
  *
  * This routine is invoked to post rpi header templates to the
  * HBA consistent with the SLI-4 interface spec.  This routine
- * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
+ * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
+ * SLI4_PAGE_SIZE modulo 64 rpi context headers.
  *
  * Returns
  *     A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
@@ -12040,9 +12192,11 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
                phba->hba_flag |= FCF_DISC_INPROGRESS;
                spin_unlock_irq(&phba->hbalock);
                /* Reset FCF round robin index bmask for new scan */
-               if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
+               if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) {
                        memset(phba->fcf.fcf_rr_bmask, 0,
                               sizeof(*phba->fcf.fcf_rr_bmask));
+                       phba->fcf.eligible_fcf_cnt = 0;
+               }
                error = 0;
        }
 fail_fcf_scan:
@@ -12507,6 +12661,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
        struct lpfc_hba *phba = vport->phba;
        LPFC_MBOXQ_t *mb, *nextmb;
        struct lpfc_dmabuf *mp;
+       struct lpfc_nodelist *ndlp;
 
        spin_lock_irq(&phba->hbalock);
        list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
@@ -12523,6 +12678,11 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
                                __lpfc_mbuf_free(phba, mp->virt, mp->phys);
                                kfree(mp);
                        }
+                       ndlp = (struct lpfc_nodelist *) mb->context2;
+                       if (ndlp) {
+                               lpfc_nlp_put(ndlp);
+                               mb->context2 = NULL;
+                       }
                }
                list_del(&mb->list);
                mempool_free(mb, phba->mbox_mem_pool);
@@ -12532,6 +12692,15 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
                if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) ||
                        (mb->u.mb.mbxCommand == MBX_REG_VPI))
                        mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+                       ndlp = (struct lpfc_nodelist *) mb->context2;
+                       if (ndlp) {
+                               lpfc_nlp_put(ndlp);
+                               mb->context2 = NULL;
+                       }
+                       /* Unregister the RPI when mailbox complete */
+                       mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
+               }
        }
        spin_unlock_irq(&phba->hbalock);
 }
index b4a639c..e379215 100644 (file)
@@ -36,6 +36,7 @@ struct lpfc_cq_event {
                struct lpfc_acqe_link           acqe_link;
                struct lpfc_acqe_fcoe           acqe_fcoe;
                struct lpfc_acqe_dcbx           acqe_dcbx;
+               struct lpfc_acqe_grp5           acqe_grp5;
                struct lpfc_rcqe                rcqe_cmpl;
                struct sli4_wcqe_xri_aborted    wcqe_axri;
                struct lpfc_wcqe_complete       wcqe_cmpl;
@@ -110,6 +111,9 @@ typedef struct lpfcMboxq {
 
        void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
        uint8_t mbox_flag;
+       uint16_t in_ext_byte_len;
+       uint16_t out_ext_byte_len;
+       uint8_t  mbox_offset_word;
        struct lpfc_mcqe mcqe;
        struct lpfc_mbx_nembed_sge_virt *sge_array;
 } LPFC_MBOXQ_t;
index 4a35e7b..58bb4c8 100644 (file)
@@ -162,6 +162,7 @@ struct lpfc_fcf {
 #define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */
        uint32_t addr_mode;
        uint16_t fcf_rr_init_indx;
+       uint32_t eligible_fcf_cnt;
        struct lpfc_fcf_rec current_rec;
        struct lpfc_fcf_rec failover_rec;
        struct timer_list redisc_wait;
@@ -492,8 +493,8 @@ void lpfc_sli4_queue_free(struct lpfc_queue *);
 uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t);
 uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *,
                        struct lpfc_queue *, uint32_t, uint32_t);
-uint32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
-                       struct lpfc_queue *, uint32_t);
+int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
+                      struct lpfc_queue *, uint32_t);
 uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *,
                        struct lpfc_queue *, uint32_t);
 uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *,
index 013deec..5294c3a 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.10"
+#define LPFC_DRIVER_VERSION "8.3.12"
 #define LPFC_DRIVER_NAME               "lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME    "lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME    "lpfc:fp"
index ffd575c..ab91359 100644 (file)
@@ -763,7 +763,9 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
        spin_lock_irq(&phba->hbalock);
        list_for_each_entry(port_iterator, &phba->port_list, listentry) {
                if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) {
-                       lpfc_printf_vlog(port_iterator, KERN_WARNING, LOG_VPORT,
+                       if (!(port_iterator->load_flag & FC_UNLOADING))
+                               lpfc_printf_vlog(port_iterator, KERN_ERR,
+                                        LOG_VPORT,
                                         "1801 Create vport work array FAILED: "
                                         "cannot do scsi_host_get\n");
                        continue;
index ba8e128..bbb7e4b 100644 (file)
@@ -2,7 +2,7 @@
 # Kernel configuration file for the MPT2SAS
 #
 # This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2009  LSI Corporation
+# Copyright (C) 2007-2010  LSI Corporation
 #  (mailto:DL-MPTFusionLinux@lsi.com)
 
 # This program is free software; you can redistribute it and/or
index 9958d84..dada0a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2.h
index cf0ac9f..d4e9d6f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_cnfg.h
index c4adf76..bd6c92b 100644 (file)
@@ -2,7 +2,7 @@
  Fusion-MPT MPI 2.0 Header File Change History
  ==============================
 
- Copyright (c) 2000-2009 LSI Corporation.
+ Copyright (c) 2000-2010 LSI Corporation.
 
  ---------------------------------------
  Header Set Release Version:    02.00.14
index 6541945..220bf65 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_init.h
index 7549384..f18f114 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_ioc.h
index 73fcdbf..686b09b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_tool.h
index 88e6eeb..b830d61 100644 (file)
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -58,6 +58,7 @@
 #include <linux/sort.h>
 #include <linux/io.h>
 #include <linux/time.h>
+#include <linux/aer.h>
 
 #include "mpt2sas_base.h"
 
@@ -285,6 +286,9 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
            request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
                return;
 
+       if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+               return;
+
        switch (ioc_status) {
 
 /****************************************************************************
@@ -517,8 +521,18 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
                desc = "IR Operation Status";
                break;
        case MPI2_EVENT_SAS_DISCOVERY:
-               desc =  "Discovery";
-               break;
+       {
+               Mpi2EventDataSasDiscovery_t *event_data =
+                   (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData;
+               printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name,
+                   (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
+                   "start" : "stop");
+               if (event_data->DiscoveryStatus)
+                       printk("discovery_status(0x%08x)",
+                           le32_to_cpu(event_data->DiscoveryStatus));
+                       printk("\n");
+               return;
+       }
        case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
                desc = "SAS Broadcast Primitive";
                break;
@@ -1243,6 +1257,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
                goto out_fail;
        }
 
+       /* AER (Advanced Error Reporting) hooks */
+       pci_enable_pcie_error_reporting(pdev);
+
        pci_set_master(pdev);
 
        if (_base_config_dma_addressing(ioc, pdev) != 0) {
@@ -1253,7 +1270,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
        }
 
        for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) {
-               if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
+               if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
                        if (pio_sz)
                                continue;
                        pio_chip = (u64)pci_resource_start(pdev, i);
@@ -1261,15 +1278,18 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
                } else {
                        if (memap_sz)
                                continue;
-                       ioc->chip_phys = pci_resource_start(pdev, i);
-                       chip_phys = (u64)ioc->chip_phys;
-                       memap_sz = pci_resource_len(pdev, i);
-                       ioc->chip = ioremap(ioc->chip_phys, memap_sz);
-                       if (ioc->chip == NULL) {
-                               printk(MPT2SAS_ERR_FMT "unable to map adapter "
-                                   "memory!\n", ioc->name);
-                               r = -EINVAL;
-                               goto out_fail;
+                       /* verify memory resource is valid before using */
+                       if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+                               ioc->chip_phys = pci_resource_start(pdev, i);
+                               chip_phys = (u64)ioc->chip_phys;
+                               memap_sz = pci_resource_len(pdev, i);
+                               ioc->chip = ioremap(ioc->chip_phys, memap_sz);
+                               if (ioc->chip == NULL) {
+                                       printk(MPT2SAS_ERR_FMT "unable to map "
+                                           "adapter memory!\n", ioc->name);
+                                       r = -EINVAL;
+                                       goto out_fail;
+                               }
                        }
                }
        }
@@ -1295,6 +1315,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
        ioc->chip_phys = 0;
        ioc->pci_irq = -1;
        pci_release_selected_regions(ioc->pdev, ioc->bars);
+       pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
        return r;
 }
@@ -1898,7 +1919,10 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
                    ioc->config_page, ioc->config_page_dma);
        }
 
-       kfree(ioc->scsi_lookup);
+       if (ioc->scsi_lookup) {
+               free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages);
+               ioc->scsi_lookup = NULL;
+       }
        kfree(ioc->hpr_lookup);
        kfree(ioc->internal_lookup);
 }
@@ -2110,11 +2134,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
            ioc->name, (unsigned long long) ioc->request_dma));
        total_sz += sz;
 
-       ioc->scsi_lookup = kcalloc(ioc->scsiio_depth,
-           sizeof(struct request_tracker), GFP_KERNEL);
+       sz = ioc->scsiio_depth * sizeof(struct request_tracker);
+       ioc->scsi_lookup_pages = get_order(sz);
+       ioc->scsi_lookup = (struct request_tracker *)__get_free_pages(
+           GFP_KERNEL, ioc->scsi_lookup_pages);
        if (!ioc->scsi_lookup) {
-               printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
-                   ioc->name);
+               printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, "
+                   "sz(%d)\n", ioc->name, (int)sz);
                goto out;
        }
 
@@ -3006,8 +3032,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
         * since epoch ~ midnight January 1, 1970.
         */
        do_gettimeofday(&current_time);
-       mpi_request.TimeStamp = (current_time.tv_sec * 1000) +
-           (current_time.tv_usec >> 3);
+       mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 +
+           (current_time.tv_usec / 1000));
 
        if (ioc->logging_level & MPT_DEBUG_INIT) {
                u32 *mfp;
@@ -3179,7 +3205,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
        mpi_request->VP_ID = 0;
        for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
                mpi_request->EventMasks[i] =
-                   le32_to_cpu(ioc->event_masks[i]);
+                   cpu_to_le32(ioc->event_masks[i]);
        mpt2sas_base_put_smid_default(ioc, smid);
        init_completion(&ioc->base_cmds.done);
        timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
@@ -3516,7 +3542,9 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
            __func__));
 
        _base_mask_interrupts(ioc);
+       ioc->shost_recovery = 1;
        _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+       ioc->shost_recovery = 0;
        if (ioc->pci_irq) {
                synchronize_irq(pdev->irq);
                free_irq(ioc->pci_irq, ioc);
@@ -3527,6 +3555,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
        ioc->pci_irq = -1;
        ioc->chip_phys = 0;
        pci_release_selected_regions(ioc->pdev, ioc->bars);
+       pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
        return;
 }
@@ -3560,8 +3589,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 
        ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
            sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
-       if (!ioc->pfacts)
+       if (!ioc->pfacts) {
+               r = -ENOMEM;
                goto out_free_resources;
+       }
 
        for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
                r = _base_get_port_facts(ioc, i, CAN_SLEEP);
@@ -3607,6 +3638,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
        ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
        mutex_init(&ioc->ctl_cmds.mutex);
 
+       if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
+           !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
+           !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) {
+               r = -ENOMEM;
+               goto out_free_resources;
+       }
+
+       init_completion(&ioc->shost_recovery_done);
+
        for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
                ioc->event_masks[i] = -1;
 
@@ -3639,6 +3679,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
        pci_set_drvdata(ioc->pdev, NULL);
        kfree(ioc->tm_cmds.reply);
        kfree(ioc->transport_cmds.reply);
+       kfree(ioc->scsih_cmds.reply);
        kfree(ioc->config_cmds.reply);
        kfree(ioc->base_cmds.reply);
        kfree(ioc->ctl_cmds.reply);
@@ -3646,6 +3687,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
        ioc->ctl_cmds.reply = NULL;
        ioc->base_cmds.reply = NULL;
        ioc->tm_cmds.reply = NULL;
+       ioc->scsih_cmds.reply = NULL;
        ioc->transport_cmds.reply = NULL;
        ioc->config_cmds.reply = NULL;
        ioc->pfacts = NULL;
@@ -3675,6 +3717,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
        kfree(ioc->base_cmds.reply);
        kfree(ioc->tm_cmds.reply);
        kfree(ioc->transport_cmds.reply);
+       kfree(ioc->scsih_cmds.reply);
        kfree(ioc->config_cmds.reply);
 }
 
@@ -3811,9 +3854,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 
        spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
        ioc->shost_recovery = 0;
+       complete(&ioc->shost_recovery_done);
        spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
 
-       if (!r)
-               _base_reset_handler(ioc, MPT2_IOC_RUNNING);
        return r;
 }
index e18b054..b4afe43 100644 (file)
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
 #define MPT2SAS_DRIVER_NAME            "mpt2sas"
 #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION    "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION         "04.100.01.00"
-#define MPT2SAS_MAJOR_VERSION          04
+#define MPT2SAS_DRIVER_VERSION         "05.100.00.02"
+#define MPT2SAS_MAJOR_VERSION          05
 #define MPT2SAS_MINOR_VERSION          100
-#define MPT2SAS_BUILD_VERSION          01
-#define MPT2SAS_RELEASE_VERSION                00
+#define MPT2SAS_BUILD_VERSION          00
+#define MPT2SAS_RELEASE_VERSION                02
 
 /*
  * Set MPT2SAS_SG_DEPTH value based on user input.
 #define MPT2_IOC_PRE_RESET             1 /* prior to host reset */
 #define MPT2_IOC_AFTER_RESET           2 /* just after host reset */
 #define MPT2_IOC_DONE_RESET            3 /* links re-initialized */
-#define MPT2_IOC_RUNNING               4 /* shost running */
 
 /*
  * logging format
@@ -260,16 +259,6 @@ struct _internal_cmd {
        u16     smid;
 };
 
-/*
- * SAS Topology Structures
- */
-
-#define MPTSAS_STATE_TR_SEND           0x0001
-#define MPTSAS_STATE_TR_COMPLETE       0x0002
-#define MPTSAS_STATE_CNTRL_SEND                0x0004
-#define MPTSAS_STATE_CNTRL_COMPLETE    0x0008
-
-#define MPT2SAS_REQ_SAS_CNTRL          0x0010
 
 /**
  * struct _sas_device - attached device information
@@ -307,7 +296,6 @@ struct _sas_device {
        u16     slot;
        u8      hidden_raid_component;
        u8      responding;
-       u16     state;
 };
 
 /**
@@ -378,6 +366,7 @@ struct _sas_port {
  * @phy_id: unique phy id
  * @handle: device handle for this phy
  * @attached_handle: device handle for attached device
+ * @phy_belongs_to_port: port has been created for this phy
  */
 struct _sas_phy {
        struct list_head port_siblings;
@@ -387,6 +376,7 @@ struct _sas_phy {
        u8      phy_id;
        u16     handle;
        u16     attached_handle;
+       u8      phy_belongs_to_port;
 };
 
 /**
@@ -603,7 +593,6 @@ struct MPT2SAS_ADAPTER {
        /* fw event handler */
        char            firmware_event_name[20];
        struct workqueue_struct *firmware_event_thread;
-       u8              fw_events_off;
        spinlock_t      fw_event_lock;
        struct list_head fw_event_list;
 
@@ -611,6 +600,7 @@ struct MPT2SAS_ADAPTER {
        int             aen_event_read_flag;
        u8              broadcast_aen_busy;
        u8              shost_recovery;
+       struct completion       shost_recovery_done;
        spinlock_t      ioc_reset_in_progress_lock;
        u8              ioc_link_reset_in_progress;
        u8              ignore_loginfos;
@@ -688,7 +678,8 @@ struct MPT2SAS_ADAPTER {
        dma_addr_t      request_dma;
        u32             request_dma_sz;
        struct request_tracker *scsi_lookup;
-       spinlock_t scsi_lookup_lock;
+       ulong           scsi_lookup_pages;
+       spinlock_t      scsi_lookup_lock;
        struct list_head free_list;
        int             pending_io_count;
        wait_queue_head_t reset_wq;
@@ -700,7 +691,7 @@ struct MPT2SAS_ADAPTER {
        u16             max_sges_in_chain_message;
        u16             chains_needed_per_io;
        u16             chain_offset_value_for_main_message;
-       u16             chain_depth;
+       u32             chain_depth;
 
        /* hi-priority queue */
        u16             hi_priority_smid;
@@ -814,8 +805,9 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
 /* scsih shared API */
 u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
     u32 reply);
-void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
-    u8 type, u16 smid_task, ulong timeout);
+int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+    uint channel, uint id, uint lun, u8 type, u16 smid_task,
+    ulong timeout, struct scsi_cmnd *scmd);
 void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
 void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
 struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
index cf44b35..e762dd3 100644 (file)
@@ -2,7 +2,7 @@
  * This module provides common API for accessing firmware configuration pages
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -1390,12 +1390,12 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
        if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
                goto out;
        for (i = 0; i < config_page->NumElements; i++) {
-               if ((config_page->ConfigElement[i].ElementFlags &
+               if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) &
                    MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) !=
                    MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)
                        continue;
-               if (config_page->ConfigElement[i].PhysDiskDevHandle ==
-                   pd_handle) {
+               if (le16_to_cpu(config_page->ConfigElement[i].
+                   PhysDiskDevHandle) == pd_handle) {
                        *volume_handle = le16_to_cpu(config_page->
                            ConfigElement[i].VolDevHandle);
                        r = 0;
index fa9bf83..d88e975 100644 (file)
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -533,7 +533,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
        if (!found) {
                dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
                    "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
-                   desc, tm_request->DevHandle, lun));
+                   desc, le16_to_cpu(tm_request->DevHandle), lun));
                tm_reply = ioc->ctl_cmds.reply;
                tm_reply->DevHandle = tm_request->DevHandle;
                tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
@@ -551,7 +551,8 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
 
        dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
            "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
-           desc, tm_request->DevHandle, lun, tm_request->TaskMID));
+           desc, le16_to_cpu(tm_request->DevHandle), lun,
+            le16_to_cpu(tm_request->TaskMID)));
        return 0;
 }
 
@@ -647,9 +648,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
 
        if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
            mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
-               if (!mpi_request->FunctionDependent1 ||
-                   mpi_request->FunctionDependent1 >
-                   cpu_to_le16(ioc->facts.MaxDevHandle)) {
+               if (!le16_to_cpu(mpi_request->FunctionDependent1) ||
+                   le16_to_cpu(mpi_request->FunctionDependent1) >
+                   ioc->facts.MaxDevHandle) {
                        ret = -EINVAL;
                        mpt2sas_base_free_smid(ioc, smid);
                        goto out;
@@ -743,8 +744,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
                    mpt2sas_base_get_sense_buffer_dma(ioc, smid);
                priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
                memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
-               mpt2sas_base_put_smid_scsi_io(ioc, smid,
-                   le16_to_cpu(mpi_request->FunctionDependent1));
+               if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
+                       mpt2sas_base_put_smid_scsi_io(ioc, smid,
+                           le16_to_cpu(mpi_request->FunctionDependent1));
+               else
+                       mpt2sas_base_put_smid_default(ioc, smid);
                break;
        }
        case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -752,6 +756,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
                Mpi2SCSITaskManagementRequest_t *tm_request =
                    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
 
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+                   "handle(0x%04x), task_type(0x%02x)\n", ioc->name,
+                   le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
+
                if (tm_request->TaskType ==
                    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
                    tm_request->TaskType ==
@@ -762,7 +770,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
                        }
                }
 
-               mutex_lock(&ioc->tm_cmds.mutex);
                mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
                    tm_request->DevHandle));
                mpt2sas_base_put_smid_hi_priority(ioc, smid);
@@ -818,7 +825,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
        if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
                Mpi2SCSITaskManagementRequest_t *tm_request =
                    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
-               mutex_unlock(&ioc->tm_cmds.mutex);
                mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
                    tm_request->DevHandle));
        } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
@@ -897,14 +903,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
                    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
                        printk(MPT2SAS_INFO_FMT "issue target reset: handle "
                            "= (0x%04x)\n", ioc->name,
-                           mpi_request->FunctionDependent1);
+                           le16_to_cpu(mpi_request->FunctionDependent1));
                        mpt2sas_halt_firmware(ioc);
-                       mutex_lock(&ioc->tm_cmds.mutex);
                        mpt2sas_scsih_issue_tm(ioc,
-                           mpi_request->FunctionDependent1, 0,
-                           MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
+                           le16_to_cpu(mpi_request->FunctionDependent1), 0, 0,
+                           0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10,
+                           NULL);
                        ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-                       mutex_unlock(&ioc->tm_cmds.mutex);
                } else
                        mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
                            FORCE_BIG_HAMMER);
@@ -1373,7 +1378,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
 
        dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
            "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
-           (unsigned long long)request_data_dma, mpi_request->BufferLength));
+           (unsigned long long)request_data_dma,
+           le32_to_cpu(mpi_request->BufferLength)));
 
        for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
                mpi_request->ProductSpecific[i] =
@@ -2334,8 +2340,8 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,
        struct Scsi_Host *shost = class_to_shost(cdev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
 
-       return snprintf(buf, PAGE_SIZE, "%02xh\n",
-           le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
+       return snprintf(buf, PAGE_SIZE, "%08xh\n",
+           le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
 }
 static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
     _ctl_version_nvdata_persistent_show, NULL);
@@ -2354,8 +2360,8 @@ _ctl_version_nvdata_default_show(struct device *cdev,
        struct Scsi_Host *shost = class_to_shost(cdev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
 
-       return snprintf(buf, PAGE_SIZE, "%02xh\n",
-           le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
+       return snprintf(buf, PAGE_SIZE, "%08xh\n",
+           le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
 }
 static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
     _ctl_version_nvdata_default_show, NULL);
index 8a5eeb1..69916e4 100644 (file)
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index 5308a25..3dcddfe 100644 (file)
@@ -2,7 +2,7 @@
  * Logging Support for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index be171ed..c5ff26a 100644 (file)
@@ -2,7 +2,7 @@
  * Scsi Host Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -52,6 +52,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/aer.h>
 #include <linux/raid_class.h>
 #include <linux/slab.h>
 
@@ -109,14 +110,16 @@ struct sense_info {
 };
 
 
+#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
+
 /**
  * struct fw_event_work - firmware event struct
  * @list: link list framework
  * @work: work object (ioc->fault_reset_work_q)
+ * @cancel_pending_work: flag set during reset handling
  * @ioc: per adapter object
  * @VF_ID: virtual function id
  * @VP_ID: virtual port id
- * @host_reset_handling: handling events during host reset
  * @ignore: flag meaning this event has been marked to ignore
  * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
  * @event_data: reply event data payload follows
@@ -125,11 +128,11 @@ struct sense_info {
  */
 struct fw_event_work {
        struct list_head        list;
-       struct work_struct      work;
+       u8                      cancel_pending_work;
+       struct delayed_work     delayed_work;
        struct MPT2SAS_ADAPTER *ioc;
        u8                      VF_ID;
        u8                      VP_ID;
-       u8                      host_reset_handling;
        u8                      ignore;
        u16                     event;
        void                    *event_data;
@@ -482,27 +485,17 @@ struct _sas_device *
 mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
     u64 sas_address)
 {
-       struct _sas_device *sas_device, *r;
+       struct _sas_device *sas_device;
 
-       r = NULL;
-       /* check the sas_device_init_list */
-       list_for_each_entry(sas_device, &ioc->sas_device_init_list,
-           list) {
-               if (sas_device->sas_address != sas_address)
-                       continue;
-               r = sas_device;
-               goto out;
-       }
+       list_for_each_entry(sas_device, &ioc->sas_device_list, list)
+               if (sas_device->sas_address == sas_address)
+                       return sas_device;
 
-       /* then check the sas_device_list */
-       list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
-               if (sas_device->sas_address != sas_address)
-                       continue;
-               r = sas_device;
-               goto out;
-       }
- out:
-       return r;
+       list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
+               if (sas_device->sas_address == sas_address)
+                       return sas_device;
+
+       return NULL;
 }
 
 /**
@@ -517,28 +510,17 @@ mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
 static struct _sas_device *
 _scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
 {
-       struct _sas_device *sas_device, *r;
+       struct _sas_device *sas_device;
 
-       r = NULL;
-       if (ioc->wait_for_port_enable_to_complete) {
-               list_for_each_entry(sas_device, &ioc->sas_device_init_list,
-                   list) {
-                       if (sas_device->handle != handle)
-                               continue;
-                       r = sas_device;
-                       goto out;
-               }
-       } else {
-               list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
-                       if (sas_device->handle != handle)
-                               continue;
-                       r = sas_device;
-                       goto out;
-               }
-       }
+       list_for_each_entry(sas_device, &ioc->sas_device_list, list)
+               if (sas_device->handle == handle)
+                       return sas_device;
 
- out:
-       return r;
+       list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
+               if (sas_device->handle == handle)
+                       return sas_device;
+
+       return NULL;
 }
 
 /**
@@ -555,10 +537,15 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
 {
        unsigned long flags;
 
+       if (!sas_device)
+               return;
+
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
-       list_del(&sas_device->list);
-       memset(sas_device, 0, sizeof(struct _sas_device));
-       kfree(sas_device);
+       if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+           sas_device->sas_address)) {
+               list_del(&sas_device->list);
+               kfree(sas_device);
+       }
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 }
 
@@ -988,7 +975,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
        u32 chain_offset;
        u32 chain_length;
        u32 chain_flags;
-       u32 sges_left;
+       int sges_left;
        u32 sges_in_segment;
        u32 sgl_flags;
        u32 sgl_flags_last_element;
@@ -1009,7 +996,7 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
 
        sg_scmd = scsi_sglist(scmd);
        sges_left = scsi_dma_map(scmd);
-       if (!sges_left) {
+       if (sges_left < 0) {
                sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
                " failed: request for %d bytes!\n", scsi_bufflen(scmd));
                return -ENOMEM;
@@ -1395,7 +1382,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
        }
 
        flags = le16_to_cpu(sas_device_pg0.Flags);
-       device_info = le16_to_cpu(sas_device_pg0.DeviceInfo);
+       device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
 
        sdev_printk(KERN_INFO, sdev,
            "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
@@ -1963,65 +1950,78 @@ mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
        }
 }
 
+
 /**
  * mpt2sas_scsih_issue_tm - main routine for sending tm requests
  * @ioc: per adapter struct
  * @device_handle: device handle
+ * @channel: the channel assigned by the OS
+ * @id: the id assigned by the OS
  * @lun: lun number
  * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
  * @smid_task: smid assigned to the task
  * @timeout: timeout in seconds
- * Context: The calling function needs to acquire the tm_cmds.mutex
+ * Context: user
  *
  * A generic API for sending task management requests to firmware.
  *
- * The ioc->tm_cmds.status flag should be MPT2_CMD_NOT_USED before calling
- * this API.
- *
  * The callback index is set inside `ioc->tm_cb_idx`.
  *
- * Return nothing.
+ * Return SUCCESS or FAILED.
  */
-void
-mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
-    u8 type, u16 smid_task, ulong timeout)
+int
+mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
+    uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
+    struct scsi_cmnd *scmd)
 {
        Mpi2SCSITaskManagementRequest_t *mpi_request;
        Mpi2SCSITaskManagementReply_t *mpi_reply;
        u16 smid = 0;
        u32 ioc_state;
        unsigned long timeleft;
+       struct scsi_cmnd *scmd_lookup;
+       int rc;
 
+       mutex_lock(&ioc->tm_cmds.mutex);
        if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
                printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
                    __func__, ioc->name);
-               return;
+               rc = FAILED;
+               goto err_out;
        }
 
-       if (ioc->shost_recovery) {
+       if (ioc->shost_recovery || ioc->remove_host) {
                printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
                    __func__, ioc->name);
-               return;
+               rc = FAILED;
+               goto err_out;
        }
 
        ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
        if (ioc_state & MPI2_DOORBELL_USED) {
                dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
                    "active!\n", ioc->name));
-               goto issue_host_reset;
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+               rc = SUCCESS;
+               goto err_out;
        }
 
        if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
                mpt2sas_base_fault_info(ioc, ioc_state &
                    MPI2_DOORBELL_DATA_MASK);
-               goto issue_host_reset;
+               mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                   FORCE_BIG_HAMMER);
+               rc = SUCCESS;
+               goto err_out;
        }
 
        smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
        if (!smid) {
                printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
                    ioc->name, __func__);
-               return;
+               rc = FAILED;
+               goto err_out;
        }
 
        dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
@@ -2035,21 +2035,24 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
        mpi_request->DevHandle = cpu_to_le16(handle);
        mpi_request->TaskType = type;
        mpi_request->TaskMID = cpu_to_le16(smid_task);
-       mpi_request->VP_ID = 0;  /* TODO */
-       mpi_request->VF_ID = 0;
        int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
        mpt2sas_scsih_set_tm_flag(ioc, handle);
        init_completion(&ioc->tm_cmds.done);
        mpt2sas_base_put_smid_hi_priority(ioc, smid);
        timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
-       mpt2sas_scsih_clear_tm_flag(ioc, handle);
        if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
                printk(MPT2SAS_ERR_FMT "%s: timeout\n",
                    ioc->name, __func__);
                _debug_dump_mf(mpi_request,
                    sizeof(Mpi2SCSITaskManagementRequest_t)/4);
-               if (!(ioc->tm_cmds.status & MPT2_CMD_RESET))
-                       goto issue_host_reset;
+               if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
+                       mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+                           FORCE_BIG_HAMMER);
+                       rc = SUCCESS;
+                       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+                       mpt2sas_scsih_clear_tm_flag(ioc, handle);
+                       goto err_out;
+               }
        }
 
        if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
@@ -2059,12 +2062,57 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
                    ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
                    le32_to_cpu(mpi_reply->IOCLogInfo),
                    le32_to_cpu(mpi_reply->TerminationCount)));
-               if (ioc->logging_level & MPT_DEBUG_TM)
+               if (ioc->logging_level & MPT_DEBUG_TM) {
                        _scsih_response_code(ioc, mpi_reply->ResponseCode);
+                       if (mpi_reply->IOCStatus)
+                               _debug_dump_mf(mpi_request,
+                                   sizeof(Mpi2SCSITaskManagementRequest_t)/4);
+               }
        }
-       return;
- issue_host_reset:
-       mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER);
+
+       /* sanity check:
+        * Check to see the commands were terminated.
+        * This is only needed for eh callbacks, hence the scmd check.
+        */
+       rc = FAILED;
+       if (scmd == NULL)
+               goto bypass_sanity_checks;
+       switch (type) {
+       case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+               scmd_lookup = _scsih_scsi_lookup_get(ioc, smid_task);
+               if (scmd_lookup && (scmd_lookup->serial_number ==
+                   scmd->serial_number))
+                       rc = FAILED;
+               else
+                       rc = SUCCESS;
+               break;
+
+       case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+               if (_scsih_scsi_lookup_find_by_target(ioc, id, channel))
+                       rc = FAILED;
+               else
+                       rc = SUCCESS;
+               break;
+
+       case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
+               if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
+                       rc = FAILED;
+               else
+                       rc = SUCCESS;
+               break;
+       }
+
+ bypass_sanity_checks:
+
+       mpt2sas_scsih_clear_tm_flag(ioc, handle);
+       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->tm_cmds.mutex);
+
+       return rc;
+
+ err_out:
+       mutex_unlock(&ioc->tm_cmds.mutex);
+       return rc;
 }
 
 /**
@@ -2081,7 +2129,6 @@ _scsih_abort(struct scsi_cmnd *scmd)
        u16 smid;
        u16 handle;
        int r;
-       struct scsi_cmnd *scmd_lookup;
 
        printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
            ioc->name, scmd);
@@ -2116,19 +2163,10 @@ _scsih_abort(struct scsi_cmnd *scmd)
 
        mpt2sas_halt_firmware(ioc);
 
-       mutex_lock(&ioc->tm_cmds.mutex);
        handle = sas_device_priv_data->sas_target->handle;
-       mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun,
-           MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30);
-
-       /* sanity check - see whether command actually completed */
-       scmd_lookup = _scsih_scsi_lookup_get(ioc, smid);
-       if (scmd_lookup && (scmd_lookup->serial_number == scmd->serial_number))
-               r = FAILED;
-       else
-               r = SUCCESS;
-       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-       mutex_unlock(&ioc->tm_cmds.mutex);
+       r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
+           scmd->device->id, scmd->device->lun,
+           MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);
 
  out:
        printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
@@ -2185,22 +2223,9 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
                goto out;
        }
 
-       mutex_lock(&ioc->tm_cmds.mutex);
-       mpt2sas_scsih_issue_tm(ioc, handle, 0,
-           MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, scmd->device->lun,
-           30);
-
-       /*
-        *  sanity check see whether all commands to this device been
-        *  completed
-        */
-       if (_scsih_scsi_lookup_find_by_lun(ioc, scmd->device->id,
-           scmd->device->lun, scmd->device->channel))
-               r = FAILED;
-       else
-               r = SUCCESS;
-       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-       mutex_unlock(&ioc->tm_cmds.mutex);
+       r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
+           scmd->device->id, scmd->device->lun,
+           MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);
 
  out:
        printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
@@ -2257,21 +2282,9 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
                goto out;
        }
 
-       mutex_lock(&ioc->tm_cmds.mutex);
-       mpt2sas_scsih_issue_tm(ioc, handle, 0,
-           MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30);
-
-       /*
-        *  sanity check see whether all commands to this target been
-        *  completed
-        */
-       if (_scsih_scsi_lookup_find_by_target(ioc, scmd->device->id,
-           scmd->device->channel))
-               r = FAILED;
-       else
-               r = SUCCESS;
-       ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-       mutex_unlock(&ioc->tm_cmds.mutex);
+       r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
+           scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
+           30, scmd);
 
  out:
        printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
@@ -2325,8 +2338,9 @@ _scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
 
        spin_lock_irqsave(&ioc->fw_event_lock, flags);
        list_add_tail(&fw_event->list, &ioc->fw_event_list);
-       INIT_WORK(&fw_event->work, _firmware_event_work);
-       queue_work(ioc->firmware_event_thread, &fw_event->work);
+       INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
+       queue_delayed_work(ioc->firmware_event_thread,
+           &fw_event->delayed_work, 0);
        spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
 }
 
@@ -2353,61 +2367,53 @@ _scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
        spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
 }
 
+
 /**
- * _scsih_fw_event_add - requeue an event
+ * _scsih_queue_rescan - queue a topology rescan from user context
  * @ioc: per adapter object
- * @fw_event: object describing the event
- * Context: This function will acquire ioc->fw_event_lock.
  *
  * Return nothing.
  */
 static void
-_scsih_fw_event_requeue(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
-    *fw_event, unsigned long delay)
+_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)
 {
-       unsigned long flags;
-       if (ioc->firmware_event_thread == NULL)
-               return;
+       struct fw_event_work *fw_event;
 
-       spin_lock_irqsave(&ioc->fw_event_lock, flags);
-       queue_work(ioc->firmware_event_thread, &fw_event->work);
-       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+       if (ioc->wait_for_port_enable_to_complete)
+               return;
+       fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+       if (!fw_event)
+               return;
+       fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET;
+       fw_event->ioc = ioc;
+       _scsih_fw_event_add(ioc, fw_event);
 }
 
 /**
- * _scsih_fw_event_off - turn flag off preventing event handling
+ * _scsih_fw_event_cleanup_queue - cleanup event queue
  * @ioc: per adapter object
  *
- * Used to prevent handling of firmware events during adapter reset
- * driver unload.
+ * Walk the firmware event queue, either killing timers, or waiting
+ * for outstanding events to complete
  *
  * Return nothing.
  */
 static void
-_scsih_fw_event_off(struct MPT2SAS_ADAPTER *ioc)
+_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
 {
-       unsigned long flags;
+       struct fw_event_work *fw_event, *next;
 
-       spin_lock_irqsave(&ioc->fw_event_lock, flags);
-       ioc->fw_events_off = 1;
-       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-
-}
-
-/**
- * _scsih_fw_event_on - turn flag on allowing firmware event handling
- * @ioc: per adapter object
- *
- * Returns nothing.
- */
-static void
-_scsih_fw_event_on(struct MPT2SAS_ADAPTER *ioc)
-{
-       unsigned long flags;
+       if (list_empty(&ioc->fw_event_list) ||
+            !ioc->firmware_event_thread || in_interrupt())
+               return;
 
-       spin_lock_irqsave(&ioc->fw_event_lock, flags);
-       ioc->fw_events_off = 0;
-       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+       list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
+               if (cancel_delayed_work(&fw_event->delayed_work)) {
+                       _scsih_fw_event_free(ioc, fw_event);
+                       continue;
+               }
+               fw_event->cancel_pending_work = 1;
+       }
 }
 
 /**
@@ -2571,25 +2577,24 @@ static void
 _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
 {
        Mpi2SCSITaskManagementRequest_t *mpi_request;
-       struct MPT2SAS_TARGET *sas_target_priv_data;
        u16 smid;
        struct _sas_device *sas_device;
        unsigned long flags;
        struct _tr_list *delayed_tr;
 
-       if (ioc->shost_recovery) {
-               printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
-                   __func__, ioc->name);
+       if (ioc->shost_recovery || ioc->remove_host) {
+               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
+                  "progress!\n", __func__, ioc->name));
                return;
        }
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
-       /* skip is hidden raid component */
-       if (sas_device && sas_device->hidden_raid_component)
+       if (sas_device && sas_device->hidden_raid_component) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                return;
+       }
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
        smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
        if (!smid) {
@@ -2598,36 +2603,16 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
                        return;
                INIT_LIST_HEAD(&delayed_tr->list);
                delayed_tr->handle = handle;
-               delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
-               list_add_tail(&delayed_tr->list,
-                   &ioc->delayed_tr_list);
-               if (sas_device && sas_device->starget) {
-                       dewtprintk(ioc, starget_printk(KERN_INFO,
-                           sas_device->starget, "DELAYED:tr:handle(0x%04x), "
-                           "(open)\n", handle));
-               } else {
-                       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
-                           "DELAYED:tr:handle(0x%04x), (open)\n",
-                           ioc->name, handle));
-               }
-               return;
-       }
-
-       if (sas_device) {
-               sas_device->state |= MPTSAS_STATE_TR_SEND;
-               sas_device->state |= MPT2SAS_REQ_SAS_CNTRL;
-               if (sas_device->starget && sas_device->starget->hostdata) {
-                       sas_target_priv_data = sas_device->starget->hostdata;
-                       sas_target_priv_data->tm_busy = 1;
-                       dewtprintk(ioc, starget_printk(KERN_INFO,
-                           sas_device->starget, "tr:handle(0x%04x), (open)\n",
-                           handle));
-               }
-       } else {
+               list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
                dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
-                   "tr:handle(0x%04x), (open)\n", ioc->name, handle));
+                   "DELAYED:tr:handle(0x%04x), (open)\n",
+                   ioc->name, handle));
+               return;
        }
 
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
+           "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
+           ioc->tm_tr_cb_idx));
        mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
        memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
        mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
@@ -2657,35 +2642,15 @@ static u8
 _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
     u8 msix_index, u32 reply)
 {
-       unsigned long flags;
-       u16 handle;
-       struct _sas_device *sas_device;
        Mpi2SasIoUnitControlReply_t *mpi_reply =
            mpt2sas_base_get_reply_virt_addr(ioc, reply);
 
-       handle = le16_to_cpu(mpi_reply->DevHandle);
-
-       spin_lock_irqsave(&ioc->sas_device_lock, flags);
-       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
-       if (sas_device) {
-               sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE;
-               if (sas_device->starget)
-                       dewtprintk(ioc, starget_printk(KERN_INFO,
-                           sas_device->starget,
-                           "sc_complete:handle(0x%04x), "
-                           "ioc_status(0x%04x), loginfo(0x%08x)\n",
-                           handle, le16_to_cpu(mpi_reply->IOCStatus),
-                           le32_to_cpu(mpi_reply->IOCLogInfo)));
-       } else {
-               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
-                   "sc_complete:handle(0x%04x), "
-                   "ioc_status(0x%04x), loginfo(0x%08x)\n",
-                   ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus),
-                   le32_to_cpu(mpi_reply->IOCLogInfo)));
-       }
-
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+           "sc_complete:handle(0x%04x), (open) "
+           "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
+           ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
+           le16_to_cpu(mpi_reply->IOCStatus),
+           le32_to_cpu(mpi_reply->IOCLogInfo)));
        return 1;
 }
 
@@ -2709,87 +2674,63 @@ static u8
 _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
     u32 reply)
 {
-       unsigned long flags;
        u16 handle;
-       struct _sas_device *sas_device;
+       Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
        Mpi2SCSITaskManagementReply_t *mpi_reply =
            mpt2sas_base_get_reply_virt_addr(ioc, reply);
        Mpi2SasIoUnitControlRequest_t *mpi_request;
        u16 smid_sas_ctrl;
-       struct MPT2SAS_TARGET *sas_target_priv_data;
        struct _tr_list *delayed_tr;
-       u8 rc;
 
-       handle = le16_to_cpu(mpi_reply->DevHandle);
-       spin_lock_irqsave(&ioc->sas_device_lock, flags);
-       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
-       if (sas_device) {
-               sas_device->state |= MPTSAS_STATE_TR_COMPLETE;
-               if (sas_device->starget) {
-                       dewtprintk(ioc, starget_printk(KERN_INFO,
-                           sas_device->starget, "tr_complete:handle(0x%04x), "
-                           "(%s) ioc_status(0x%04x), loginfo(0x%08x), "
-                           "completed(%d)\n", sas_device->handle,
-                           (sas_device->state & MPT2SAS_REQ_SAS_CNTRL) ?
-                           "open" : "active",
-                           le16_to_cpu(mpi_reply->IOCStatus),
-                           le32_to_cpu(mpi_reply->IOCLogInfo),
-                           le32_to_cpu(mpi_reply->TerminationCount)));
-                       if (sas_device->starget->hostdata) {
-                               sas_target_priv_data =
-                                   sas_device->starget->hostdata;
-                               sas_target_priv_data->tm_busy = 0;
-                       }
-               }
-       } else {
-               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
-                   "tr_complete:handle(0x%04x), (open) ioc_status(0x%04x), "
-                   "loginfo(0x%08x), completed(%d)\n", ioc->name,
-                   handle, le16_to_cpu(mpi_reply->IOCStatus),
-                   le32_to_cpu(mpi_reply->IOCLogInfo),
-                   le32_to_cpu(mpi_reply->TerminationCount)));
+       if (ioc->shost_recovery || ioc->remove_host) {
+               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
+                  "progress!\n", __func__, ioc->name));
+               return 1;
        }
 
-       if (!list_empty(&ioc->delayed_tr_list)) {
-               delayed_tr = list_entry(ioc->delayed_tr_list.next,
-                   struct _tr_list, list);
-               mpt2sas_base_free_smid(ioc, smid);
-               if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
-                       _scsih_tm_tr_send(ioc, delayed_tr->handle);
-               list_del(&delayed_tr->list);
-               kfree(delayed_tr);
-               rc = 0; /* tells base_interrupt not to free mf */
-       } else
-               rc = 1;
-
-       if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
-               return rc;
-
-       if (ioc->shost_recovery) {
-               printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
-                   __func__, ioc->name);
-               return rc;
+       mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
+       handle = le16_to_cpu(mpi_request_tm->DevHandle);
+       if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
+               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
+                   "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
+                   le16_to_cpu(mpi_reply->DevHandle), smid));
+               return 0;
        }
 
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+           "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
+           "loginfo(0x%08x), completed(%d)\n", ioc->name,
+           handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
+           le32_to_cpu(mpi_reply->IOCLogInfo),
+           le32_to_cpu(mpi_reply->TerminationCount)));
+
        smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
        if (!smid_sas_ctrl) {
                printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
                    ioc->name, __func__);
-               return rc;
+               return 1;
        }
 
-       if (sas_device)
-               sas_device->state |= MPTSAS_STATE_CNTRL_SEND;
-
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
+           "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
+           ioc->tm_sas_control_cb_idx));
        mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
        memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
        mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
        mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
-       mpi_request->DevHandle = mpi_reply->DevHandle;
+       mpi_request->DevHandle = mpi_request_tm->DevHandle;
        mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
-       return rc;
+
+       if (!list_empty(&ioc->delayed_tr_list)) {
+               delayed_tr = list_entry(ioc->delayed_tr_list.next,
+                   struct _tr_list, list);
+               mpt2sas_base_free_smid(ioc, smid);
+               _scsih_tm_tr_send(ioc, delayed_tr->handle);
+               list_del(&delayed_tr->list);
+               kfree(delayed_tr);
+               return 0; /* tells base_interrupt not to free mf */
+       }
+       return 1;
 }
 
 /**
@@ -3021,25 +2962,32 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
 
        scmd->scsi_done = done;
        sas_device_priv_data = scmd->device->hostdata;
-       if (!sas_device_priv_data) {
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
                scmd->result = DID_NO_CONNECT << 16;
                scmd->scsi_done(scmd);
                return 0;
        }
 
        sas_target_priv_data = sas_device_priv_data->sas_target;
-       if (!sas_target_priv_data || sas_target_priv_data->handle ==
-           MPT2SAS_INVALID_DEVICE_HANDLE || sas_target_priv_data->deleted) {
+       /* invalid device handle */
+       if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
                scmd->result = DID_NO_CONNECT << 16;
                scmd->scsi_done(scmd);
                return 0;
        }
 
-       /* see if we are busy with task managment stuff */
-       if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
-               return SCSI_MLQUEUE_DEVICE_BUSY;
-       else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
+       /* host recovery or link resets sent via IOCTLs */
+       if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
                return SCSI_MLQUEUE_HOST_BUSY;
+       /* device busy with task managment */
+       else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
+               return SCSI_MLQUEUE_DEVICE_BUSY;
+       /* device has been deleted */
+       else if (sas_target_priv_data->deleted) {
+               scmd->result = DID_NO_CONNECT << 16;
+               scmd->scsi_done(scmd);
+               return 0;
+       }
 
        if (scmd->sc_data_direction == DMA_FROM_DEVICE)
                mpi_control = MPI2_SCSIIO_CONTROL_READ;
@@ -3110,8 +3058,11 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
                }
        }
 
-       mpt2sas_base_put_smid_scsi_io(ioc, smid,
-           sas_device_priv_data->sas_target->handle);
+       if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
+               mpt2sas_base_put_smid_scsi_io(ioc, smid,
+                   sas_device_priv_data->sas_target->handle);
+       else
+               mpt2sas_base_put_smid_default(ioc, smid);
        return 0;
 
  out:
@@ -3301,8 +3252,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
                struct sense_info data;
                _scsih_normalize_sense(scmd->sense_buffer, &data);
                printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
-                   "[0x%02x,0x%02x,0x%02x]\n", ioc->name, data.skey,
-                   data.asc, data.ascq);
+                   "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
+                   data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
        }
 
        if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
@@ -3356,7 +3307,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
                mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
                mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
                mpi_request.SlotStatus =
-                   MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
+                   cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
                mpi_request.DevHandle = cpu_to_le16(handle);
                mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
                if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
@@ -4008,6 +3959,134 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
 }
 
 /**
+ * _scsih_check_access_status - check access flags
+ * @ioc: per adapter object
+ * @sas_address: sas address
+ * @handle: sas device handle
+ * @access_flags: errors returned during discovery of the device
+ *
+ * Return 0 for success, else failure
+ */
+static u8
+_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
+   u16 handle, u8 access_status)
+{
+       u8 rc = 1;
+       char *desc = NULL;
+
+       switch (access_status) {
+       case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
+       case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
+               rc = 0;
+               break;
+       case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
+               desc = "sata capability failed";
+               break;
+       case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
+               desc = "sata affiliation conflict";
+               break;
+       case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
+               desc = "route not addressable";
+               break;
+       case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
+               desc = "smp error not addressable";
+               break;
+       case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
+               desc = "device blocked";
+               break;
+       case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
+       case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
+               desc = "sata initialization failed";
+               break;
+       default:
+               desc = "unknown";
+               break;
+       }
+
+       if (!rc)
+               return 0;
+
+       printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
+           "handle(0x%04x)\n", ioc->name, desc,
+           (unsigned long long)sas_address, handle);
+       return rc;
+}
+
+static void
+_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       Mpi2ConfigReply_t mpi_reply;
+       Mpi2SasDevicePage0_t sas_device_pg0;
+       struct _sas_device *sas_device;
+       u32 ioc_status;
+       unsigned long flags;
+       u64 sas_address;
+       struct scsi_target *starget;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
+       u32 device_info;
+
+       if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
+           MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
+               return;
+
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
+               return;
+
+       /* check if this is end device */
+       device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
+       if (!(_scsih_is_end_device(device_info)))
+               return;
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+           sas_address);
+
+       if (!sas_device) {
+               printk(MPT2SAS_ERR_FMT "device is not present "
+                   "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+               return;
+       }
+
+       if (unlikely(sas_device->handle != handle)) {
+               starget = sas_device->starget;
+               sas_target_priv_data = starget->hostdata;
+               starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
+                  " to (0x%04x)!!!\n", sas_device->handle, handle);
+               sas_target_priv_data->handle = handle;
+               sas_device->handle = handle;
+       }
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+       /* check if device is present */
+       if (!(le16_to_cpu(sas_device_pg0.Flags) &
+           MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
+               printk(MPT2SAS_ERR_FMT "device is not present "
+                   "handle(0x%04x), flags!!!\n", ioc->name, handle);
+               return;
+       }
+
+       /* check if there were any issues with discovery */
+       if (_scsih_check_access_status(ioc, sas_address, handle,
+           sas_device_pg0.AccessStatus))
+               return;
+       _scsih_ublock_io_device(ioc, handle);
+
+}
+
+/**
  * _scsih_add_device -  creating sas device object
  * @ioc: per adapter object
  * @handle: sas device handle
@@ -4045,6 +4124,8 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
                return -1;
        }
 
+       sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
+
        /* check if device is present */
        if (!(le16_to_cpu(sas_device_pg0.Flags) &
            MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
@@ -4055,15 +4136,10 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
                return -1;
        }
 
-       /* check if there were any issus with discovery */
-       if (sas_device_pg0.AccessStatus ==
-           MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED) {
-               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
-                   ioc->name, __FILE__, __LINE__, __func__);
-               printk(MPT2SAS_ERR_FMT "AccessStatus = 0x%02x\n",
-                   ioc->name, sas_device_pg0.AccessStatus);
+       /* check if there were any issues with discovery */
+       if (_scsih_check_access_status(ioc, sas_address, handle,
+           sas_device_pg0.AccessStatus))
                return -1;
-       }
 
        /* check if this is end device */
        device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
@@ -4073,17 +4149,14 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
                return -1;
        }
 
-       sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
            sas_address);
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
-       if (sas_device) {
-               _scsih_ublock_io_device(ioc, handle);
+       if (sas_device)
                return 0;
-       }
 
        sas_device = kzalloc(sizeof(struct _sas_device),
            GFP_KERNEL);
@@ -4126,67 +4199,38 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
 }
 
 /**
- * _scsih_remove_device -  removing sas device object
+ * _scsih_remove_pd_device -  removing sas device pd object
  * @ioc: per adapter object
- * @sas_device: the sas_device object
+ * @sas_device_delete: the sas_device object
  *
+ * For hidden raid components, we do driver-fw handshake from
+ * hotplug work threads.
  * Return nothing.
  */
 static void
-_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
-    *sas_device)
+_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
+    sas_device)
 {
-       struct MPT2SAS_TARGET *sas_target_priv_data;
        Mpi2SasIoUnitControlReply_t mpi_reply;
        Mpi2SasIoUnitControlRequest_t mpi_request;
-       u16 device_handle, handle;
-
-       if (!sas_device)
-               return;
+       u16 vol_handle, handle;
 
-       handle = sas_device->handle;
+       handle = sas_device.handle;
        dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
            " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
-           (unsigned long long) sas_device->sas_address));
-
-       if (sas_device->starget && sas_device->starget->hostdata) {
-               sas_target_priv_data = sas_device->starget->hostdata;
-               sas_target_priv_data->deleted = 1;
-       }
-
-       if (ioc->remove_host || ioc->shost_recovery || !handle)
-               goto out;
+           (unsigned long long) sas_device.sas_address));
 
-       if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) {
-               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
-                  "target_reset handle(0x%04x)\n", ioc->name,
-                  handle));
-               goto skip_tr;
-       }
-
-       /* Target Reset to flush out all the outstanding IO */
-       device_handle = (sas_device->hidden_raid_component) ?
-           sas_device->volume_handle : handle;
-       if (device_handle) {
-               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
-                   "handle(0x%04x)\n", ioc->name, device_handle));
-               mutex_lock(&ioc->tm_cmds.mutex);
-               mpt2sas_scsih_issue_tm(ioc, device_handle, 0,
-                   MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
-               ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-               mutex_unlock(&ioc->tm_cmds.mutex);
-               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
-                   "done: handle(0x%04x)\n", ioc->name, device_handle));
-               if (ioc->shost_recovery)
-                       goto out;
-       }
- skip_tr:
-
-       if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
-               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
-                  "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
-               goto out;
-       }
+       vol_handle = sas_device.volume_handle;
+       if (!vol_handle)
+               return;
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
+           "handle(0x%04x)\n", ioc->name, vol_handle));
+       mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0,
+           MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL);
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
+           "done: handle(0x%04x)\n", ioc->name, vol_handle));
+       if (ioc->shost_recovery)
+               return;
 
        /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
        dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
@@ -4194,34 +4238,68 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
        memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
        mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
        mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
-       mpi_request.DevHandle = handle;
-       mpi_request.VF_ID = 0; /* TODO */
-       mpi_request.VP_ID = 0;
+       mpi_request.DevHandle = cpu_to_le16(handle);
        if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
-           &mpi_request)) != 0) {
+           &mpi_request)) != 0)
                printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
-       }
 
        dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
            "(0x%04x), loginfo(0x%08x)\n", ioc->name,
            le16_to_cpu(mpi_reply.IOCStatus),
            le32_to_cpu(mpi_reply.IOCLogInfo)));
 
- out:
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x),"
+           " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
+           (unsigned long long) sas_device.sas_address));
+}
 
-       _scsih_ublock_io_device(ioc, handle);
+/**
+ * _scsih_remove_device -  removing sas device object
+ * @ioc: per adapter object
+ * @sas_device_delete: the sas_device object
+ *
+ * Return nothing.
+ */
+static void
+_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_device *sas_device)
+{
+       struct _sas_device sas_device_backup;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
 
-       mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
-           sas_device->sas_address_parent);
+       if (!sas_device)
+               return;
 
-       printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
-           "(0x%016llx)\n", ioc->name, handle,
-           (unsigned long long) sas_device->sas_address);
+       memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
        _scsih_sas_device_remove(ioc, sas_device);
 
-       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle"
-           "(0x%04x)\n", ioc->name, __func__, handle));
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
+           "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
+           sas_device_backup.handle, (unsigned long long)
+           sas_device_backup.sas_address));
+
+       if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
+               sas_target_priv_data = sas_device_backup.starget->hostdata;
+               sas_target_priv_data->deleted = 1;
+       }
+
+       if (sas_device_backup.hidden_raid_component)
+               _scsih_remove_pd_device(ioc, sas_device_backup);
+
+       _scsih_ublock_io_device(ioc, sas_device_backup.handle);
+
+       mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address,
+           sas_device_backup.sas_address_parent);
+
+       printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
+           "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
+           (unsigned long long) sas_device_backup.sas_address);
+
+       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
+           "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
+           sas_device_backup.handle, (unsigned long long)
+           sas_device_backup.sas_address));
 }
 
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -4331,7 +4409,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
                _scsih_sas_topology_change_event_debug(ioc, event_data);
 #endif
 
-       if (ioc->shost_recovery)
+       if (ioc->shost_recovery || ioc->remove_host)
                return;
 
        if (!ioc->sas_hba.num_phys)
@@ -4370,7 +4448,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
                            "expander event\n", ioc->name));
                        return;
                }
-               if (ioc->shost_recovery)
+               if (ioc->shost_recovery || ioc->remove_host)
                        return;
                phy_number = event_data->StartPhyNum + i;
                reason_code = event_data->PHY[i].PhyStatus &
@@ -4393,8 +4471,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
                        mpt2sas_transport_update_links(ioc, sas_address,
                            handle, phy_number, link_rate);
 
-                       if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
-                               _scsih_ublock_io_device(ioc, handle);
+                       if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
+                               break;
+
+                       _scsih_check_device(ioc, handle);
                        break;
                case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
 
@@ -4520,10 +4600,10 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
                     event_data);
 #endif
 
-       if (!(event_data->ReasonCode ==
+       if (event_data->ReasonCode !=
            MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
-          event_data->ReasonCode ==
-           MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET))
+          event_data->ReasonCode !=
+           MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
                return;
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
@@ -4630,7 +4710,6 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
        dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
            __func__));
 
-       mutex_lock(&ioc->tm_cmds.mutex);
        termination_count = 0;
        query_count = 0;
        mpi_reply = ioc->tm_cmds.reply;
@@ -4654,8 +4733,8 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                lun = sas_device_priv_data->lun;
                query_count++;
 
-               mpt2sas_scsih_issue_tm(ioc, handle, lun,
-                   MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30);
+               mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
+                   MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, NULL);
                ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
                ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
                    & MPI2_IOCSTATUS_MASK;
@@ -4666,13 +4745,11 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
                     MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
                        continue;
 
-               mpt2sas_scsih_issue_tm(ioc, handle, lun,
-                   MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30);
-               ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
+               mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
+                   MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, 0, 30, NULL);
                termination_count += le32_to_cpu(mpi_reply->TerminationCount);
        }
        ioc->broadcast_aen_busy = 0;
-       mutex_unlock(&ioc->tm_cmds.mutex);
 
        dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
            "%s - exit, query_count = %d termination_count = %d\n",
@@ -5442,6 +5519,26 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
 }
 
 /**
+ * _scsih_prep_device_scan - initialize parameters prior to device scan
+ * @ioc: per adapter object
+ *
+ * Set the deleted flag prior to device scan.  If the device is found during
+ * the scan, then we clear the deleted flag.
+ */
+static void
+_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
+{
+       struct MPT2SAS_DEVICE *sas_device_priv_data;
+       struct scsi_device *sdev;
+
+       shost_for_each_device(sdev, ioc->shost) {
+               sas_device_priv_data = sdev->hostdata;
+               if (sas_device_priv_data && sas_device_priv_data->sas_target)
+                       sas_device_priv_data->sas_target->deleted = 1;
+       }
+}
+
+/**
  * _scsih_mark_responding_sas_device - mark a sas_devices as responding
  * @ioc: per adapter object
  * @sas_address: sas address
@@ -5467,10 +5564,13 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
                if (sas_device->sas_address == sas_address &&
                    sas_device->slot == slot && sas_device->starget) {
                        sas_device->responding = 1;
-                       sas_device->state = 0;
                        starget = sas_device->starget;
-                       sas_target_priv_data = starget->hostdata;
-                       sas_target_priv_data->tm_busy = 0;
+                       if (starget && starget->hostdata) {
+                               sas_target_priv_data = starget->hostdata;
+                               sas_target_priv_data->tm_busy = 0;
+                               sas_target_priv_data->deleted = 0;
+                       } else
+                               sas_target_priv_data = NULL;
                        starget_printk(KERN_INFO, sas_device->starget,
                            "handle(0x%04x), sas_addr(0x%016llx), enclosure "
                            "logical id(0x%016llx), slot(%d)\n", handle,
@@ -5483,7 +5583,8 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
                        printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
                            sas_device->handle);
                        sas_device->handle = handle;
-                       sas_target_priv_data->handle = handle;
+                       if (sas_target_priv_data)
+                               sas_target_priv_data->handle = handle;
                        goto out;
                }
        }
@@ -5558,6 +5659,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
        spin_lock_irqsave(&ioc->raid_device_lock, flags);
        list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
                if (raid_device->wwid == wwid && raid_device->starget) {
+                       starget = raid_device->starget;
+                       if (starget && starget->hostdata) {
+                               sas_target_priv_data = starget->hostdata;
+                               sas_target_priv_data->deleted = 0;
+                       } else
+                               sas_target_priv_data = NULL;
                        raid_device->responding = 1;
                        starget_printk(KERN_INFO, raid_device->starget,
                            "handle(0x%04x), wwid(0x%016llx)\n", handle,
@@ -5567,9 +5674,8 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
                        printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
                            raid_device->handle);
                        raid_device->handle = handle;
-                       starget = raid_device->starget;
-                       sas_target_priv_data = starget->hostdata;
-                       sas_target_priv_data->handle = handle;
+                       if (sas_target_priv_data)
+                               sas_target_priv_data->handle = handle;
                        goto out;
                }
        }
@@ -5694,13 +5800,13 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
 }
 
 /**
- * _scsih_remove_unresponding_devices - removing unresponding devices
+ * _scsih_remove_unresponding_sas_devices - removing unresponding devices
  * @ioc: per adapter object
  *
  * Return nothing.
  */
 static void
-_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
+_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
 {
        struct _sas_device *sas_device, *sas_device_next;
        struct _sas_node *sas_expander;
@@ -5722,8 +5828,6 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
                            (unsigned long long)
                            sas_device->enclosure_logical_id,
                            sas_device->slot);
-               /* invalidate the device handle */
-               sas_device->handle = 0;
                _scsih_remove_device(ioc, sas_device);
        }
 
@@ -5774,32 +5878,33 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
        case MPT2_IOC_PRE_RESET:
                dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
                    "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
-               _scsih_fw_event_off(ioc);
                break;
        case MPT2_IOC_AFTER_RESET:
                dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
                    "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
+               if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
+                       ioc->scsih_cmds.status |= MPT2_CMD_RESET;
+                       mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
+                       complete(&ioc->scsih_cmds.done);
+               }
                if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
                        ioc->tm_cmds.status |= MPT2_CMD_RESET;
                        mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
                        complete(&ioc->tm_cmds.done);
                }
-               _scsih_fw_event_on(ioc);
+               _scsih_fw_event_cleanup_queue(ioc);
                _scsih_flush_running_cmds(ioc);
+               _scsih_queue_rescan(ioc);
                break;
        case MPT2_IOC_DONE_RESET:
                dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
                    "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
                _scsih_sas_host_refresh(ioc);
+               _scsih_prep_device_scan(ioc);
                _scsih_search_responding_sas_devices(ioc);
                _scsih_search_responding_raid_devices(ioc);
                _scsih_search_responding_expanders(ioc);
                break;
-       case MPT2_IOC_RUNNING:
-               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
-                   "MPT2_IOC_RUNNING\n", ioc->name, __func__));
-               _scsih_remove_unresponding_devices(ioc);
-               break;
        }
 }
 
@@ -5815,21 +5920,28 @@ static void
 _firmware_event_work(struct work_struct *work)
 {
        struct fw_event_work *fw_event = container_of(work,
-           struct fw_event_work, work);
+           struct fw_event_work, delayed_work.work);
        unsigned long flags;
        struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
 
        /* the queue is being flushed so ignore this event */
-       spin_lock_irqsave(&ioc->fw_event_lock, flags);
-       if (ioc->fw_events_off || ioc->remove_host) {
-               spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+       if (ioc->remove_host || fw_event->cancel_pending_work) {
                _scsih_fw_event_free(ioc, fw_event);
                return;
        }
-       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
 
-       if (ioc->shost_recovery) {
-               _scsih_fw_event_requeue(ioc, fw_event, 1000);
+       if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) {
+               _scsih_fw_event_free(ioc, fw_event);
+               spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+               if (ioc->shost_recovery) {
+                       init_completion(&ioc->shost_recovery_done);
+                       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
+                           flags);
+                       wait_for_completion(&ioc->shost_recovery_done);
+               } else
+                       spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
+                           flags);
+               _scsih_remove_unresponding_sas_devices(ioc);
                return;
        }
 
@@ -5891,16 +6003,12 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
 {
        struct fw_event_work *fw_event;
        Mpi2EventNotificationReply_t *mpi_reply;
-       unsigned long flags;
        u16 event;
+       u16 sz;
 
        /* events turned off due to host reset or driver unloading */
-       spin_lock_irqsave(&ioc->fw_event_lock, flags);
-       if (ioc->fw_events_off || ioc->remove_host) {
-               spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+       if (ioc->remove_host)
                return 1;
-       }
-       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
 
        mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
        event = le16_to_cpu(mpi_reply->Event);
@@ -5947,8 +6055,8 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
                    ioc->name, __FILE__, __LINE__, __func__);
                return 1;
        }
-       fw_event->event_data =
-           kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
+       sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
+       fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
        if (!fw_event->event_data) {
                printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
@@ -5957,7 +6065,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
        }
 
        memcpy(fw_event->event_data, mpi_reply->EventData,
-           mpi_reply->EventDataLength*4);
+           sz);
        fw_event->ioc = ioc;
        fw_event->VF_ID = mpi_reply->VF_ID;
        fw_event->VP_ID = mpi_reply->VP_ID;
@@ -6158,6 +6266,18 @@ _scsih_shutdown(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       struct workqueue_struct *wq;
+       unsigned long flags;
+
+       ioc->remove_host = 1;
+       _scsih_fw_event_cleanup_queue(ioc);
+
+       spin_lock_irqsave(&ioc->fw_event_lock, flags);
+       wq = ioc->firmware_event_thread;
+       ioc->firmware_event_thread = NULL;
+       spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+       if (wq)
+               destroy_workqueue(wq);
 
        _scsih_ir_shutdown(ioc);
        mpt2sas_base_detach(ioc);
@@ -6184,7 +6304,7 @@ _scsih_remove(struct pci_dev *pdev)
        unsigned long flags;
 
        ioc->remove_host = 1;
-       _scsih_fw_event_off(ioc);
+       _scsih_fw_event_cleanup_queue(ioc);
 
        spin_lock_irqsave(&ioc->fw_event_lock, flags);
        wq = ioc->firmware_event_thread;
@@ -6557,6 +6677,122 @@ _scsih_resume(struct pci_dev *pdev)
 }
 #endif /* CONFIG_PM */
 
+/**
+ * _scsih_pci_error_detected - Called when a PCI error is detected.
+ * @pdev: PCI device struct
+ * @state: PCI channel state
+ *
+ * Description: Called when a PCI error is detected.
+ *
+ * Return value:
+ *      PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
+ */
+static pci_ers_result_t
+_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
+           ioc->name, state);
+
+       switch (state) {
+       case pci_channel_io_normal:
+               return PCI_ERS_RESULT_CAN_RECOVER;
+       case pci_channel_io_frozen:
+               scsi_block_requests(ioc->shost);
+               mpt2sas_base_stop_watchdog(ioc);
+               mpt2sas_base_free_resources(ioc);
+               return PCI_ERS_RESULT_NEED_RESET;
+       case pci_channel_io_perm_failure:
+               _scsih_remove(pdev);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * _scsih_pci_slot_reset - Called when PCI slot has been reset.
+ * @pdev: PCI device struct
+ *
+ * Description: This routine is called by the pci error recovery
+ * code after the PCI slot has been reset, just before we
+ * should resume normal operations.
+ */
+static pci_ers_result_t
+_scsih_pci_slot_reset(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       int rc;
+
+       printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
+               ioc->name);
+
+       ioc->pdev = pdev;
+       rc = mpt2sas_base_map_resources(ioc);
+       if (rc)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+
+       rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
+           FORCE_BIG_HAMMER);
+
+       printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
+           (rc == 0) ? "success" : "failed");
+
+       if (!rc)
+               return PCI_ERS_RESULT_RECOVERED;
+       else
+               return PCI_ERS_RESULT_DISCONNECT;
+}
+
+/**
+ * _scsih_pci_resume() - resume normal ops after PCI reset
+ * @pdev: pointer to PCI device
+ *
+ * Called when the error recovery driver tells us that its
+ * OK to resume normal operation. Use completion to allow
+ * halted scsi ops to resume.
+ */
+static void
+_scsih_pci_resume(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
+
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+       mpt2sas_base_start_watchdog(ioc);
+       scsi_unblock_requests(ioc->shost);
+}
+
+/**
+ * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
+ * @pdev: pointer to PCI device
+ */
+static pci_ers_result_t
+_scsih_pci_mmio_enabled(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
+           ioc->name);
+
+       /* TODO - dump whatever for debugging purposes */
+
+       /* Request a slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static struct pci_error_handlers _scsih_err_handler = {
+       .error_detected = _scsih_pci_error_detected,
+       .mmio_enabled = _scsih_pci_mmio_enabled,
+       .slot_reset =   _scsih_pci_slot_reset,
+       .resume =       _scsih_pci_resume,
+};
 
 static struct pci_driver scsih_driver = {
        .name           = MPT2SAS_DRIVER_NAME,
@@ -6564,6 +6800,7 @@ static struct pci_driver scsih_driver = {
        .probe          = _scsih_probe,
        .remove         = __devexit_p(_scsih_remove),
        .shutdown       = _scsih_shutdown,
+       .err_handler    = &_scsih_err_handler,
 #ifdef CONFIG_PM
        .suspend        = _scsih_suspend,
        .resume         = _scsih_resume,
index bd7ca2b..2727c3b 100644 (file)
@@ -2,7 +2,7 @@
  * SAS Transport Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -465,6 +465,85 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
        return rc;
 }
 
+
+/**
+ * _transport_delete_duplicate_port - (see below description)
+ * @ioc: per adapter object
+ * @sas_node: sas node object (either expander or sas host)
+ * @sas_address: sas address of device being added
+ * @phy_num: phy number
+ *
+ * This function is called when attempting to add a new port that is claiming
+ * the same phy resources already in use by another port.  If we don't release
+ * the claimed phy resources, the sas transport layer will hang from the BUG
+ * in sas_port_add_phy.
+ *
+ * The reason we would hit this issue is becuase someone is changing the
+ * sas address of a device on the fly, meanwhile controller firmware sends
+ * EVENTs out of order when removing the previous instance of the device.
+ */
+static void
+_transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc,
+    struct _sas_node *sas_node, u64 sas_address, int phy_num)
+{
+       struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate;
+       struct _sas_phy *mpt2sas_phy;
+
+       printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), "
+           "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address,
+           phy_num);
+
+       mpt2sas_port_duplicate = NULL;
+       list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) {
+               dev_printk(KERN_ERR, &mpt2sas_port->port->dev,
+                   "existing device at sas_addr(0x%016llx), num_phys(%d)\n",
+                   (unsigned long long)
+                   mpt2sas_port->remote_identify.sas_address,
+                   mpt2sas_port->num_phys);
+               list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
+                   port_siblings) {
+                       dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev,
+                           "phy_number(%d)\n", mpt2sas_phy->phy_id);
+                       if (mpt2sas_phy->phy_id == phy_num)
+                               mpt2sas_port_duplicate = mpt2sas_port;
+               }
+       }
+
+       if (!mpt2sas_port_duplicate)
+               return;
+
+       dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev,
+           "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n",
+           (unsigned long long)
+           mpt2sas_port_duplicate->remote_identify.sas_address, phy_num);
+       ioc->logging_level |= MPT_DEBUG_TRANSPORT;
+       mpt2sas_transport_port_remove(ioc,
+           mpt2sas_port_duplicate->remote_identify.sas_address,
+           sas_node->sas_address);
+       ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
+}
+
+/**
+ * _transport_sanity_check - sanity check when adding a new port
+ * @ioc: per adapter object
+ * @sas_node: sas node object (either expander or sas host)
+ * @sas_address: sas address of device being added
+ *
+ * See the explanation above from _transport_delete_duplicate_port
+ */
+static void
+_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node,
+     u64 sas_address)
+{
+       int i;
+
+       for (i = 0; i < sas_node->num_phys; i++)
+               if (sas_node->phy[i].remote_identify.sas_address == sas_address)
+                       if (sas_node->phy[i].phy_belongs_to_port)
+                               _transport_delete_duplicate_port(ioc, sas_node,
+                                       sas_address, i);
+}
+
 /**
  * mpt2sas_transport_port_add - insert port to the list
  * @ioc: per adapter object
@@ -522,6 +601,9 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
                goto out_fail;
        }
 
+       _transport_sanity_check(ioc, sas_node,
+           mpt2sas_port->remote_identify.sas_address);
+
        for (i = 0; i < sas_node->num_phys; i++) {
                if (sas_node->phy[i].remote_identify.sas_address !=
                    mpt2sas_port->remote_identify.sas_address)
@@ -553,6 +635,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
                            mpt2sas_port->remote_identify.sas_address,
                            mpt2sas_phy->phy_id);
                sas_port_add_phy(port, mpt2sas_phy->phy);
+               mpt2sas_phy->phy_belongs_to_port = 1;
        }
 
        mpt2sas_port->port = port;
@@ -651,6 +734,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
                            (unsigned long long)
                            mpt2sas_port->remote_identify.sas_address,
                            mpt2sas_phy->phy_id);
+               mpt2sas_phy->phy_belongs_to_port = 0;
                sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
                list_del(&mpt2sas_phy->port_siblings);
        }
@@ -1341,7 +1425,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
                req->sense_len = sizeof(*mpi_reply);
                req->resid_len = 0;
-               rsp->resid_len -= mpi_reply->ResponseDataLength;
+               rsp->resid_len -=
+                   le16_to_cpu(mpi_reply->ResponseDataLength);
        } else {
                dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
                    "%s - no reply\n", ioc->name, __func__));
index d722235..716d178 100644 (file)
 #include "wd33c93.h"
 #include "mvme147.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
-#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
 
 static struct Scsi_Host *mvme147_host = NULL;
 
-static irqreturn_t mvme147_intr (int irq, void *dummy)
+static irqreturn_t mvme147_intr(int irq, void *dummy)
 {
-    if (irq == MVME147_IRQ_SCSI_PORT)
-       wd33c93_intr (mvme147_host);
-    else
-       m147_pcc->dma_intr = 0x89;      /* Ack and enable ints */
-    return IRQ_HANDLED;
+       if (irq == MVME147_IRQ_SCSI_PORT)
+               wd33c93_intr(mvme147_host);
+       else
+               m147_pcc->dma_intr = 0x89;      /* Ack and enable ints */
+       return IRQ_HANDLED;
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-    unsigned char flags = 0x01;
-    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-
-    /* setup dma direction */
-    if (!dir_in)
-       flags |= 0x04;
-
-    /* remember direction */
-    HDATA(mvme147_host)->dma_dir = dir_in;
-
-    if (dir_in)
-       /* invalidate any cache */
-       cache_clear (addr, cmd->SCp.this_residual);
-    else
-       /* push any dirty cache */
-       cache_push (addr, cmd->SCp.this_residual);
-
-    /* start DMA */
-    m147_pcc->dma_bcr   = cmd->SCp.this_residual | (1<<24);
-    m147_pcc->dma_dadr  = addr;
-    m147_pcc->dma_cntrl = flags;
-
-    /* return success */
-    return 0;
+       struct WD33C93_hostdata *hdata = shost_priv(mvme147_host);
+       unsigned char flags = 0x01;
+       unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+
+       /* setup dma direction */
+       if (!dir_in)
+               flags |= 0x04;
+
+       /* remember direction */
+       hdata->dma_dir = dir_in;
+
+       if (dir_in) {
+               /* invalidate any cache */
+               cache_clear(addr, cmd->SCp.this_residual);
+       } else {
+               /* push any dirty cache */
+               cache_push(addr, cmd->SCp.this_residual);
+       }
+
+       /* start DMA */
+       m147_pcc->dma_bcr = cmd->SCp.this_residual | (1 << 24);
+       m147_pcc->dma_dadr = addr;
+       m147_pcc->dma_cntrl = flags;
+
+       /* return success */
+       return 0;
 }
 
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
-                     int status)
+                    int status)
 {
-    m147_pcc->dma_cntrl = 0;
+       m147_pcc->dma_cntrl = 0;
 }
 
 int mvme147_detect(struct scsi_host_template *tpnt)
 {
-    static unsigned char called = 0;
-    wd33c93_regs regs;
-
-    if (!MACH_IS_MVME147 || called)
-       return 0;
-    called++;
-
-    tpnt->proc_name = "MVME147";
-    tpnt->proc_info = &wd33c93_proc_info;
-
-    mvme147_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
-    if (!mvme147_host)
-           goto err_out;
-
-    mvme147_host->base = 0xfffe4000;
-    mvme147_host->irq = MVME147_IRQ_SCSI_PORT;
-    regs.SASR = (volatile unsigned char *)0xfffe4000;
-    regs.SCMD = (volatile unsigned char *)0xfffe4001;
-    HDATA(mvme147_host)->no_sync = 0xff;
-    HDATA(mvme147_host)->fast = 0;
-    HDATA(mvme147_host)->dma_mode = CTRL_DMA;
-    wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
-
-    if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, "MVME147 SCSI PORT", mvme147_intr))
-           goto err_unregister;
-    if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, "MVME147 SCSI DMA", mvme147_intr))
-           goto err_free_irq;
+       static unsigned char called = 0;
+       wd33c93_regs regs;
+       struct WD33C93_hostdata *hdata;
+
+       if (!MACH_IS_MVME147 || called)
+               return 0;
+       called++;
+
+       tpnt->proc_name = "MVME147";
+       tpnt->proc_info = &wd33c93_proc_info;
+
+       mvme147_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+       if (!mvme147_host)
+               goto err_out;
+
+       mvme147_host->base = 0xfffe4000;
+       mvme147_host->irq = MVME147_IRQ_SCSI_PORT;
+       regs.SASR = (volatile unsigned char *)0xfffe4000;
+       regs.SCMD = (volatile unsigned char *)0xfffe4001;
+       hdata = shost_priv(mvme147_host);
+       hdata->no_sync = 0xff;
+       hdata->fast = 0;
+       hdata->dma_mode = CTRL_DMA;
+       wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
+
+       if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
+                       "MVME147 SCSI PORT", mvme147_intr))
+               goto err_unregister;
+       if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
+                       "MVME147 SCSI DMA", mvme147_intr))
+               goto err_free_irq;
 #if 0  /* Disabled; causes problems booting */
-    m147_pcc->scsi_interrupt = 0x10;   /* Assert SCSI bus reset */
-    udelay(100);
-    m147_pcc->scsi_interrupt = 0x00;   /* Negate SCSI bus reset */
-    udelay(2000);
-    m147_pcc->scsi_interrupt = 0x40;   /* Clear bus reset interrupt */
+       m147_pcc->scsi_interrupt = 0x10;        /* Assert SCSI bus reset */
+       udelay(100);
+       m147_pcc->scsi_interrupt = 0x00;        /* Negate SCSI bus reset */
+       udelay(2000);
+       m147_pcc->scsi_interrupt = 0x40;        /* Clear bus reset interrupt */
 #endif
-    m147_pcc->scsi_interrupt = 0x09;   /* Enable interrupt */
+       m147_pcc->scsi_interrupt = 0x09;        /* Enable interrupt */
 
-    m147_pcc->dma_cntrl = 0x00;                /* ensure DMA is stopped */
-    m147_pcc->dma_intr = 0x89;         /* Ack and enable ints */
+       m147_pcc->dma_cntrl = 0x00;     /* ensure DMA is stopped */
+       m147_pcc->dma_intr = 0x89;      /* Ack and enable ints */
 
-    return 1;
+       return 1;
 
- err_free_irq:
-    free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
- err_unregister:
-    wd33c93_release();
-    scsi_unregister(mvme147_host);
- err_out:
-    return 0;
+err_free_irq:
+       free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
+err_unregister:
+       scsi_unregister(mvme147_host);
+err_out:
+       return 0;
 }
 
 static int mvme147_bus_reset(struct scsi_cmnd *cmd)
 {
        /* FIXME perform bus-specific reset */
 
-       /* FIXME 2: kill this function, and let midlayer fallback to 
+       /* FIXME 2: kill this function, and let midlayer fallback to
           the same result, calling wd33c93_host_reset() */
 
        spin_lock_irq(cmd->device->host->host_lock);
@@ -154,10 +158,9 @@ static struct scsi_host_template driver_template = {
 int mvme147_release(struct Scsi_Host *instance)
 {
 #ifdef MODULE
-    /* XXX Make sure DMA is stopped! */
-    wd33c93_release();
-    free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
-    free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);
+       /* XXX Make sure DMA is stopped! */
+       free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
+       free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);
 #endif
-    return 1;
+       return 1;
 }
index 32aee85..bfd4566 100644 (file)
@@ -14,11 +14,11 @@ int mvme147_detect(struct scsi_host_template *);
 int mvme147_release(struct Scsi_Host *);
 
 #ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
+#define CMD_PER_LUN            2
 #endif
 
 #ifndef CAN_QUEUE
-#define CAN_QUEUE 16
+#define CAN_QUEUE              16
 #endif
 
 #endif /* MVME147_H */
index 10a5077..afc7f6f 100644 (file)
@@ -132,9 +132,9 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
        tmp &= ~PHYEV_RDY_CH;
        mvs_write_port_irq_stat(mvi, phy_id, tmp);
        tmp = mvs_read_phy_ctl(mvi, phy_id);
-       if (hard)
+       if (hard == 1)
                tmp |= PHY_RST_HARD;
-       else
+       else if (hard == 0)
                tmp |= PHY_RST;
        mvs_write_phy_ctl(mvi, phy_id, tmp);
        if (hard) {
@@ -144,6 +144,26 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
        }
 }
 
+void mvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+       if (clear_all) {
+               tmp = mr32(MVS_INT_STAT_SRS_0);
+               if (tmp) {
+                       printk(KERN_DEBUG "check SRS 0 %08X.\n", tmp);
+                       mw32(MVS_INT_STAT_SRS_0, tmp);
+               }
+       } else {
+               tmp = mr32(MVS_INT_STAT_SRS_0);
+               if (tmp &  (1 << (reg_set % 32))) {
+                       printk(KERN_DEBUG "register set 0x%x was stopped.\n",
+                              reg_set);
+                       mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32));
+               }
+       }
+}
+
 static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
@@ -761,6 +781,7 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
        mvs_write_port_irq_mask,
        mvs_get_sas_addr,
        mvs_64xx_command_active,
+       mvs_64xx_clear_srs_irq,
        mvs_64xx_issue_stop,
        mvs_start_delivery,
        mvs_rx_update,
index 0940fae..eed4c5c 100644 (file)
@@ -616,6 +616,15 @@ void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
 }
 #endif
 
+/*
+ * FIXME JEJB: temporary nop clear_srs_irq to make 94xx still work
+ * with 64xx fixes
+ */
+static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set,
+                                  u8 clear_all)
+{
+}
+
 const struct mvs_dispatch mvs_94xx_dispatch = {
        "mv94xx",
        mvs_94xx_init,
@@ -640,6 +649,7 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
        mvs_write_port_irq_mask,
        mvs_get_sas_addr,
        mvs_94xx_command_active,
+       mvs_94xx_clear_srs_irq,
        mvs_94xx_issue_stop,
        mvs_start_delivery,
        mvs_rx_update,
index cae6b2c..19ad34f 100644 (file)
@@ -37,6 +37,7 @@ static const struct mvs_chip_info mvs_chips[] = {
 };
 
 #define SOC_SAS_NUM 2
+#define SG_MX 64
 
 static struct scsi_host_template mvs_sht = {
        .module                 = THIS_MODULE,
@@ -53,10 +54,10 @@ static struct scsi_host_template mvs_sht = {
        .can_queue              = 1,
        .cmd_per_lun            = 1,
        .this_id                = -1,
-       .sg_tablesize           = SG_ALL,
+       .sg_tablesize           = SG_MX,
        .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
        .use_clustering         = ENABLE_CLUSTERING,
-       .eh_device_reset_handler        = sas_eh_device_reset_handler,
+       .eh_device_reset_handler = sas_eh_device_reset_handler,
        .eh_bus_reset_handler   = sas_eh_bus_reset_handler,
        .slave_alloc            = mvs_slave_alloc,
        .target_destroy         = sas_target_destroy,
@@ -65,19 +66,17 @@ static struct scsi_host_template mvs_sht = {
 
 static struct sas_domain_function_template mvs_transport_ops = {
        .lldd_dev_found         = mvs_dev_found,
-       .lldd_dev_gone  = mvs_dev_gone,
-
+       .lldd_dev_gone          = mvs_dev_gone,
        .lldd_execute_task      = mvs_queue_command,
        .lldd_control_phy       = mvs_phy_control,
 
        .lldd_abort_task        = mvs_abort_task,
        .lldd_abort_task_set    = mvs_abort_task_set,
        .lldd_clear_aca         = mvs_clear_aca,
-       .lldd_clear_task_set    = mvs_clear_task_set,
+       .lldd_clear_task_set    = mvs_clear_task_set,
        .lldd_I_T_nexus_reset   = mvs_I_T_nexus_reset,
        .lldd_lu_reset          = mvs_lu_reset,
        .lldd_query_task        = mvs_query_task,
-
        .lldd_port_formed       = mvs_port_formed,
        .lldd_port_deformed     = mvs_port_deformed,
 
@@ -213,7 +212,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
 
 static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
 {
-       int i, slot_nr;
+       int i = 0, slot_nr;
 
        if (mvi->flags & MVF_FLAG_SOC)
                slot_nr = MVS_SOC_SLOTS;
@@ -232,6 +231,7 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
                mvi->devices[i].dev_type = NO_DEVICE;
                mvi->devices[i].device_id = i;
                mvi->devices[i].dev_status = MVS_DEV_NORMAL;
+               init_timer(&mvi->devices[i].timer);
        }
 
        /*
@@ -437,6 +437,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
 
        sha->sas_phy = arr_phy;
        sha->sas_port = arr_port;
+       sha->core.shost = shost;
 
        sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL);
        if (!sha->lldd_ha)
@@ -574,6 +575,10 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
                }
                nhost++;
        } while (nhost < chip->n_host);
+#ifdef MVS_USE_TASKLET
+       tasklet_init(&mv_tasklet, mvs_tasklet,
+                    (unsigned long)SHOST_TO_SAS_HA(shost));
+#endif
 
        mvs_post_sas_ha_init(shost, chip);
 
index 0d21386..f5e3217 100644 (file)
@@ -259,8 +259,6 @@ static inline void mvs_free_reg_set(struct mvs_info *mvi,
                mv_printk("device has been free.\n");
                return;
        }
-       if (dev->runing_req != 0)
-               return;
        if (dev->taskfileset == MVS_ID_NOT_MAPPED)
                return;
        MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset);
@@ -762,8 +760,6 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
        }
        if (is_tmf)
                flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
-       else
-               flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
        hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
        hdr->tags = cpu_to_le32(tag);
        hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -878,14 +874,15 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
        struct mvs_slot_info *slot;
        u32 tag = 0xdeadbeef, rc, n_elem = 0;
        u32 n = num, pass = 0;
-       unsigned long flags = 0;
+       unsigned long flags = 0,  flags_libsas = 0;
 
        if (!dev->port) {
                struct task_status_struct *tsm = &t->task_status;
 
                tsm->resp = SAS_TASK_UNDELIVERED;
                tsm->stat = SAS_PHY_DOWN;
-               t->task_done(t);
+               if (dev->dev_type != SATA_DEV)
+                       t->task_done(t);
                return 0;
        }
 
@@ -910,12 +907,25 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
                else
                        tei.port = &mvi->port[dev->port->id];
 
-               if (!tei.port->port_attached) {
+               if (tei.port && !tei.port->port_attached) {
                        if (sas_protocol_ata(t->task_proto)) {
+                               struct task_status_struct *ts = &t->task_status;
+
                                mv_dprintk("port %d does not"
                                        "attached device.\n", dev->port->id);
-                               rc = SAS_PHY_DOWN;
-                               goto out_done;
+                               ts->stat = SAS_PROTO_RESPONSE;
+                               ts->stat = SAS_PHY_DOWN;
+                               spin_unlock_irqrestore(dev->sata_dev.ap->lock,
+                                                      flags_libsas);
+                               spin_unlock_irqrestore(&mvi->lock, flags);
+                               t->task_done(t);
+                               spin_lock_irqsave(&mvi->lock, flags);
+                               spin_lock_irqsave(dev->sata_dev.ap->lock,
+                                                 flags_libsas);
+                               if (n > 1)
+                                       t = list_entry(t->list.next,
+                                                      struct sas_task, list);
+                               continue;
                        } else {
                                struct task_status_struct *ts = &t->task_status;
                                ts->resp = SAS_TASK_UNDELIVERED;
@@ -973,8 +983,8 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
                        break;
                default:
                        dev_printk(KERN_ERR, mvi->dev,
-                               "unknown sas_task proto: 0x%x\n",
-                               t->task_proto);
+                                  "unknown sas_task proto: 0x%x\n",
+                                  t->task_proto);
                        rc = -EINVAL;
                        break;
                }
@@ -993,11 +1003,15 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
                spin_unlock(&t->task_state_lock);
 
                mvs_hba_memory_dump(mvi, tag, t->task_proto);
-               mvi_dev->runing_req++;
+               mvi_dev->running_req++;
                ++pass;
                mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
                if (n > 1)
                        t = list_entry(t->list.next, struct sas_task, list);
+               if (likely(pass))
+                       MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
+                                                     (MVS_CHIP_SLOT_SZ - 1));
+
        } while (--n);
        rc = 0;
        goto out_done;
@@ -1012,10 +1026,6 @@ err_out:
                        dma_unmap_sg(mvi->dev, t->scatter, n_elem,
                                     t->data_dir);
 out_done:
-       if (likely(pass)) {
-               MVS_CHIP_DISP->start_delivery(mvi,
-                       (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
-       }
        spin_unlock_irqrestore(&mvi->lock, flags);
        return rc;
 }
@@ -1187,7 +1197,7 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                                MVS_CHIP_DISP->phy_reset(mvi, i, 0);
                                goto out_done;
                        }
-               }               else if (phy->phy_type & PORT_TYPE_SAS
+               }       else if (phy->phy_type & PORT_TYPE_SAS
                        || phy->att_dev_info & PORT_SSP_INIT_MASK) {
                        phy->phy_attached = 1;
                        phy->identify.device_type =
@@ -1256,7 +1266,20 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
 
 static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
 {
-       /*Nothing*/
+       struct domain_device *dev;
+       struct mvs_phy *phy = sas_phy->lldd_phy;
+       struct mvs_info *mvi = phy->mvi;
+       struct asd_sas_port *port = sas_phy->port;
+       int phy_no = 0;
+
+       while (phy != &mvi->phy[phy_no]) {
+               phy_no++;
+               if (phy_no >= MVS_MAX_PHYS)
+                       return;
+       }
+       list_for_each_entry(dev, &port->dev_list, dev_list_node)
+               mvs_do_release_task(phy->mvi, phy_no, NULL);
+
 }
 
 
@@ -1316,6 +1339,7 @@ int mvs_dev_found_notify(struct domain_device *dev, int lock)
                goto found_out;
        }
        dev->lldd_dev = mvi_device;
+       mvi_device->dev_status = MVS_DEV_NORMAL;
        mvi_device->dev_type = dev->dev_type;
        mvi_device->mvi_info = mvi;
        if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
@@ -1351,18 +1375,18 @@ int mvs_dev_found(struct domain_device *dev)
        return mvs_dev_found_notify(dev, 1);
 }
 
-void mvs_dev_gone_notify(struct domain_device *dev, int lock)
+void mvs_dev_gone_notify(struct domain_device *dev)
 {
        unsigned long flags = 0;
        struct mvs_device *mvi_dev = dev->lldd_dev;
        struct mvs_info *mvi = mvi_dev->mvi_info;
 
-       if (lock)
-               spin_lock_irqsave(&mvi->lock, flags);
+       spin_lock_irqsave(&mvi->lock, flags);
 
        if (mvi_dev) {
                mv_dprintk("found dev[%d:%x] is gone.\n",
                        mvi_dev->device_id, mvi_dev->dev_type);
+               mvs_release_task(mvi, dev);
                mvs_free_reg_set(mvi, mvi_dev);
                mvs_free_dev(mvi_dev);
        } else {
@@ -1370,14 +1394,13 @@ void mvs_dev_gone_notify(struct domain_device *dev, int lock)
        }
        dev->lldd_dev = NULL;
 
-       if (lock)
-               spin_unlock_irqrestore(&mvi->lock, flags);
+       spin_unlock_irqrestore(&mvi->lock, flags);
 }
 
 
 void mvs_dev_gone(struct domain_device *dev)
 {
-       mvs_dev_gone_notify(dev, 1);
+       mvs_dev_gone_notify(dev);
 }
 
 static  struct sas_task *mvs_alloc_task(void)
@@ -1540,7 +1563,7 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)
                num = mvs_find_dev_phyno(dev, phyno);
                spin_lock_irqsave(&mvi->lock, flags);
                for (i = 0; i < num; i++)
-                       mvs_release_task(mvi, phyno[i], dev);
+                       mvs_release_task(mvi, dev);
                spin_unlock_irqrestore(&mvi->lock, flags);
        }
        /* If failed, fall-through I_T_Nexus reset */
@@ -1552,8 +1575,8 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)
 int mvs_I_T_nexus_reset(struct domain_device *dev)
 {
        unsigned long flags;
-       int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
-       struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
+       int rc = TMF_RESP_FUNC_FAILED;
+    struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev;
        struct mvs_info *mvi = mvi_dev->mvi_info;
 
        if (mvi_dev->dev_status != MVS_DEV_EH)
@@ -1563,10 +1586,8 @@ int mvs_I_T_nexus_reset(struct domain_device *dev)
                __func__, mvi_dev->device_id, rc);
 
        /* housekeeper */
-       num = mvs_find_dev_phyno(dev, phyno);
        spin_lock_irqsave(&mvi->lock, flags);
-       for (i = 0; i < num; i++)
-               mvs_release_task(mvi, phyno[i], dev);
+       mvs_release_task(mvi, dev);
        spin_unlock_irqrestore(&mvi->lock, flags);
 
        return rc;
@@ -1603,6 +1624,9 @@ int mvs_query_task(struct sas_task *task)
                case TMF_RESP_FUNC_FAILED:
                case TMF_RESP_FUNC_COMPLETE:
                        break;
+               default:
+                       rc = TMF_RESP_FUNC_COMPLETE;
+                       break;
                }
        }
        mv_printk("%s:rc= %d\n", __func__, rc);
@@ -1621,8 +1645,11 @@ int mvs_abort_task(struct sas_task *task)
        unsigned long flags;
        u32 tag;
 
-       if (mvi->exp_req)
-               mvi->exp_req--;
+       if (!mvi_dev) {
+               mv_printk("%s:%d TMF_RESP_FUNC_FAILED\n", __func__, __LINE__);
+               rc = TMF_RESP_FUNC_FAILED;
+       }
+
        spin_lock_irqsave(&task->task_state_lock, flags);
        if (task->task_state_flags & SAS_TASK_STATE_DONE) {
                spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -1630,6 +1657,7 @@ int mvs_abort_task(struct sas_task *task)
                goto out;
        }
        spin_unlock_irqrestore(&task->task_state_lock, flags);
+       mvi_dev->dev_status = MVS_DEV_EH;
        if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
                struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task;
 
@@ -1654,12 +1682,31 @@ int mvs_abort_task(struct sas_task *task)
                        if (task->lldd_task) {
                                slot = task->lldd_task;
                                slot_no = (u32) (slot - mvi->slot_info);
+                               spin_lock_irqsave(&mvi->lock, flags);
                                mvs_slot_complete(mvi, slot_no, 1);
+                               spin_unlock_irqrestore(&mvi->lock, flags);
                        }
                }
+
        } else if (task->task_proto & SAS_PROTOCOL_SATA ||
                task->task_proto & SAS_PROTOCOL_STP) {
                /* to do free register_set */
+               if (SATA_DEV == dev->dev_type) {
+                       struct mvs_slot_info *slot = task->lldd_task;
+                       struct task_status_struct *tstat;
+                       u32 slot_idx = (u32)(slot - mvi->slot_info);
+                       tstat = &task->task_status;
+                       mv_dprintk(KERN_DEBUG "mv_abort_task() mvi=%p task=%p "
+                                  "slot=%p slot_idx=x%x\n",
+                                  mvi, task, slot, slot_idx);
+                       tstat->stat = SAS_ABORTED_TASK;
+                       if (mvi_dev && mvi_dev->running_req)
+                               mvi_dev->running_req--;
+                       if (sas_protocol_ata(task->task_proto))
+                               mvs_free_reg_set(mvi, mvi_dev);
+                       mvs_slot_task_free(mvi, task, slot, slot_idx);
+                       return -1;
+               }
        } else {
                /* SMP */
 
@@ -1717,8 +1764,13 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
               SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset),
               sizeof(struct dev_to_host_fis));
        tstat->buf_valid_size = sizeof(*resp);
-       if (unlikely(err))
-               stat = SAS_PROTO_RESPONSE;
+       if (unlikely(err)) {
+               if (unlikely(err & CMD_ISS_STPD))
+                       stat = SAS_OPEN_REJECT;
+               else
+                       stat = SAS_PROTO_RESPONSE;
+       }
+
        return stat;
 }
 
@@ -1753,9 +1805,7 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
                        mv_printk("find reserved error, why?\n");
 
                task->ata_task.use_ncq = 0;
-               stat = SAS_PROTO_RESPONSE;
-               mvs_sata_done(mvi, task, slot_idx, 1);
-
+               mvs_sata_done(mvi, task, slot_idx, err_dw0);
        }
                break;
        default:
@@ -1772,18 +1822,20 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
        struct sas_task *task = slot->task;
        struct mvs_device *mvi_dev = NULL;
        struct task_status_struct *tstat;
+       struct domain_device *dev;
+       u32 aborted;
 
-       bool aborted;
        void *to;
        enum exec_status sts;
 
        if (mvi->exp_req)
                mvi->exp_req--;
-       if (unlikely(!task || !task->lldd_task))
+       if (unlikely(!task || !task->lldd_task || !task->dev))
                return -1;
 
        tstat = &task->task_status;
-       mvi_dev = task->dev->lldd_dev;
+       dev = task->dev;
+       mvi_dev = dev->lldd_dev;
 
        mvs_hba_cq_dump(mvi);
 
@@ -1800,8 +1852,8 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
 
        if (unlikely(aborted)) {
                tstat->stat = SAS_ABORTED_TASK;
-               if (mvi_dev)
-                       mvi_dev->runing_req--;
+               if (mvi_dev && mvi_dev->running_req)
+                       mvi_dev->running_req--;
                if (sas_protocol_ata(task->task_proto))
                        mvs_free_reg_set(mvi, mvi_dev);
 
@@ -1809,24 +1861,17 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
                return -1;
        }
 
-       if (unlikely(!mvi_dev || !slot->port->port_attached || flags)) {
-               mv_dprintk("port has not device.\n");
+       if (unlikely(!mvi_dev || flags)) {
+               if (!mvi_dev)
+                       mv_dprintk("port has not device.\n");
                tstat->stat = SAS_PHY_DOWN;
                goto out;
        }
 
-       /*
-       if (unlikely((rx_desc & RXQ_ERR) || (*(u64 *) slot->response))) {
-                mv_dprintk("Find device[%016llx] RXQ_ERR %X,
-                err info:%016llx\n",
-                SAS_ADDR(task->dev->sas_addr),
-                rx_desc, (u64)(*(u64 *) slot->response));
-       }
-       */
-
        /* error info record present */
        if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
                tstat->stat = mvs_slot_err(mvi, task, slot_idx);
+               tstat->resp = SAS_TASK_COMPLETE;
                goto out;
        }
 
@@ -1868,11 +1913,16 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
                tstat->stat = SAM_CHECK_COND;
                break;
        }
+       if (!slot->port->port_attached) {
+               mv_dprintk("port %d has removed.\n", slot->port->sas_port.id);
+               tstat->stat = SAS_PHY_DOWN;
+       }
+
 
 out:
-       if (mvi_dev) {
-               mvi_dev->runing_req--;
-               if (sas_protocol_ata(task->task_proto))
+       if (mvi_dev && mvi_dev->running_req) {
+               mvi_dev->running_req--;
+               if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req)
                        mvs_free_reg_set(mvi, mvi_dev);
        }
        mvs_slot_task_free(mvi, task, slot, slot_idx);
@@ -1888,10 +1938,10 @@ out:
        return sts;
 }
 
-void mvs_release_task(struct mvs_info *mvi,
+void mvs_do_release_task(struct mvs_info *mvi,
                int phy_no, struct domain_device *dev)
 {
-       int i = 0; u32 slot_idx;
+       u32 slot_idx;
        struct mvs_phy *phy;
        struct mvs_port *port;
        struct mvs_slot_info *slot, *slot2;
@@ -1900,6 +1950,10 @@ void mvs_release_task(struct mvs_info *mvi,
        port = phy->port;
        if (!port)
                return;
+       /* clean cmpl queue in case request is already finished */
+       mvs_int_rx(mvi, false);
+
+
 
        list_for_each_entry_safe(slot, slot2, &port->list, entry) {
                struct sas_task *task;
@@ -1911,18 +1965,22 @@ void mvs_release_task(struct mvs_info *mvi,
 
                mv_printk("Release slot [%x] tag[%x], task [%p]:\n",
                        slot_idx, slot->slot_tag, task);
-
-               if (task->task_proto & SAS_PROTOCOL_SSP) {
-                       mv_printk("attached with SSP task CDB[");
-                       for (i = 0; i < 16; i++)
-                               mv_printk(" %02x", task->ssp_task.cdb[i]);
-                       mv_printk(" ]\n");
-               }
+               MVS_CHIP_DISP->command_active(mvi, slot_idx);
 
                mvs_slot_complete(mvi, slot_idx, 1);
        }
 }
 
+void mvs_release_task(struct mvs_info *mvi,
+                     struct domain_device *dev)
+{
+       int i, phyno[WIDE_PORT_MAX_PHY], num;
+       /* housekeeper */
+       num = mvs_find_dev_phyno(dev, phyno);
+       for (i = 0; i < num; i++)
+               mvs_do_release_task(mvi, phyno[i], dev);
+}
+
 static void mvs_phy_disconnected(struct mvs_phy *phy)
 {
        phy->phy_attached = 0;
@@ -2029,16 +2087,18 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
        * we need check the interrupt status which belongs to per port.
        */
 
-       if (phy->irq_status & PHYEV_DCDR_ERR)
+       if (phy->irq_status & PHYEV_DCDR_ERR) {
                mv_dprintk("port %d STP decoding error.\n",
-               phy_no+mvi->id*mvi->chip->n_phy);
+               phy_no + mvi->id*mvi->chip->n_phy);
+       }
 
        if (phy->irq_status & PHYEV_POOF) {
                if (!(phy->phy_event & PHY_PLUG_OUT)) {
                        int dev_sata = phy->phy_type & PORT_TYPE_SATA;
                        int ready;
-                       mvs_release_task(mvi, phy_no, NULL);
+                       mvs_do_release_task(mvi, phy_no, NULL);
                        phy->phy_event |= PHY_PLUG_OUT;
+                       MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1);
                        mvs_handle_event(mvi,
                                (void *)(unsigned long)phy_no,
                                PHY_PLUG_EVENT);
@@ -2085,6 +2145,11 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                                        phy_no, tmp);
                        }
                        mvs_update_phyinfo(mvi, phy_no, 0);
+                       if (phy->phy_type & PORT_TYPE_SAS) {
+                               MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2);
+                               mdelay(10);
+                       }
+
                        mvs_bytes_dmaed(mvi, phy_no);
                        /* whether driver is going to handle hot plug */
                        if (phy->phy_event & PHY_PLUG_OUT) {
index 885858b..77ddc7c 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <scsi/libsas.h>
+#include <scsi/scsi.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/sas_ata.h>
 #include <linux/version.h>
@@ -49,7 +50,7 @@
 #define _MV_DUMP               0
 #define MVS_ID_NOT_MAPPED      0x7f
 /* #define DISABLE_HOTPLUG_DMA_FIX */
-#define MAX_EXP_RUNNING_REQ    2
+// #define MAX_EXP_RUNNING_REQ 2
 #define WIDE_PORT_MAX_PHY              4
 #define        MV_DISABLE_NCQ  0
 #define mv_printk(fmt, arg ...)        \
@@ -129,6 +130,7 @@ struct mvs_dispatch {
 
        void (*get_sas_addr)(void *buf, u32 buflen);
        void (*command_active)(struct mvs_info *mvi, u32 slot_idx);
+       void (*clear_srs_irq)(struct mvs_info *mvi, u8 reg_set, u8 clear_all);
        void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,
                                u32 tfs);
        void (*start_delivery)(struct mvs_info *mvi, u32 tx);
@@ -236,9 +238,10 @@ struct mvs_device {
        enum sas_dev_type dev_type;
        struct mvs_info *mvi_info;
        struct domain_device *sas_device;
+       struct timer_list timer;
        u32 attached_phy;
        u32 device_id;
-       u32 runing_req;
+       u32 running_req;
        u8 taskfileset;
        u8 dev_status;
        u16 reserved;
@@ -397,7 +400,9 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun);
 int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags);
 int mvs_I_T_nexus_reset(struct domain_device *dev);
 int mvs_query_task(struct sas_task *task);
-void mvs_release_task(struct mvs_info *mvi, int phy_no,
+void mvs_release_task(struct mvs_info *mvi,
+                       struct domain_device *dev);
+void mvs_do_release_task(struct mvs_info *mvi, int phy_no,
                        struct domain_device *dev);
 void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
 void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
index 909c00e..5ff8261 100644 (file)
@@ -4390,7 +4390,6 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
                                return -ENOMEM;
                }
        }
-       memset(buffer, 0, fw_control->len);
        memcpy(buffer, fw_control->buffer, fw_control->len);
        flash_update_info.sgl.addr = cpu_to_le64(phys_addr);
        flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len);
index bff4f51..cd02cea 100644 (file)
@@ -885,11 +885,13 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
        u32 tag;
        struct pm8001_hba_info *pm8001_ha;
        struct pm8001_device *pm8001_dev = dev->lldd_dev;
-       u32 device_id = pm8001_dev->device_id;
+
        pm8001_ha = pm8001_find_ha_by_dev(dev);
        spin_lock_irqsave(&pm8001_ha->lock, flags);
        pm8001_tag_alloc(pm8001_ha, &tag);
        if (pm8001_dev) {
+               u32 device_id = pm8001_dev->device_id;
+
                PM8001_DISC_DBG(pm8001_ha,
                        pm8001_printk("found dev[%d:%x] is gone.\n",
                        pm8001_dev->device_id, pm8001_dev->dev_type));
index 53aefff..c44e4ab 100644 (file)
@@ -3751,12 +3751,6 @@ static int pmcraid_check_ioctl_buffer(
                return -EINVAL;
        }
 
-       /* buffer length can't be negetive */
-       if (hdr->buffer_length < 0) {
-               pmcraid_err("ioctl: invalid buffer length specified\n");
-               return -EINVAL;
-       }
-
        /* check for appropriate buffer access */
        if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ)
                access = VERIFY_WRITE;
index c51fd1f..5df782f 100644 (file)
@@ -1,4 +1,5 @@
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
-               qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o
+               qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
+        qla_nx.o
 
 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
index 1c7ef55..3b70860 100644 (file)
@@ -12,9 +12,7 @@
 #include <linux/delay.h>
 
 static int qla24xx_vport_disable(struct fc_vport *, bool);
-static int qla84xx_reset(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *);
-int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t, uint16_t *);
-static int qla84xx_mgmt_cmd(scsi_qla_host_t *, struct msg_echo_lb *, struct fc_bsg_job *);
+
 /* SYSFS attributes --------------------------------------------------------- */
 
 static ssize_t
@@ -43,6 +41,12 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
        struct qla_hw_data *ha = vha->hw;
        int reading;
 
+       if (IS_QLA82XX(ha)) {
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                       "Firmware dump not supported for ISP82xx\n"));
+               return count;
+       }
+
        if (off != 0)
                return (0);
 
@@ -277,6 +281,12 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
                        return count;
                }
 
+               if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
+                       qla_printk(KERN_WARNING, ha,
+                               "HBA not online, failing NVRAM update.\n");
+                       return -EAGAIN;
+               }
+
                DEBUG2(qla_printk(KERN_INFO, ha,
                    "Reading flash region -- 0x%x/0x%x.\n",
                    ha->optrom_region_start, ha->optrom_region_size));
@@ -315,8 +325,8 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
                else if (start == (ha->flt_region_boot * 4) ||
                    start == (ha->flt_region_fw * 4))
                        valid = 1;
-               else if (IS_QLA25XX(ha) || IS_QLA81XX(ha))
-                   valid = 1;
+               else if (IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))
+                       valid = 1;
                if (!valid) {
                        qla_printk(KERN_WARNING, ha,
                            "Invalid start region 0x%x/0x%x.\n", start, size);
@@ -519,6 +529,7 @@ qla2x00_sysfs_write_reset(struct kobject *kobj,
        struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        struct qla_hw_data *ha = vha->hw;
+       struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
        int type;
 
        if (off != 0)
@@ -553,6 +564,20 @@ qla2x00_sysfs_write_reset(struct kobject *kobj,
                            "MPI reset failed on (%ld).\n", vha->host_no);
                scsi_unblock_requests(vha->host);
                break;
+       case 0x2025e:
+               if (!IS_QLA82XX(ha) || vha != base_vha) {
+                       qla_printk(KERN_INFO, ha,
+                           "FCoE ctx reset not supported for host%ld.\n",
+                           vha->host_no);
+                       return count;
+               }
+
+               qla_printk(KERN_INFO, ha,
+                   "Issuing FCoE CTX reset on host%ld.\n", vha->host_no);
+               set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
+               qla2xxx_wake_dpc(vha);
+               qla2x00_wait_for_fcoe_ctx_reset(vha);
+               break;
        }
        return count;
 }
@@ -838,7 +863,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
                        continue;
                if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))
                        continue;
-               if (iter->is4GBp_only == 3 && !IS_QLA81XX(vha->hw))
+               if (iter->is4GBp_only == 3 && !(IS_QLA8XXX_TYPE(vha->hw)))
                        continue;
 
                ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
@@ -862,7 +887,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha)
                        continue;
                if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
                        continue;
-               if (iter->is4GBp_only == 3 && !IS_QLA81XX(ha))
+               if (iter->is4GBp_only == 3 && !!(IS_QLA8XXX_TYPE(vha->hw)))
                        continue;
 
                sysfs_remove_bin_file(&host->shost_gendev.kobj,
@@ -968,7 +993,8 @@ qla2x00_link_state_show(struct device *dev, struct device_attribute *attr,
        int len = 0;
 
        if (atomic_read(&vha->loop_state) == LOOP_DOWN ||
-           atomic_read(&vha->loop_state) == LOOP_DEAD)
+           atomic_read(&vha->loop_state) == LOOP_DEAD ||
+           vha->device_flags & DFLG_NO_CABLE)
                len = snprintf(buf, PAGE_SIZE, "Link Down\n");
        else if (atomic_read(&vha->loop_state) != LOOP_READY ||
            test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
@@ -1179,15 +1205,15 @@ qla24xx_84xx_fw_version_show(struct device *dev,
        scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
        struct qla_hw_data *ha = vha->hw;
 
-       if (IS_QLA84XX(ha) && ha->cs84xx) {
-               if (ha->cs84xx->op_fw_version == 0) {
-                       rval = qla84xx_verify_chip(vha, status);
-       }
+       if (!IS_QLA84XX(ha))
+               return snprintf(buf, PAGE_SIZE, "\n");
+
+       if (ha->cs84xx && ha->cs84xx->op_fw_version == 0)
+               rval = qla84xx_verify_chip(vha, status);
 
        if ((rval == QLA_SUCCESS) && (status[0] == 0))
                return snprintf(buf, PAGE_SIZE, "%u\n",
                        (uint32_t)ha->cs84xx->op_fw_version);
-       }
 
        return snprintf(buf, PAGE_SIZE, "\n");
 }
@@ -1237,7 +1263,7 @@ qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
 {
        scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 
-       if (!IS_QLA81XX(vha->hw))
+       if (!IS_QLA8XXX_TYPE(vha->hw))
                return snprintf(buf, PAGE_SIZE, "\n");
 
        return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
@@ -1249,7 +1275,7 @@ qla2x00_vn_port_mac_address_show(struct device *dev,
 {
        scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 
-       if (!IS_QLA81XX(vha->hw))
+       if (!IS_QLA8XXX_TYPE(vha->hw))
                return snprintf(buf, PAGE_SIZE, "\n");
 
        return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -1706,6 +1732,22 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
                        fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
        }
 
+       if (IS_QLA25XX(ha) && ql2xenabledif) {
+               if (ha->fw_attributes & BIT_4) {
+                       vha->flags.difdix_supported = 1;
+                       DEBUG18(qla_printk(KERN_INFO, ha,
+                           "Registering for DIF/DIX type 1 and 3"
+                           " protection.\n"));
+                       scsi_host_set_prot(vha->host,
+                           SHOST_DIF_TYPE1_PROTECTION
+                           | SHOST_DIF_TYPE3_PROTECTION
+                           | SHOST_DIX_TYPE1_PROTECTION
+                           | SHOST_DIX_TYPE3_PROTECTION);
+                       scsi_host_set_guard(vha->host, SHOST_DIX_GUARD_CRC);
+               } else
+                       vha->flags.difdix_supported = 0;
+       }
+
        if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,
                                   &ha->pdev->dev)) {
                DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
@@ -1825,582 +1867,6 @@ qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
        return 0;
 }
 
-/* BSG support for ELS/CT pass through */
-inline srb_t *
-qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size)
-{
-       srb_t *sp;
-       struct qla_hw_data *ha = vha->hw;
-       struct srb_bsg_ctx *ctx;
-
-       sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
-       if (!sp)
-               goto done;
-       ctx = kzalloc(size, GFP_KERNEL);
-       if (!ctx) {
-               mempool_free(sp, ha->srb_mempool);
-               goto done;
-       }
-
-       memset(sp, 0, sizeof(*sp));
-       sp->fcport = fcport;
-       sp->ctx = ctx;
-done:
-       return sp;
-}
-
-static int
-qla2x00_process_els(struct fc_bsg_job *bsg_job)
-{
-       struct fc_rport *rport;
-       fc_port_t *fcport;
-       struct Scsi_Host *host;
-       scsi_qla_host_t *vha;
-       struct qla_hw_data *ha;
-       srb_t *sp;
-       const char *type;
-       int req_sg_cnt, rsp_sg_cnt;
-       int rval =  (DRIVER_ERROR << 16);
-       uint16_t nextlid = 0;
-       struct srb_bsg *els;
-
-       /*  Multiple SG's are not supported for ELS requests */
-        if (bsg_job->request_payload.sg_cnt > 1 ||
-               bsg_job->reply_payload.sg_cnt > 1) {
-               DEBUG2(printk(KERN_INFO
-                   "multiple SG's are not supported for ELS requests"
-                   " [request_sg_cnt: %x reply_sg_cnt: %x]\n",
-                   bsg_job->request_payload.sg_cnt,
-                   bsg_job->reply_payload.sg_cnt));
-               rval = -EPERM;
-               goto done;
-        }
-
-       /* ELS request for rport */
-       if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
-               rport = bsg_job->rport;
-               fcport = *(fc_port_t **) rport->dd_data;
-               host = rport_to_shost(rport);
-               vha = shost_priv(host);
-               ha = vha->hw;
-               type = "FC_BSG_RPT_ELS";
-
-               /* make sure the rport is logged in,
-                * if not perform fabric login
-                */
-               if (qla2x00_fabric_login(vha, fcport, &nextlid)) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "failed to login port %06X for ELS passthru\n",
-                           fcport->d_id.b24));
-                       rval = -EIO;
-                       goto done;
-               }
-       } else {
-               host = bsg_job->shost;
-               vha = shost_priv(host);
-               ha = vha->hw;
-               type = "FC_BSG_HST_ELS_NOLOGIN";
-
-               /* Allocate a dummy fcport structure, since functions
-                * preparing the IOCB and mailbox command retrieves port
-                * specific information from fcport structure. For Host based
-                * ELS commands there will be no fcport structure allocated
-                */
-               fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
-               if (!fcport) {
-                       rval = -ENOMEM;
-                       goto done;
-               }
-
-               /* Initialize all required  fields of fcport */
-               fcport->vha = vha;
-               fcport->vp_idx = vha->vp_idx;
-               fcport->d_id.b.al_pa =
-                   bsg_job->request->rqst_data.h_els.port_id[0];
-               fcport->d_id.b.area =
-                   bsg_job->request->rqst_data.h_els.port_id[1];
-               fcport->d_id.b.domain =
-                   bsg_job->request->rqst_data.h_els.port_id[2];
-               fcport->loop_id =
-                   (fcport->d_id.b.al_pa == 0xFD) ?
-                   NPH_FABRIC_CONTROLLER : NPH_F_PORT;
-       }
-
-       if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "host not online\n"));
-               rval = -EIO;
-               goto done;
-       }
-
-        req_sg_cnt =
-           dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
-           bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-        if (!req_sg_cnt) {
-               rval = -ENOMEM;
-               goto done_free_fcport;
-       }
-        rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
-           bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-        if (!rsp_sg_cnt) {
-               rval = -ENOMEM;
-                goto done_free_fcport;
-       }
-
-       if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
-           (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt))
-       {
-               DEBUG2(printk(KERN_INFO
-                   "dma mapping resulted in different sg counts \
-                   [request_sg_cnt: %x dma_request_sg_cnt: %x\
-                   reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                   bsg_job->request_payload.sg_cnt, req_sg_cnt,
-                   bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
-               rval = -EAGAIN;
-                goto done_unmap_sg;
-       }
-
-       /* Alloc SRB structure */
-       sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg));
-       if (!sp) {
-               rval = -ENOMEM;
-                goto done_unmap_sg;
-       }
-
-       els = sp->ctx;
-       els->ctx.type =
-           (bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
-           SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);
-       els->bsg_job = bsg_job;
-
-       DEBUG2(qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
-           "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
-           bsg_job->request->rqst_data.h_els.command_code,
-           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
-           fcport->d_id.b.al_pa));
-
-       rval = qla2x00_start_sp(sp);
-       if (rval != QLA_SUCCESS) {
-               kfree(sp->ctx);
-               mempool_free(sp, ha->srb_mempool);
-               rval = -EIO;
-               goto done_unmap_sg;
-       }
-       return rval;
-
-done_unmap_sg:
-       dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
-               bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-       dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
-               bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-       goto done_free_fcport;
-
-done_free_fcport:
-       if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN)
-               kfree(fcport);
-done:
-       return rval;
-}
-
-static int
-qla2x00_process_ct(struct fc_bsg_job *bsg_job)
-{
-       srb_t *sp;
-       struct Scsi_Host *host = bsg_job->shost;
-       scsi_qla_host_t *vha = shost_priv(host);
-       struct qla_hw_data *ha = vha->hw;
-       int rval = (DRIVER_ERROR << 16);
-       int req_sg_cnt, rsp_sg_cnt;
-       uint16_t loop_id;
-       struct fc_port *fcport;
-       char  *type = "FC_BSG_HST_CT";
-       struct srb_bsg *ct;
-
-       /* pass through is supported only for ISP 4Gb or higher */
-        if (!IS_FWI2_CAPABLE(ha)) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "scsi(%ld):Firmware is not capable to support FC "
-                   "CT pass thru\n", vha->host_no));
-               rval = -EPERM;
-                goto done;
-       }
-
-        req_sg_cnt =
-           dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
-           bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-        if (!req_sg_cnt) {
-               rval = -ENOMEM;
-               goto done;
-       }
-
-        rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
-            bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-        if (!rsp_sg_cnt) {
-               rval = -ENOMEM;
-                goto done;
-       }
-
-       if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
-               (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt))
-       {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "dma mapping resulted in different sg counts \
-                   [request_sg_cnt: %x dma_request_sg_cnt: %x\
-                   reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                   bsg_job->request_payload.sg_cnt, req_sg_cnt,
-                   bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
-               rval = -EAGAIN;
-                goto done_unmap_sg;
-       }
-
-       if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "host not online\n"));
-               rval = -EIO;
-                goto done_unmap_sg;
-       }
-
-       loop_id =
-           (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000)
-           >> 24;
-       switch (loop_id) {
-               case 0xFC:
-                       loop_id = cpu_to_le16(NPH_SNS);
-                       break;
-               case 0xFA:
-                       loop_id = vha->mgmt_svr_loop_id;
-                       break;
-               default:
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Unknown loop id: %x\n", loop_id));
-                       rval = -EINVAL;
-                       goto done_unmap_sg;
-       }
-
-       /* Allocate a dummy fcport structure, since functions preparing the
-        * IOCB and mailbox command retrieves port specific information
-        * from fcport structure. For Host based ELS commands there will be
-        * no fcport structure allocated
-        */
-       fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
-       if (!fcport)
-       {
-               rval = -ENOMEM;
-               goto  done_unmap_sg;
-       }
-
-       /* Initialize all required  fields of fcport */
-       fcport->vha = vha;
-       fcport->vp_idx = vha->vp_idx;
-       fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0];
-       fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1];
-       fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2];
-       fcport->loop_id = loop_id;
-
-       /* Alloc SRB structure */
-       sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_bsg));
-       if (!sp) {
-               rval = -ENOMEM;
-               goto done_free_fcport;
-       }
-
-       ct = sp->ctx;
-       ct->ctx.type = SRB_CT_CMD;
-       ct->bsg_job = bsg_job;
-
-       DEBUG2(qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
-           "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
-           (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16),
-           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
-           fcport->d_id.b.al_pa));
-
-       rval = qla2x00_start_sp(sp);
-       if (rval != QLA_SUCCESS) {
-               kfree(sp->ctx);
-               mempool_free(sp, ha->srb_mempool);
-               rval = -EIO;
-               goto done_free_fcport;
-       }
-       return rval;
-
-done_free_fcport:
-       kfree(fcport);
-done_unmap_sg:
-       dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
-           bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-       dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
-           bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-done:
-       return rval;
-}
-
-static int
-qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
-{
-       struct Scsi_Host *host = bsg_job->shost;
-       scsi_qla_host_t *vha = shost_priv(host);
-       struct qla_hw_data *ha = vha->hw;
-       int rval;
-       uint8_t command_sent;
-       uint32_t vendor_cmd;
-       char *type;
-       struct msg_echo_lb elreq;
-       uint16_t response[MAILBOX_REGISTER_COUNT];
-       uint8_t* fw_sts_ptr;
-       uint8_t *req_data;
-       dma_addr_t req_data_dma;
-       uint32_t req_data_len;
-       uint8_t *rsp_data;
-       dma_addr_t rsp_data_dma;
-       uint32_t rsp_data_len;
-
-       if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
-           test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-           test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
-               rval = -EBUSY;
-               goto done;
-       }
-
-       if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "host not online\n"));
-               rval = -EIO;
-                goto done;
-       }
-
-        elreq.req_sg_cnt =
-           dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
-           bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-        if (!elreq.req_sg_cnt) {
-               rval = -ENOMEM;
-               goto done;
-       }
-        elreq.rsp_sg_cnt =
-           dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
-           bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-        if (!elreq.rsp_sg_cnt) {
-               rval = -ENOMEM;
-                goto done;
-       }
-
-       if ((elreq.req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
-           (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt))
-       {
-               DEBUG2(printk(KERN_INFO
-                   "dma mapping resulted in different sg counts \
-                   [request_sg_cnt: %x dma_request_sg_cnt: %x\
-                   reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                   bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
-                   bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt));
-               rval = -EAGAIN;
-                goto done_unmap_sg;
-       }
-       req_data_len = rsp_data_len = bsg_job->request_payload.payload_len;
-       req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len,
-           &req_data_dma, GFP_KERNEL);
-
-       rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len,
-           &rsp_data_dma, GFP_KERNEL);
-
-       /* Copy the request buffer in req_data now */
-       sg_copy_to_buffer(bsg_job->request_payload.sg_list,
-           bsg_job->request_payload.sg_cnt, req_data,
-           req_data_len);
-
-       elreq.send_dma = req_data_dma;
-       elreq.rcv_dma = rsp_data_dma;
-       elreq.transfer_size = req_data_len;
-
-       /* Vendor cmd : loopback or ECHO diagnostic
-        * Options:
-        *      Loopback : Either internal or external loopback
-        *      ECHO: ECHO ELS or Vendor specific FC4  link data
-        */
-       vendor_cmd = bsg_job->request->rqst_data.h_vendor.vendor_cmd[0];
-       elreq.options =
-           *(((uint32_t *)bsg_job->request->rqst_data.h_vendor.vendor_cmd)
-           + 1);
-
-       switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
-       case QL_VND_LOOPBACK:
-               if (ha->current_topology != ISP_CFG_F) {
-                       type = "FC_BSG_HST_VENDOR_LOOPBACK";
-
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n",
-                               vha->host_no, type, vendor_cmd, elreq.options));
-
-                       command_sent = INT_DEF_LB_LOOPBACK_CMD;
-                       rval = qla2x00_loopback_test(vha, &elreq, response);
-                       if (IS_QLA81XX(ha)) {
-                               if (response[0] == MBS_COMMAND_ERROR && response[1] == MBS_LB_RESET) {
-                                       DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
-                                               "ISP\n", __func__, vha->host_no));
-                                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
-                                       qla2xxx_wake_dpc(vha);
-                                }
-                       }
-               } else {
-                       type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) bsg rqst type: %s vendor rqst type: %x options: %x.\n",
-                               vha->host_no, type, vendor_cmd, elreq.options));
-
-                       command_sent = INT_DEF_LB_ECHO_CMD;
-                       rval = qla2x00_echo_test(vha, &elreq, response);
-               }
-               break;
-       case QLA84_RESET:
-               if (!IS_QLA84XX(vha->hw)) {
-                       rval = -EINVAL;
-                       DEBUG16(printk(
-                               "%s(%ld): 8xxx exiting.\n",
-                               __func__, vha->host_no));
-                       return rval;
-               }
-               rval = qla84xx_reset(vha, &elreq, bsg_job);
-               break;
-       case QLA84_MGMT_CMD:
-               if (!IS_QLA84XX(vha->hw)) {
-                       rval = -EINVAL;
-                       DEBUG16(printk(
-                               "%s(%ld): 8xxx exiting.\n",
-                               __func__, vha->host_no));
-                       return rval;
-               }
-               rval = qla84xx_mgmt_cmd(vha, &elreq, bsg_job);
-               break;
-       default:
-               rval = -ENOSYS;
-       }
-
-       if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "scsi(%ld) Vendor request %s failed\n", vha->host_no, type));
-               rval = 0;
-               bsg_job->reply->result = (DID_ERROR << 16);
-               bsg_job->reply->reply_payload_rcv_len = 0;
-               fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
-               memcpy( fw_sts_ptr, response, sizeof(response));
-               fw_sts_ptr += sizeof(response);
-                *fw_sts_ptr = command_sent;
-       } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "scsi(%ld) Vendor request %s completed\n", vha->host_no, type));
-               rval = bsg_job->reply->result = 0;
-               bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t);
-               bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
-               fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
-               memcpy(fw_sts_ptr, response, sizeof(response));
-               fw_sts_ptr += sizeof(response);
-               *fw_sts_ptr = command_sent;
-               sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
-               bsg_job->reply_payload.sg_cnt, rsp_data,
-               rsp_data_len);
-       }
-       bsg_job->job_done(bsg_job);
-
-done_unmap_sg:
-
-       if(req_data)
-               dma_free_coherent(&ha->pdev->dev, req_data_len,
-                       req_data, req_data_dma);
-       dma_unmap_sg(&ha->pdev->dev,
-           bsg_job->request_payload.sg_list,
-           bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-       dma_unmap_sg(&ha->pdev->dev,
-           bsg_job->reply_payload.sg_list,
-           bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-
-done:
-        return rval;
-}
-
-static int
-qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
-{
-        int ret = -EINVAL;
-
-        switch (bsg_job->request->msgcode) {
-               case FC_BSG_RPT_ELS:
-               case FC_BSG_HST_ELS_NOLOGIN:
-                       ret = qla2x00_process_els(bsg_job);
-                       break;
-               case FC_BSG_HST_CT:
-                       ret = qla2x00_process_ct(bsg_job);
-                       break;
-               case FC_BSG_HST_VENDOR:
-                       ret = qla2x00_process_vendor_specific(bsg_job);
-                       break;
-               case FC_BSG_HST_ADD_RPORT:
-               case FC_BSG_HST_DEL_RPORT:
-               case FC_BSG_RPT_CT:
-               default:
-                       DEBUG2(printk("qla2xxx: unsupported BSG request\n"));
-                       break;
-        }
-       return ret;
-}
-
-static int
-qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
-{
-        scsi_qla_host_t *vha = shost_priv(bsg_job->shost);
-        struct qla_hw_data *ha = vha->hw;
-        srb_t *sp;
-        int cnt, que;
-        unsigned long flags;
-        struct req_que *req;
-       struct srb_bsg *sp_bsg;
-
-       /* find the bsg job from the active list of commands */
-        spin_lock_irqsave(&ha->hardware_lock, flags);
-       for (que = 0; que < ha->max_req_queues; que++) {
-               req = ha->req_q_map[que];
-               if (!req)
-                       continue;
-
-               for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++ ) {
-                       sp = req->outstanding_cmds[cnt];
-
-                       if (sp) {
-                               sp_bsg = (struct srb_bsg*)sp->ctx;
-
-                               if (((sp_bsg->ctx.type == SRB_CT_CMD) ||
-                                   (sp_bsg->ctx.type == SRB_ELS_CMD_RPT)
-                                   || ( sp_bsg->ctx.type == SRB_ELS_CMD_HST)) &&
-                                   (sp_bsg->bsg_job == bsg_job)) {
-                                       if (ha->isp_ops->abort_command(sp)) {
-                                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                               "scsi(%ld): mbx abort_command failed\n", vha->host_no));
-                                               bsg_job->req->errors = bsg_job->reply->result = -EIO;
-                                       } else {
-                                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                               "scsi(%ld): mbx abort_command success\n", vha->host_no));
-                                               bsg_job->req->errors = bsg_job->reply->result = 0;
-                                       }
-                                       goto done;
-                               }
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       DEBUG2(qla_printk(KERN_INFO, ha,
-               "scsi(%ld) SRB not found to abort\n", vha->host_no));
-       bsg_job->req->errors = bsg_job->reply->result = -ENXIO;
-       return 0;
-
-done:
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       if (bsg_job->request->msgcode == FC_BSG_HST_CT)
-               kfree(sp->fcport);
-       kfree(sp->ctx);
-       mempool_free(sp, ha->srb_mempool);
-       return 0;
-}
-
 struct fc_function_template qla2xxx_transport_functions = {
 
        .show_host_node_name = 1,
@@ -2502,7 +1968,7 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
        fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports;
        fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;
 
-       if (IS_QLA81XX(ha))
+       if (IS_QLA8XXX_TYPE(ha))
                speed = FC_PORTSPEED_10GBIT;
        else if (IS_QLA25XX(ha))
                speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
@@ -2516,125 +1982,3 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
                speed = FC_PORTSPEED_1GBIT;
        fc_host_supported_speeds(vha->host) = speed;
 }
-static int
-qla84xx_reset(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job)
-{
-       int             ret = 0;
-       int             cmd;
-       uint16_t        cmd_status;
-
-       DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no));
-
-       cmd = (*((bsg_job->request->rqst_data.h_vendor.vendor_cmd) + 2))
-                       == A84_RESET_FLAG_ENABLE_DIAG_FW ?
-                               A84_ISSUE_RESET_DIAG_FW : A84_ISSUE_RESET_OP_FW;
-       ret = qla84xx_reset_chip(ha, cmd == A84_ISSUE_RESET_DIAG_FW,
-       &cmd_status);
-       return ret;
-}
-
-static int
-qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct msg_echo_lb *mreq, struct fc_bsg_job *bsg_job)
-{
-       struct access_chip_84xx *mn;
-       dma_addr_t mn_dma, mgmt_dma;
-       void *mgmt_b = NULL;
-       int ret = 0;
-       int rsp_hdr_len, len = 0;
-       struct qla84_msg_mgmt *ql84_mgmt;
-
-       ql84_mgmt = (struct qla84_msg_mgmt *) vmalloc(sizeof(struct qla84_msg_mgmt));
-       ql84_mgmt->cmd =
-               *((uint16_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 2));
-       ql84_mgmt->mgmtp.u.mem.start_addr =
-               *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 3));
-       ql84_mgmt->len =
-               *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 4));
-       ql84_mgmt->mgmtp.u.config.id =
-               *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 5));
-       ql84_mgmt->mgmtp.u.config.param0 =
-               *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 6));
-       ql84_mgmt->mgmtp.u.config.param1 =
-               *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 7));
-       ql84_mgmt->mgmtp.u.info.type =
-               *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 8));
-       ql84_mgmt->mgmtp.u.info.context =
-               *((uint32_t *)(bsg_job->request->rqst_data.h_vendor.vendor_cmd + 9));
-
-       rsp_hdr_len = bsg_job->request_payload.payload_len;
-
-       mn = dma_pool_alloc(ha->hw->s_dma_pool, GFP_KERNEL, &mn_dma);
-       if (mn == NULL) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
-               "failed%lu\n", __func__, ha->host_no));
-               return -ENOMEM;
-       }
-
-       memset(mn, 0, sizeof (struct access_chip_84xx));
-
-       mn->entry_type = ACCESS_CHIP_IOCB_TYPE;
-       mn->entry_count = 1;
-
-       switch (ql84_mgmt->cmd) {
-       case QLA84_MGMT_READ_MEM:
-               mn->options = cpu_to_le16(ACO_DUMP_MEMORY);
-               mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr);
-               break;
-       case QLA84_MGMT_WRITE_MEM:
-               mn->options = cpu_to_le16(ACO_LOAD_MEMORY);
-               mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr);
-               break;
-       case QLA84_MGMT_CHNG_CONFIG:
-               mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM);
-               mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id);
-               mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0);
-               mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1);
-               break;
-       case QLA84_MGMT_GET_INFO:
-               mn->options = cpu_to_le16(ACO_REQUEST_INFO);
-               mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type);
-               mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context);
-               break;
-       default:
-               ret = -EIO;
-               goto exit_mgmt0;
-       }
-
-       if ((len == ql84_mgmt->len) &&
-               ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) {
-               mgmt_b = dma_alloc_coherent(&ha->hw->pdev->dev, len,
-                               &mgmt_dma, GFP_KERNEL);
-               if (mgmt_b == NULL) {
-                       DEBUG2(printk(KERN_ERR "%s: dma alloc mgmt_b "
-                       "failed%lu\n", __func__, ha->host_no));
-                       ret = -ENOMEM;
-                       goto exit_mgmt0;
-               }
-               mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len);
-               mn->dseg_count = cpu_to_le16(1);
-               mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma));
-               mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma));
-               mn->dseg_length = cpu_to_le32(len);
-
-               if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) {
-                       memcpy(mgmt_b, ql84_mgmt->payload, len);
-               }
-       }
-
-       ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0);
-       if ((ret != QLA_SUCCESS) || (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM)
-               || (ql84_mgmt->cmd == QLA84_MGMT_CHNG_CONFIG)) {
-                       if (ret != QLA_SUCCESS)
-                               DEBUG2(printk(KERN_ERR "%s(%lu): failed\n",
-                                       __func__, ha->host_no));
-       } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM) ||
-                       (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) {
-       }
-
-       if (mgmt_b)
-               dma_free_coherent(&ha->hw->pdev->dev, len, mgmt_b, mgmt_dma);
-
-exit_mgmt0:
-       dma_pool_free(ha->hw->s_dma_pool, mn, mn_dma);
-       return ret;
-}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
new file mode 100644 (file)
index 0000000..b905dfe
--- /dev/null
@@ -0,0 +1,1212 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2008 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+
+#include <linux/kthread.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+
+/* BSG support for ELS/CT pass through */
+inline srb_t *
+qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size)
+{
+       srb_t *sp;
+       struct qla_hw_data *ha = vha->hw;
+       struct srb_ctx *ctx;
+
+       sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
+       if (!sp)
+               goto done;
+       ctx = kzalloc(size, GFP_KERNEL);
+       if (!ctx) {
+               mempool_free(sp, ha->srb_mempool);
+               sp = NULL;
+               goto done;
+       }
+
+       memset(sp, 0, sizeof(*sp));
+       sp->fcport = fcport;
+       sp->ctx = ctx;
+done:
+       return sp;
+}
+
+int
+qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
+{
+       int i, ret, num_valid;
+       uint8_t *bcode;
+       struct qla_fcp_prio_entry *pri_entry;
+
+       ret = 1;
+       num_valid = 0;
+       bcode = (uint8_t *)pri_cfg;
+
+       if (bcode[0x0] != 'H' || bcode[0x1] != 'Q' || bcode[0x2] != 'O' ||
+                       bcode[0x3] != 'S') {
+               return 0;
+       }
+       if (flag != 1)
+               return ret;
+
+       pri_entry = &pri_cfg->entry[0];
+       for (i = 0; i < pri_cfg->num_entries; i++) {
+               if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
+                       num_valid++;
+               pri_entry++;
+       }
+
+       if (num_valid == 0)
+               ret = 0;
+
+       return ret;
+}
+
+static int
+qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       int ret = 0;
+       uint32_t len;
+       uint32_t oper;
+
+       bsg_job->reply->reply_payload_rcv_len = 0;
+
+       if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+               test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ret = -EBUSY;
+               goto exit_fcp_prio_cfg;
+       }
+
+       /* Get the sub command */
+       oper = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+
+       /* Only set config is allowed if config memory is not allocated */
+       if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) {
+               ret = -EINVAL;
+               goto exit_fcp_prio_cfg;
+       }
+       switch (oper) {
+       case QLFC_FCP_PRIO_DISABLE:
+               if (ha->flags.fcp_prio_enabled) {
+                       ha->flags.fcp_prio_enabled = 0;
+                       ha->fcp_prio_cfg->attributes &=
+                               ~FCP_PRIO_ATTR_ENABLE;
+                       qla24xx_update_all_fcp_prio(vha);
+                       bsg_job->reply->result = DID_OK;
+               } else {
+                       ret = -EINVAL;
+                       bsg_job->reply->result = (DID_ERROR << 16);
+                       goto exit_fcp_prio_cfg;
+               }
+               break;
+
+       case QLFC_FCP_PRIO_ENABLE:
+               if (!ha->flags.fcp_prio_enabled) {
+                       if (ha->fcp_prio_cfg) {
+                               ha->flags.fcp_prio_enabled = 1;
+                               ha->fcp_prio_cfg->attributes |=
+                                   FCP_PRIO_ATTR_ENABLE;
+                               qla24xx_update_all_fcp_prio(vha);
+                               bsg_job->reply->result = DID_OK;
+                       } else {
+                               ret = -EINVAL;
+                               bsg_job->reply->result = (DID_ERROR << 16);
+                               goto exit_fcp_prio_cfg;
+                       }
+               }
+               break;
+
+       case QLFC_FCP_PRIO_GET_CONFIG:
+               len = bsg_job->reply_payload.payload_len;
+               if (!len || len > FCP_PRIO_CFG_SIZE) {
+                       ret = -EINVAL;
+                       bsg_job->reply->result = (DID_ERROR << 16);
+                       goto exit_fcp_prio_cfg;
+               }
+
+               bsg_job->reply->result = DID_OK;
+               bsg_job->reply->reply_payload_rcv_len =
+                       sg_copy_from_buffer(
+                       bsg_job->reply_payload.sg_list,
+                       bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg,
+                       len);
+
+               break;
+
+       case QLFC_FCP_PRIO_SET_CONFIG:
+               len = bsg_job->request_payload.payload_len;
+               if (!len || len > FCP_PRIO_CFG_SIZE) {
+                       bsg_job->reply->result = (DID_ERROR << 16);
+                       ret = -EINVAL;
+                       goto exit_fcp_prio_cfg;
+               }
+
+               if (!ha->fcp_prio_cfg) {
+                       ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
+                       if (!ha->fcp_prio_cfg) {
+                               qla_printk(KERN_WARNING, ha,
+                                       "Unable to allocate memory "
+                                       "for fcp prio config data (%x).\n",
+                                       FCP_PRIO_CFG_SIZE);
+                               bsg_job->reply->result = (DID_ERROR << 16);
+                               ret = -ENOMEM;
+                               goto exit_fcp_prio_cfg;
+                       }
+               }
+
+               memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE);
+               sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg,
+                       FCP_PRIO_CFG_SIZE);
+
+               /* validate fcp priority data */
+               if (!qla24xx_fcp_prio_cfg_valid(
+                       (struct qla_fcp_prio_cfg *)
+                       ha->fcp_prio_cfg, 1)) {
+                       bsg_job->reply->result = (DID_ERROR << 16);
+                       ret = -EINVAL;
+                       /* If buffer was invalidatic int
+                        * fcp_prio_cfg is of no use
+                        */
+                       vfree(ha->fcp_prio_cfg);
+                       ha->fcp_prio_cfg = NULL;
+                       goto exit_fcp_prio_cfg;
+               }
+
+               ha->flags.fcp_prio_enabled = 0;
+               if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE)
+                       ha->flags.fcp_prio_enabled = 1;
+               qla24xx_update_all_fcp_prio(vha);
+               bsg_job->reply->result = DID_OK;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+exit_fcp_prio_cfg:
+       bsg_job->job_done(bsg_job);
+       return ret;
+}
+static int
+qla2x00_process_els(struct fc_bsg_job *bsg_job)
+{
+       struct fc_rport *rport;
+       fc_port_t *fcport;
+       struct Scsi_Host *host;
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
+       srb_t *sp;
+       const char *type;
+       int req_sg_cnt, rsp_sg_cnt;
+       int rval =  (DRIVER_ERROR << 16);
+       uint16_t nextlid = 0;
+       struct srb_ctx *els;
+
+       /*  Multiple SG's are not supported for ELS requests */
+       if (bsg_job->request_payload.sg_cnt > 1 ||
+               bsg_job->reply_payload.sg_cnt > 1) {
+               DEBUG2(printk(KERN_INFO
+                       "multiple SG's are not supported for ELS requests"
+                       " [request_sg_cnt: %x reply_sg_cnt: %x]\n",
+                       bsg_job->request_payload.sg_cnt,
+                       bsg_job->reply_payload.sg_cnt));
+               rval = -EPERM;
+               goto done;
+       }
+
+       /* ELS request for rport */
+       if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
+               rport = bsg_job->rport;
+               fcport = *(fc_port_t **) rport->dd_data;
+               host = rport_to_shost(rport);
+               vha = shost_priv(host);
+               ha = vha->hw;
+               type = "FC_BSG_RPT_ELS";
+
+               /* make sure the rport is logged in,
+                * if not perform fabric login
+                */
+               if (qla2x00_fabric_login(vha, fcport, &nextlid)) {
+                       DEBUG2(qla_printk(KERN_WARNING, ha,
+                       "failed to login port %06X for ELS passthru\n",
+                       fcport->d_id.b24));
+                       rval = -EIO;
+                       goto done;
+               }
+       } else {
+               host = bsg_job->shost;
+               vha = shost_priv(host);
+               ha = vha->hw;
+               type = "FC_BSG_HST_ELS_NOLOGIN";
+
+               /* Allocate a dummy fcport structure, since functions
+                * preparing the IOCB and mailbox command retrieves port
+                * specific information from fcport structure. For Host based
+                * ELS commands there will be no fcport structure allocated
+                */
+               fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+               if (!fcport) {
+                       rval = -ENOMEM;
+                       goto done;
+               }
+
+               /* Initialize all required  fields of fcport */
+               fcport->vha = vha;
+               fcport->vp_idx = vha->vp_idx;
+               fcport->d_id.b.al_pa =
+                       bsg_job->request->rqst_data.h_els.port_id[0];
+               fcport->d_id.b.area =
+                       bsg_job->request->rqst_data.h_els.port_id[1];
+               fcport->d_id.b.domain =
+                       bsg_job->request->rqst_data.h_els.port_id[2];
+               fcport->loop_id =
+                       (fcport->d_id.b.al_pa == 0xFD) ?
+                       NPH_FABRIC_CONTROLLER : NPH_F_PORT;
+       }
+
+       if (!vha->flags.online) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+               "host not online\n"));
+               rval = -EIO;
+               goto done;
+       }
+
+       req_sg_cnt =
+               dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       if (!req_sg_cnt) {
+               rval = -ENOMEM;
+               goto done_free_fcport;
+       }
+
+       rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+               bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+        if (!rsp_sg_cnt) {
+               rval = -ENOMEM;
+               goto done_free_fcport;
+       }
+
+       if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
+               (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
+               DEBUG2(printk(KERN_INFO
+                       "dma mapping resulted in different sg counts \
+                       [request_sg_cnt: %x dma_request_sg_cnt: %x\
+                       reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
+                       bsg_job->request_payload.sg_cnt, req_sg_cnt,
+                       bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+               rval = -EAGAIN;
+               goto done_unmap_sg;
+       }
+
+       /* Alloc SRB structure */
+       sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
+       if (!sp) {
+               rval = -ENOMEM;
+               goto done_unmap_sg;
+       }
+
+       els = sp->ctx;
+       els->type =
+               (bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
+               SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);
+       els->name =
+               (bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
+               "bsg_els_rpt" : "bsg_els_hst");
+       els->u.bsg_job = bsg_job;
+
+       DEBUG2(qla_printk(KERN_INFO, ha,
+               "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
+               "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
+               bsg_job->request->rqst_data.h_els.command_code,
+               fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+               fcport->d_id.b.al_pa));
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS) {
+               kfree(sp->ctx);
+               mempool_free(sp, ha->srb_mempool);
+               rval = -EIO;
+               goto done_unmap_sg;
+       }
+       return rval;
+
+done_unmap_sg:
+       dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+               bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+       goto done_free_fcport;
+
+done_free_fcport:
+       if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN)
+               kfree(fcport);
+done:
+       return rval;
+}
+
+static int
+qla2x00_process_ct(struct fc_bsg_job *bsg_job)
+{
+       srb_t *sp;
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       int rval = (DRIVER_ERROR << 16);
+       int req_sg_cnt, rsp_sg_cnt;
+       uint16_t loop_id;
+       struct fc_port *fcport;
+       char  *type = "FC_BSG_HST_CT";
+       struct srb_ctx *ct;
+
+       /* pass through is supported only for ISP 4Gb or higher */
+       if (!IS_FWI2_CAPABLE(ha)) {
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "scsi(%ld):Firmware is not capable to support FC "
+                   "CT pass thru\n", vha->host_no));
+               rval = -EPERM;
+               goto done;
+       }
+
+       req_sg_cnt =
+               dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+                       bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       if (!req_sg_cnt) {
+               rval = -ENOMEM;
+               goto done;
+       }
+
+       rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+               bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+       if (!rsp_sg_cnt) {
+               rval = -ENOMEM;
+               goto done;
+       }
+
+       if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
+           (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                   "[request_sg_cnt: %x dma_request_sg_cnt: %x\
+                   reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
+                   bsg_job->request_payload.sg_cnt, req_sg_cnt,
+                   bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+               rval = -EAGAIN;
+               goto done_unmap_sg;
+       }
+
+       if (!vha->flags.online) {
+               DEBUG2(qla_printk(KERN_WARNING, ha,
+                       "host not online\n"));
+               rval = -EIO;
+               goto done_unmap_sg;
+       }
+
+       loop_id =
+               (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000)
+                       >> 24;
+       switch (loop_id) {
+       case 0xFC:
+               loop_id = cpu_to_le16(NPH_SNS);
+               break;
+       case 0xFA:
+               loop_id = vha->mgmt_svr_loop_id;
+               break;
+       default:
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "Unknown loop id: %x\n", loop_id));
+               rval = -EINVAL;
+               goto done_unmap_sg;
+       }
+
+       /* Allocate a dummy fcport structure, since functions preparing the
+        * IOCB and mailbox command retrieves port specific information
+        * from fcport structure. For Host based ELS commands there will be
+        * no fcport structure allocated
+        */
+       fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+       if (!fcport) {
+               rval = -ENOMEM;
+               goto done_unmap_sg;
+       }
+
+       /* Initialize all required  fields of fcport */
+       fcport->vha = vha;
+       fcport->vp_idx = vha->vp_idx;
+       fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0];
+       fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1];
+       fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2];
+       fcport->loop_id = loop_id;
+
+       /* Alloc SRB structure */
+       sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
+       if (!sp) {
+               rval = -ENOMEM;
+               goto done_free_fcport;
+       }
+
+       ct = sp->ctx;
+       ct->type = SRB_CT_CMD;
+       ct->name = "bsg_ct";
+       ct->u.bsg_job = bsg_job;
+
+       DEBUG2(qla_printk(KERN_INFO, ha,
+               "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
+               "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
+               (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16),
+               fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+               fcport->d_id.b.al_pa));
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS) {
+               kfree(sp->ctx);
+               mempool_free(sp, ha->srb_mempool);
+               rval = -EIO;
+               goto done_free_fcport;
+       }
+       return rval;
+
+done_free_fcport:
+       kfree(fcport);
+done_unmap_sg:
+       dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+               bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+done:
+       return rval;
+}
+
+static int
+qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       int rval;
+       uint8_t command_sent;
+       char *type;
+       struct msg_echo_lb elreq;
+       uint16_t response[MAILBOX_REGISTER_COUNT];
+       uint8_t *fw_sts_ptr;
+       uint8_t *req_data = NULL;
+       dma_addr_t req_data_dma;
+       uint32_t req_data_len;
+       uint8_t *rsp_data = NULL;
+       dma_addr_t rsp_data_dma;
+       uint32_t rsp_data_len;
+
+       if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+               test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               return -EBUSY;
+
+       if (!vha->flags.online) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "host not online\n"));
+               return -EIO;
+       }
+
+       elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev,
+               bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt,
+               DMA_TO_DEVICE);
+
+       if (!elreq.req_sg_cnt)
+               return -ENOMEM;
+
+       elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
+               bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt,
+               DMA_FROM_DEVICE);
+
+       if (!elreq.rsp_sg_cnt) {
+               rval = -ENOMEM;
+               goto done_unmap_req_sg;
+       }
+
+       if ((elreq.req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
+               (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
+               DEBUG2(printk(KERN_INFO
+                       "dma mapping resulted in different sg counts "
+                       "[request_sg_cnt: %x dma_request_sg_cnt: %x "
+                       "reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
+                       bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
+                       bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt));
+               rval = -EAGAIN;
+               goto done_unmap_sg;
+       }
+       req_data_len = rsp_data_len = bsg_job->request_payload.payload_len;
+       req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len,
+               &req_data_dma, GFP_KERNEL);
+       if (!req_data) {
+               DEBUG2(printk(KERN_ERR "%s: dma alloc for req_data "
+                       "failed for host=%lu\n", __func__, vha->host_no));
+               rval = -ENOMEM;
+               goto done_unmap_sg;
+       }
+
+       rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len,
+               &rsp_data_dma, GFP_KERNEL);
+       if (!rsp_data) {
+               DEBUG2(printk(KERN_ERR "%s: dma alloc for rsp_data "
+                       "failed for host=%lu\n", __func__, vha->host_no));
+               rval = -ENOMEM;
+               goto done_free_dma_req;
+       }
+
+       /* Copy the request buffer in req_data now */
+       sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, req_data, req_data_len);
+
+       elreq.send_dma = req_data_dma;
+       elreq.rcv_dma = rsp_data_dma;
+       elreq.transfer_size = req_data_len;
+
+       elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+
+       if (ha->current_topology != ISP_CFG_F) {
+               type = "FC_BSG_HST_VENDOR_LOOPBACK";
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                       "scsi(%ld) bsg rqst type: %s\n",
+                       vha->host_no, type));
+
+               command_sent = INT_DEF_LB_LOOPBACK_CMD;
+               rval = qla2x00_loopback_test(vha, &elreq, response);
+               if (IS_QLA81XX(ha)) {
+                       if (response[0] == MBS_COMMAND_ERROR &&
+                               response[1] == MBS_LB_RESET) {
+                               DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
+                               "ISP\n", __func__, vha->host_no));
+                               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+                               qla2xxx_wake_dpc(vha);
+                       }
+               }
+       } else {
+               type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
+               command_sent = INT_DEF_LB_ECHO_CMD;
+               rval = qla2x00_echo_test(vha, &elreq, response);
+       }
+
+       if (rval) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                   "request %s failed\n", vha->host_no, type));
+
+               fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
+                   sizeof(struct fc_bsg_reply);
+
+               memcpy(fw_sts_ptr, response, sizeof(response));
+               fw_sts_ptr += sizeof(response);
+               *fw_sts_ptr = command_sent;
+               rval = 0;
+               bsg_job->reply->reply_payload_rcv_len = 0;
+               bsg_job->reply->result = (DID_ERROR << 16);
+       } else {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                       "request %s completed\n", vha->host_no, type));
+
+               bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
+                       sizeof(response) + sizeof(uint8_t);
+               bsg_job->reply->reply_payload_rcv_len =
+                       bsg_job->reply_payload.payload_len;
+               fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
+                       sizeof(struct fc_bsg_reply);
+               memcpy(fw_sts_ptr, response, sizeof(response));
+               fw_sts_ptr += sizeof(response);
+               *fw_sts_ptr = command_sent;
+               bsg_job->reply->result = DID_OK;
+               sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+                       bsg_job->reply_payload.sg_cnt, rsp_data,
+                       rsp_data_len);
+       }
+       bsg_job->job_done(bsg_job);
+
+       dma_free_coherent(&ha->pdev->dev, rsp_data_len,
+               rsp_data, rsp_data_dma);
+done_free_dma_req:
+       dma_free_coherent(&ha->pdev->dev, req_data_len,
+               req_data, req_data_dma);
+done_unmap_sg:
+       dma_unmap_sg(&ha->pdev->dev,
+           bsg_job->reply_payload.sg_list,
+           bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+done_unmap_req_sg:
+       dma_unmap_sg(&ha->pdev->dev,
+           bsg_job->request_payload.sg_list,
+           bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       return rval;
+}
+
+static int
+qla84xx_reset(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       int rval = 0;
+       uint32_t flag;
+
+       if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+           test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+           test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               return -EBUSY;
+
+       if (!IS_QLA84XX(ha)) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
+                  "exiting.\n", vha->host_no));
+               return -EINVAL;
+       }
+
+       flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+
+       rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW);
+
+       if (rval) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                   "request 84xx reset failed\n", vha->host_no));
+               rval = bsg_job->reply->reply_payload_rcv_len = 0;
+               bsg_job->reply->result = (DID_ERROR << 16);
+
+       } else {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                   "request 84xx reset completed\n", vha->host_no));
+               bsg_job->reply->result = DID_OK;
+       }
+
+       bsg_job->job_done(bsg_job);
+       return rval;
+}
+
+static int
+qla84xx_updatefw(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       struct verify_chip_entry_84xx *mn = NULL;
+       dma_addr_t mn_dma, fw_dma;
+       void *fw_buf = NULL;
+       int rval = 0;
+       uint32_t sg_cnt;
+       uint32_t data_len;
+       uint16_t options;
+       uint32_t flag;
+       uint32_t fw_ver;
+
+       if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+               test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               return -EBUSY;
+
+       if (!IS_QLA84XX(ha)) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
+                       "exiting.\n", vha->host_no));
+               return -EINVAL;
+       }
+
+       sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       if (!sg_cnt)
+               return -ENOMEM;
+
+       if (sg_cnt != bsg_job->request_payload.sg_cnt) {
+               DEBUG2(printk(KERN_INFO
+                       "dma mapping resulted in different sg counts "
+                       "request_sg_cnt: %x dma_request_sg_cnt: %x ",
+                       bsg_job->request_payload.sg_cnt, sg_cnt));
+               rval = -EAGAIN;
+               goto done_unmap_sg;
+       }
+
+       data_len = bsg_job->request_payload.payload_len;
+       fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len,
+               &fw_dma, GFP_KERNEL);
+       if (!fw_buf) {
+               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw_buf "
+                       "failed for host=%lu\n", __func__, vha->host_no));
+               rval = -ENOMEM;
+               goto done_unmap_sg;
+       }
+
+       sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, fw_buf, data_len);
+
+       mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
+       if (!mn) {
+               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
+                       "failed for host=%lu\n", __func__, vha->host_no));
+               rval = -ENOMEM;
+               goto done_free_fw_buf;
+       }
+
+       flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+       fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)fw_buf + 2)));
+
+       memset(mn, 0, sizeof(struct access_chip_84xx));
+       mn->entry_type = VERIFY_CHIP_IOCB_TYPE;
+       mn->entry_count = 1;
+
+       options = VCO_FORCE_UPDATE | VCO_END_OF_DATA;
+       if (flag == A84_ISSUE_UPDATE_DIAGFW_CMD)
+               options |= VCO_DIAG_FW;
+
+       mn->options = cpu_to_le16(options);
+       mn->fw_ver =  cpu_to_le32(fw_ver);
+       mn->fw_size =  cpu_to_le32(data_len);
+       mn->fw_seq_size =  cpu_to_le32(data_len);
+       mn->dseg_address[0] = cpu_to_le32(LSD(fw_dma));
+       mn->dseg_address[1] = cpu_to_le32(MSD(fw_dma));
+       mn->dseg_length = cpu_to_le32(data_len);
+       mn->data_seg_cnt = cpu_to_le16(1);
+
+       rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
+
+       if (rval) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                       "request 84xx updatefw failed\n", vha->host_no));
+
+               rval = bsg_job->reply->reply_payload_rcv_len = 0;
+               bsg_job->reply->result = (DID_ERROR << 16);
+
+       } else {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                       "request 84xx updatefw completed\n", vha->host_no));
+
+               bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+               bsg_job->reply->result = DID_OK;
+       }
+
+       bsg_job->job_done(bsg_job);
+       dma_pool_free(ha->s_dma_pool, mn, mn_dma);
+
+done_free_fw_buf:
+       dma_free_coherent(&ha->pdev->dev, data_len, fw_buf, fw_dma);
+
+done_unmap_sg:
+       dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+               bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+       return rval;
+}
+
+static int
+qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       struct access_chip_84xx *mn = NULL;
+       dma_addr_t mn_dma, mgmt_dma;
+       void *mgmt_b = NULL;
+       int rval = 0;
+       struct qla_bsg_a84_mgmt *ql84_mgmt;
+       uint32_t sg_cnt;
+       uint32_t data_len = 0;
+       uint32_t dma_direction = DMA_NONE;
+
+       if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+               test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               return -EBUSY;
+
+       if (!IS_QLA84XX(ha)) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
+                       "exiting.\n", vha->host_no));
+               return -EINVAL;
+       }
+
+       ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request +
+               sizeof(struct fc_bsg_request));
+       if (!ql84_mgmt) {
+               DEBUG2(printk("%s(%ld): mgmt header not provided, exiting.\n",
+                       __func__, vha->host_no));
+               return -EINVAL;
+       }
+
+       mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
+       if (!mn) {
+               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
+                       "failed for host=%lu\n", __func__, vha->host_no));
+               return -ENOMEM;
+       }
+
+       memset(mn, 0, sizeof(struct access_chip_84xx));
+       mn->entry_type = ACCESS_CHIP_IOCB_TYPE;
+       mn->entry_count = 1;
+
+       switch (ql84_mgmt->mgmt.cmd) {
+       case QLA84_MGMT_READ_MEM:
+       case QLA84_MGMT_GET_INFO:
+               sg_cnt = dma_map_sg(&ha->pdev->dev,
+                       bsg_job->reply_payload.sg_list,
+                       bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+               if (!sg_cnt) {
+                       rval = -ENOMEM;
+                       goto exit_mgmt;
+               }
+
+               dma_direction = DMA_FROM_DEVICE;
+
+               if (sg_cnt != bsg_job->reply_payload.sg_cnt) {
+                       DEBUG2(printk(KERN_INFO
+                               "dma mapping resulted in different sg counts "
+                               "reply_sg_cnt: %x dma_reply_sg_cnt: %x\n",
+                               bsg_job->reply_payload.sg_cnt, sg_cnt));
+                       rval = -EAGAIN;
+                       goto done_unmap_sg;
+               }
+
+               data_len = bsg_job->reply_payload.payload_len;
+
+               mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
+                   &mgmt_dma, GFP_KERNEL);
+               if (!mgmt_b) {
+                       DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b "
+                               "failed for host=%lu\n",
+                               __func__, vha->host_no));
+                       rval = -ENOMEM;
+                       goto done_unmap_sg;
+               }
+
+               if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) {
+                       mn->options = cpu_to_le16(ACO_DUMP_MEMORY);
+                       mn->parameter1 =
+                               cpu_to_le32(
+                               ql84_mgmt->mgmt.mgmtp.u.mem.start_addr);
+
+               } else if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO) {
+                       mn->options = cpu_to_le16(ACO_REQUEST_INFO);
+                       mn->parameter1 =
+                               cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.info.type);
+
+                       mn->parameter2 =
+                               cpu_to_le32(
+                               ql84_mgmt->mgmt.mgmtp.u.info.context);
+               }
+               break;
+
+       case QLA84_MGMT_WRITE_MEM:
+               sg_cnt = dma_map_sg(&ha->pdev->dev,
+                       bsg_job->request_payload.sg_list,
+                       bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+               if (!sg_cnt) {
+                       rval = -ENOMEM;
+                       goto exit_mgmt;
+               }
+
+               dma_direction = DMA_TO_DEVICE;
+
+               if (sg_cnt != bsg_job->request_payload.sg_cnt) {
+                       DEBUG2(printk(KERN_INFO
+                               "dma mapping resulted in different sg counts "
+                               "request_sg_cnt: %x dma_request_sg_cnt: %x ",
+                               bsg_job->request_payload.sg_cnt, sg_cnt));
+                       rval = -EAGAIN;
+                       goto done_unmap_sg;
+               }
+
+               data_len = bsg_job->request_payload.payload_len;
+               mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
+                       &mgmt_dma, GFP_KERNEL);
+               if (!mgmt_b) {
+                       DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b "
+                               "failed for host=%lu\n",
+                               __func__, vha->host_no));
+                       rval = -ENOMEM;
+                       goto done_unmap_sg;
+               }
+
+               sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+                       bsg_job->request_payload.sg_cnt, mgmt_b, data_len);
+
+               mn->options = cpu_to_le16(ACO_LOAD_MEMORY);
+               mn->parameter1 =
+                       cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.mem.start_addr);
+               break;
+
+       case QLA84_MGMT_CHNG_CONFIG:
+               mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM);
+               mn->parameter1 =
+                       cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.id);
+
+               mn->parameter2 =
+                       cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param0);
+
+               mn->parameter3 =
+                       cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param1);
+               break;
+
+       default:
+               rval = -EIO;
+               goto exit_mgmt;
+       }
+
+       if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) {
+               mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len);
+               mn->dseg_count = cpu_to_le16(1);
+               mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma));
+               mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma));
+               mn->dseg_length = cpu_to_le32(ql84_mgmt->mgmt.len);
+       }
+
+       rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0);
+
+       if (rval) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                       "request 84xx mgmt failed\n", vha->host_no));
+
+               rval = bsg_job->reply->reply_payload_rcv_len = 0;
+               bsg_job->reply->result = (DID_ERROR << 16);
+
+       } else {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
+                       "request 84xx mgmt completed\n", vha->host_no));
+
+               bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+               bsg_job->reply->result = DID_OK;
+
+               if ((ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) ||
+                       (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO)) {
+                       bsg_job->reply->reply_payload_rcv_len =
+                               bsg_job->reply_payload.payload_len;
+
+                       sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+                               bsg_job->reply_payload.sg_cnt, mgmt_b,
+                               data_len);
+               }
+       }
+
+       bsg_job->job_done(bsg_job);
+
+done_unmap_sg:
+       if (mgmt_b)
+               dma_free_coherent(&ha->pdev->dev, data_len, mgmt_b, mgmt_dma);
+
+       if (dma_direction == DMA_TO_DEVICE)
+               dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+                       bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+       else if (dma_direction == DMA_FROM_DEVICE)
+               dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+                       bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+exit_mgmt:
+       dma_pool_free(ha->s_dma_pool, mn, mn_dma);
+
+       return rval;
+}
+
+static int
+qla24xx_iidma(struct fc_bsg_job *bsg_job)
+{
+       struct Scsi_Host *host = bsg_job->shost;
+       scsi_qla_host_t *vha = shost_priv(host);
+       struct qla_hw_data *ha = vha->hw;
+       int rval = 0;
+       struct qla_port_param *port_param = NULL;
+       fc_port_t *fcport = NULL;
+       uint16_t mb[MAILBOX_REGISTER_COUNT];
+       uint8_t *rsp_ptr = NULL;
+
+       bsg_job->reply->reply_payload_rcv_len = 0;
+
+       if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+               test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               return -EBUSY;
+
+       if (!IS_IIDMA_CAPABLE(vha->hw)) {
+               DEBUG2(qla_printk(KERN_WARNING, ha, "%s(%lu): iiDMA not "
+                       "supported\n",  __func__, vha->host_no));
+               return -EINVAL;
+       }
+
+       port_param = (struct qla_port_param *)((char *)bsg_job->request +
+               sizeof(struct fc_bsg_request));
+       if (!port_param) {
+               DEBUG2(printk("%s(%ld): port_param header not provided, "
+                       "exiting.\n", __func__, vha->host_no));
+               return -EINVAL;
+       }
+
+       if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {
+               DEBUG2(printk(KERN_ERR "%s(%ld): Invalid destination type\n",
+                       __func__, vha->host_no));
+               return -EINVAL;
+       }
+
+       list_for_each_entry(fcport, &vha->vp_fcports, list) {
+               if (fcport->port_type != FCT_TARGET)
+                       continue;
+
+               if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn,
+                       fcport->port_name, sizeof(fcport->port_name)))
+                       continue;
+               break;
+       }
+
+       if (!fcport) {
+               DEBUG2(printk(KERN_ERR "%s(%ld): Failed to find port\n",
+                       __func__, vha->host_no));
+               return -EINVAL;
+       }
+
+       if (port_param->mode)
+               rval = qla2x00_set_idma_speed(vha, fcport->loop_id,
+                       port_param->speed, mb);
+       else
+               rval = qla2x00_get_idma_speed(vha, fcport->loop_id,
+                       &port_param->speed, mb);
+
+       if (rval) {
+               DEBUG16(printk(KERN_ERR "scsi(%ld): iIDMA cmd failed for "
+                       "%02x%02x%02x%02x%02x%02x%02x%02x -- "
+                       "%04x %x %04x %04x.\n",
+                       vha->host_no, fcport->port_name[0],
+                       fcport->port_name[1],
+                       fcport->port_name[2], fcport->port_name[3],
+                       fcport->port_name[4], fcport->port_name[5],
+                       fcport->port_name[6], fcport->port_name[7], rval,
+                       fcport->fp_speed, mb[0], mb[1]));
+               rval = 0;
+               bsg_job->reply->result = (DID_ERROR << 16);
+
+       } else {
+               if (!port_param->mode) {
+                       bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
+                               sizeof(struct qla_port_param);
+
+                       rsp_ptr = ((uint8_t *)bsg_job->reply) +
+                               sizeof(struct fc_bsg_reply);
+
+                       memcpy(rsp_ptr, port_param,
+                               sizeof(struct qla_port_param));
+               }
+
+               bsg_job->reply->result = DID_OK;
+       }
+
+       bsg_job->job_done(bsg_job);
+       return rval;
+}
+
+static int
+qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
+{
+       switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
+       case QL_VND_LOOPBACK:
+               return qla2x00_process_loopback(bsg_job);
+
+       case QL_VND_A84_RESET:
+               return qla84xx_reset(bsg_job);
+
+       case QL_VND_A84_UPDATE_FW:
+               return qla84xx_updatefw(bsg_job);
+
+       case QL_VND_A84_MGMT_CMD:
+               return qla84xx_mgmt_cmd(bsg_job);
+
+       case QL_VND_IIDMA:
+               return qla24xx_iidma(bsg_job);
+
+       case QL_VND_FCP_PRIO_CFG_CMD:
+               return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);
+
+       default:
+               bsg_job->reply->result = (DID_ERROR << 16);
+               bsg_job->job_done(bsg_job);
+               return -ENOSYS;
+       }
+}
+
+int
+qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
+{
+       int ret = -EINVAL;
+
+       switch (bsg_job->request->msgcode) {
+       case FC_BSG_RPT_ELS:
+       case FC_BSG_HST_ELS_NOLOGIN:
+               ret = qla2x00_process_els(bsg_job);
+               break;
+       case FC_BSG_HST_CT:
+               ret = qla2x00_process_ct(bsg_job);
+               break;
+       case FC_BSG_HST_VENDOR:
+               ret = qla2x00_process_vendor_specific(bsg_job);
+               break;
+       case FC_BSG_HST_ADD_RPORT:
+       case FC_BSG_HST_DEL_RPORT:
+       case FC_BSG_RPT_CT:
+       default:
+               DEBUG2(printk("qla2xxx: unsupported BSG request\n"));
+               break;
+       }
+       return ret;
+}
+
+int
+qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
+{
+       scsi_qla_host_t *vha = shost_priv(bsg_job->shost);
+       struct qla_hw_data *ha = vha->hw;
+       srb_t *sp;
+       int cnt, que;
+       unsigned long flags;
+       struct req_que *req;
+       struct srb_ctx *sp_bsg;
+
+       /* find the bsg job from the active list of commands */
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       for (que = 0; que < ha->max_req_queues; que++) {
+               req = ha->req_q_map[que];
+               if (!req)
+                       continue;
+
+               for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+                       sp = req->outstanding_cmds[cnt];
+                       if (sp) {
+                               sp_bsg = sp->ctx;
+
+                               if (((sp_bsg->type == SRB_CT_CMD) ||
+                                       (sp_bsg->type == SRB_ELS_CMD_HST))
+                                       && (sp_bsg->u.bsg_job == bsg_job)) {
+                                       if (ha->isp_ops->abort_command(sp)) {
+                                               DEBUG2(qla_printk(KERN_INFO, ha,
+                                                   "scsi(%ld): mbx "
+                                                   "abort_command failed\n",
+                                                   vha->host_no));
+                                               bsg_job->req->errors =
+                                               bsg_job->reply->result = -EIO;
+                                       } else {
+                                               DEBUG2(qla_printk(KERN_INFO, ha,
+                                                   "scsi(%ld): mbx "
+                                                   "abort_command success\n",
+                                                   vha->host_no));
+                                               bsg_job->req->errors =
+                                               bsg_job->reply->result = 0;
+                                       }
+                                       goto done;
+                               }
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       DEBUG2(qla_printk(KERN_INFO, ha,
+               "scsi(%ld) SRB not found to abort\n", vha->host_no));
+       bsg_job->req->errors = bsg_job->reply->result = -ENXIO;
+       return 0;
+
+done:
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       if (bsg_job->request->msgcode == FC_BSG_HST_CT)
+               kfree(sp->fcport);
+       kfree(sp->ctx);
+       mempool_free(sp, ha->srb_mempool);
+       return 0;
+}
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
new file mode 100644 (file)
index 0000000..76ed92d
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2008 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#ifndef __QLA_BSG_H
+#define __QLA_BSG_H
+
+/* BSG Vendor specific commands */
+#define QL_VND_LOOPBACK                0x01
+#define QL_VND_A84_RESET       0x02
+#define QL_VND_A84_UPDATE_FW   0x03
+#define QL_VND_A84_MGMT_CMD    0x04
+#define QL_VND_IIDMA           0x05
+#define QL_VND_FCP_PRIO_CFG_CMD        0x06
+
+/* BSG definations for interpreting CommandSent field */
+#define INT_DEF_LB_LOOPBACK_CMD         0
+#define INT_DEF_LB_ECHO_CMD             1
+
+/* BSG Vendor specific definations */
+#define A84_ISSUE_WRITE_TYPE_CMD        0
+#define A84_ISSUE_READ_TYPE_CMD         1
+#define A84_CLEANUP_CMD                 2
+#define A84_ISSUE_RESET_OP_FW           3
+#define A84_ISSUE_RESET_DIAG_FW         4
+#define A84_ISSUE_UPDATE_OPFW_CMD       5
+#define A84_ISSUE_UPDATE_DIAGFW_CMD     6
+
+struct qla84_mgmt_param {
+       union {
+               struct {
+                       uint32_t start_addr;
+               } mem; /* for QLA84_MGMT_READ/WRITE_MEM */
+               struct {
+                       uint32_t id;
+#define QLA84_MGMT_CONFIG_ID_UIF        1
+#define QLA84_MGMT_CONFIG_ID_FCOE_COS   2
+#define QLA84_MGMT_CONFIG_ID_PAUSE      3
+#define QLA84_MGMT_CONFIG_ID_TIMEOUTS   4
+
+               uint32_t param0;
+               uint32_t param1;
+       } config; /* for QLA84_MGMT_CHNG_CONFIG */
+
+       struct {
+               uint32_t type;
+#define QLA84_MGMT_INFO_CONFIG_LOG_DATA         1 /* Get Config Log Data */
+#define QLA84_MGMT_INFO_LOG_DATA                2 /* Get Log Data */
+#define QLA84_MGMT_INFO_PORT_STAT               3 /* Get Port Statistics */
+#define QLA84_MGMT_INFO_LIF_STAT                4 /* Get LIF Statistics  */
+#define QLA84_MGMT_INFO_ASIC_STAT               5 /* Get ASIC Statistics */
+#define QLA84_MGMT_INFO_CONFIG_PARAMS           6 /* Get Config Parameters */
+#define QLA84_MGMT_INFO_PANIC_LOG               7 /* Get Panic Log */
+
+               uint32_t context;
+/*
+* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA
+*/
+#define IC_LOG_DATA_LOG_ID_DEBUG_LOG                    0
+#define IC_LOG_DATA_LOG_ID_LEARN_LOG                    1
+#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG           2
+#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG            3
+#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG     4
+#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG      5
+#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG         6
+#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG          7
+#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG               8
+#define IC_LOG_DATA_LOG_ID_DCX_LOG                      9
+
+/*
+* context definitions for QLA84_MGMT_INFO_PORT_STAT
+*/
+#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0   0
+#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1   1
+#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0        2
+#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1        3
+#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0         4
+#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1         5
+
+
+/*
+* context definitions for QLA84_MGMT_INFO_LIF_STAT
+*/
+#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0     0
+#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1     1
+#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0           2
+#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1           3
+#define IC_LIF_STATISTICS_LIF_NUMBER_CPU                6
+
+               } info; /* for QLA84_MGMT_GET_INFO */
+       } u;
+};
+
+struct qla84_msg_mgmt {
+       uint16_t cmd;
+#define QLA84_MGMT_READ_MEM     0x00
+#define QLA84_MGMT_WRITE_MEM    0x01
+#define QLA84_MGMT_CHNG_CONFIG  0x02
+#define QLA84_MGMT_GET_INFO     0x03
+       uint16_t rsrvd;
+       struct qla84_mgmt_param mgmtp;/* parameters for cmd */
+       uint32_t len; /* bytes in payload following this struct */
+       uint8_t payload[0]; /* payload for cmd */
+};
+
+struct qla_bsg_a84_mgmt {
+       struct qla84_msg_mgmt mgmt;
+} __attribute__ ((packed));
+
+struct qla_scsi_addr {
+       uint16_t bus;
+       uint16_t target;
+} __attribute__ ((packed));
+
+struct qla_ext_dest_addr {
+       union {
+               uint8_t wwnn[8];
+               uint8_t wwpn[8];
+               uint8_t id[4];
+               struct qla_scsi_addr scsi_addr;
+       } dest_addr;
+       uint16_t dest_type;
+#define        EXT_DEF_TYPE_WWPN       2
+       uint16_t lun;
+       uint16_t padding[2];
+} __attribute__ ((packed));
+
+struct qla_port_param {
+       struct qla_ext_dest_addr fc_scsi_addr;
+       uint16_t mode;
+       uint16_t speed;
+} __attribute__ ((packed));
+#endif
index cb2eca4..2afc8a3 100644 (file)
@@ -769,6 +769,9 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
        void            *nxt;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
 
+       if (IS_QLA82XX(ha))
+               return;
+
        risc_address = ext_mem_cnt = 0;
        flags = 0;
 
@@ -1660,4 +1663,62 @@ qla2x00_dump_buffer(uint8_t * b, uint32_t size)
                printk("\n");
 }
 
+void
+qla2x00_dump_buffer_zipped(uint8_t *b, uint32_t size)
+{
+       uint32_t cnt;
+       uint8_t c;
+       uint8_t  last16[16], cur16[16];
+       uint32_t lc = 0, num_same16 = 0, j;
+
+       printk(KERN_DEBUG " 0   1   2   3   4   5   6   7   8   9  "
+           "Ah  Bh  Ch  Dh  Eh  Fh\n");
+       printk(KERN_DEBUG "----------------------------------------"
+           "----------------------\n");
+
+       for (cnt = 0; cnt < size;) {
+               c = *b++;
 
+               cur16[lc++] = c;
+
+               cnt++;
+               if (cnt % 16)
+                       continue;
+
+               /* We have 16 now */
+               lc = 0;
+               if (num_same16 == 0) {
+                       memcpy(last16, cur16, 16);
+                       num_same16++;
+                       continue;
+               }
+               if (memcmp(cur16, last16, 16) == 0) {
+                       num_same16++;
+                       continue;
+               }
+               for (j = 0; j < 16; j++)
+                       printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]);
+               printk(KERN_DEBUG "\n");
+
+               if (num_same16 > 1)
+                       printk(KERN_DEBUG "> prev pattern repeats (%u)"
+                           "more times\n", num_same16-1);
+               memcpy(last16, cur16, 16);
+               num_same16 = 1;
+       }
+
+       if (num_same16) {
+               for (j = 0; j < 16; j++)
+                       printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]);
+               printk(KERN_DEBUG "\n");
+
+               if (num_same16 > 1)
+                       printk(KERN_DEBUG "> prev pattern repeats (%u)"
+                           "more times\n", num_same16-1);
+       }
+       if (lc) {
+               for (j = 0; j < lc; j++)
+                       printk(KERN_DEBUG "%02x  ", (uint32_t)cur16[j]);
+               printk(KERN_DEBUG "\n");
+       }
+}
index d6d9c86..916c81f 100644 (file)
@@ -27,6 +27,9 @@
 /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
 /* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */
 /* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */
+/* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */
+
+/* #define QL_PRINTK_BUF */ /* Captures printk to buffer */
 
 /*
 * Macros use for debugging the driver.
 #define DEBUG17(x)     do {} while (0)
 #endif
 
+#if defined(QL_DEBUG_LEVEL_18)
+#define DEBUG18(x)     do {if (ql2xextended_error_logging) x; } while (0)
+#else
+#define DEBUG18(x)     do {} while (0)
+#endif
+
+
 /*
  * Firmware Dump structure definition
  */
index afa9561..8396109 100644 (file)
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_bsg_fc.h>
 
-#define QLA2XXX_DRIVER_NAME  "qla2xxx"
+#include "qla_bsg.h"
+#include "qla_nx.h"
+#define QLA2XXX_DRIVER_NAME    "qla2xxx"
+#define QLA2XXX_APIDEV         "ql2xapidev"
 
 /*
  * We have MAILBOX_REGISTER_COUNT sized arrays in a few places,
 struct req_que;
 
 /*
+ * (sd.h is not exported, hence local inclusion)
+ * Data Integrity Field tuple.
+ */
+struct sd_dif_tuple {
+       __be16 guard_tag;       /* Checksum */
+       __be16 app_tag;         /* Opaque storage */
+       __be32 ref_tag;         /* Target LBA or indirect LBA */
+};
+
+/*
  * SCSI Request Block
  */
 typedef struct srb {
@@ -205,40 +218,73 @@ typedef struct srb {
 /*
  * SRB flag definitions
  */
-#define SRB_DMA_VALID          BIT_0   /* Command sent to ISP */
+#define SRB_DMA_VALID                  BIT_0   /* Command sent to ISP */
+#define SRB_FCP_CMND_DMA_VALID         BIT_12  /* DIF: DSD List valid */
+#define SRB_CRC_CTX_DMA_VALID          BIT_2   /* DIF: context DMA valid */
+#define SRB_CRC_PROT_DMA_VALID         BIT_4   /* DIF: prot DMA valid */
+#define SRB_CRC_CTX_DSD_VALID          BIT_5   /* DIF: dsd_list valid */
+
+/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
+#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
 
 /*
  * SRB extensions.
  */
-struct srb_ctx {
-#define SRB_LOGIN_CMD  1
-#define SRB_LOGOUT_CMD 2
-       uint16_t type;
-       struct timer_list timer;
-
-       void (*free)(srb_t *sp);
-       void (*timeout)(srb_t *sp);
-};
-
-struct srb_logio {
-       struct srb_ctx ctx;
-
+struct srb_iocb {
+       union {
+               struct {
+                       uint16_t flags;
 #define SRB_LOGIN_RETRIED      BIT_0
 #define SRB_LOGIN_COND_PLOGI   BIT_1
 #define SRB_LOGIN_SKIP_PRLI    BIT_2
-       uint16_t flags;
+                       uint16_t data[2];
+               } logio;
+               struct {
+                       /*
+                        * Values for flags field below are as
+                        * defined in tsk_mgmt_entry struct
+                        * for control_flags field in qla_fw.h.
+                        */
+                       uint32_t flags;
+                       uint32_t lun;
+                       uint32_t data;
+               } tmf;
+               struct {
+                       /*
+                        * values for modif field below are as
+                        * defined in mrk_entry_24xx struct
+                        * for the modifier field in qla_fw.h.
+                        */
+                       uint8_t modif;
+                       uint16_t lun;
+                       uint32_t data;
+               } marker;
+       } u;
+
+       struct timer_list timer;
+
+       void (*done)(srb_t *);
+       void (*free)(srb_t *);
+       void (*timeout)(srb_t *);
 };
 
-struct srb_bsg_ctx {
+/* Values for srb_ctx type */
+#define SRB_LOGIN_CMD  1
+#define SRB_LOGOUT_CMD 2
 #define SRB_ELS_CMD_RPT 3
 #define SRB_ELS_CMD_HST 4
-#define SRB_CT_CMD 5
-       uint16_t type;
-};
+#define SRB_CT_CMD     5
+#define SRB_ADISC_CMD  6
+#define SRB_TM_CMD     7
+#define SRB_MARKER_CMD 8
 
-struct srb_bsg {
-       struct srb_bsg_ctx ctx;
-       struct fc_bsg_job *bsg_job;
+struct srb_ctx {
+       uint16_t type;
+       char *name;
+       union {
+               struct srb_iocb *iocb_cmd;
+               struct fc_bsg_job *bsg_job;
+       } u;
 };
 
 struct msg_echo_lb {
@@ -416,6 +462,7 @@ typedef union {
                struct device_reg_2xxx isp;
                struct device_reg_24xx isp24;
                struct device_reg_25xxmq isp25mq;
+               struct device_reg_82xx isp82;
 } device_reg_t;
 
 #define ISP_REQ_Q_IN(ha, reg) \
@@ -1299,6 +1346,66 @@ typedef struct {
        uint32_t dseg_4_length;         /* Data segment 4 length. */
 } cont_a64_entry_t;
 
+#define PO_MODE_DIF_INSERT     0
+#define PO_MODE_DIF_REMOVE     BIT_0
+#define PO_MODE_DIF_PASS       BIT_1
+#define PO_MODE_DIF_REPLACE    (BIT_0 + BIT_1)
+#define PO_ENABLE_DIF_BUNDLING BIT_8
+#define PO_ENABLE_INCR_GUARD_SEED      BIT_3
+#define PO_DISABLE_INCR_REF_TAG        BIT_5
+#define PO_DISABLE_GUARD_CHECK BIT_4
+/*
+ * ISP queue - 64-Bit addressing, continuation crc entry structure definition.
+ */
+struct crc_context {
+       uint32_t handle;                /* System handle. */
+       uint32_t ref_tag;
+       uint16_t app_tag;
+       uint8_t ref_tag_mask[4];        /* Validation/Replacement Mask*/
+       uint8_t app_tag_mask[2];        /* Validation/Replacement Mask*/
+       uint16_t guard_seed;            /* Initial Guard Seed */
+       uint16_t prot_opts;             /* Requested Data Protection Mode */
+       uint16_t blk_size;              /* Data size in bytes */
+       uint16_t runt_blk_guard;        /* Guard value for runt block (tape
+                                        * only) */
+       uint32_t byte_count;            /* Total byte count/ total data
+                                        * transfer count */
+       union {
+               struct {
+                       uint32_t        reserved_1;
+                       uint16_t        reserved_2;
+                       uint16_t        reserved_3;
+                       uint32_t        reserved_4;
+                       uint32_t        data_address[2];
+                       uint32_t        data_length;
+                       uint32_t        reserved_5[2];
+                       uint32_t        reserved_6;
+               } nobundling;
+               struct {
+                       uint32_t        dif_byte_count; /* Total DIF byte
+                                                        * count */
+                       uint16_t        reserved_1;
+                       uint16_t        dseg_count;     /* Data segment count */
+                       uint32_t        reserved_2;
+                       uint32_t        data_address[2];
+                       uint32_t        data_length;
+                       uint32_t        dif_address[2];
+                       uint32_t        dif_length;     /* Data segment 0
+                                                        * length */
+               } bundling;
+       } u;
+
+       struct fcp_cmnd fcp_cmnd;
+       dma_addr_t      crc_ctx_dma;
+       /* List of DMA context transfers */
+       struct list_head dsd_list;
+
+       /* This structure should not exceed 512 bytes */
+};
+
+#define CRC_CONTEXT_LEN_FW     (offsetof(struct crc_context, fcp_cmnd.lun))
+#define CRC_CONTEXT_FCPCMND_OFF        (offsetof(struct crc_context, fcp_cmnd.lun))
+
 /*
  * ISP queue - status entry structure definition.
  */
@@ -1359,6 +1466,7 @@ typedef struct {
 #define CS_ABORTED             0x5     /* System aborted command. */
 #define CS_TIMEOUT             0x6     /* Timeout error. */
 #define CS_DATA_OVERRUN                0x7     /* Data overrun. */
+#define CS_DIF_ERROR           0xC     /* DIF error detected  */
 
 #define CS_DATA_UNDERRUN       0x15    /* Data Underrun. */
 #define CS_QUEUE_FULL          0x1C    /* Queue Full. */
@@ -1579,6 +1687,8 @@ typedef struct fc_port {
        uint16_t loop_id;
        uint16_t old_loop_id;
 
+       uint8_t fcp_prio;
+
        uint8_t fabric_port_name[WWN_SIZE];
        uint16_t fp_speed;
 
@@ -1611,6 +1721,7 @@ typedef struct fc_port {
 #define FCF_FABRIC_DEVICE      BIT_0
 #define FCF_LOGIN_NEEDED       BIT_1
 #define FCF_FCP2_DEVICE                BIT_2
+#define FCF_ASYNC_SENT         BIT_3
 
 /* No loop ID flag. */
 #define FC_NO_LOOP_ID          0x1000
@@ -2109,6 +2220,7 @@ struct isp_operations {
 
        int (*get_flash_version) (struct scsi_qla_host *, void *);
        int (*start_scsi) (srb_t *);
+       int (*abort_isp) (struct scsi_qla_host *);
 };
 
 /* MSI-X Support *************************************************************/
@@ -2143,6 +2255,8 @@ enum qla_work_type {
        QLA_EVT_ASYNC_LOGIN_DONE,
        QLA_EVT_ASYNC_LOGOUT,
        QLA_EVT_ASYNC_LOGOUT_DONE,
+       QLA_EVT_ASYNC_ADISC,
+       QLA_EVT_ASYNC_ADISC_DONE,
        QLA_EVT_UEVENT,
 };
 
@@ -2295,6 +2409,7 @@ struct qla_hw_data {
                uint32_t        eeh_busy                :1;
                uint32_t        cpu_affinity_enabled    :1;
                uint32_t        disable_msix_handshake  :1;
+               uint32_t        fcp_prio_enabled        :1;
        } flags;
 
        /* This spinlock is used to protect "io transactions", you must
@@ -2382,7 +2497,8 @@ struct qla_hw_data {
 #define DT_ISP2532                      BIT_11
 #define DT_ISP8432                      BIT_12
 #define DT_ISP8001                     BIT_13
-#define DT_ISP_LAST                    (DT_ISP8001 << 1)
+#define DT_ISP8021                     BIT_14
+#define DT_ISP_LAST                    (DT_ISP8021 << 1)
 
 #define DT_IIDMA                        BIT_26
 #define DT_FWI2                         BIT_27
@@ -2405,6 +2521,7 @@ struct qla_hw_data {
 #define IS_QLA2532(ha)  (DT_MASK(ha) & DT_ISP2532)
 #define IS_QLA8432(ha)  (DT_MASK(ha) & DT_ISP8432)
 #define IS_QLA8001(ha) (DT_MASK(ha) & DT_ISP8001)
+#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021)
 
 #define IS_QLA23XX(ha)  (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
                        IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -2415,8 +2532,10 @@ struct qla_hw_data {
 #define IS_QLA24XX_TYPE(ha)     (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
                                IS_QLA84XX(ha))
 #define IS_QLA81XX(ha)         (IS_QLA8001(ha))
+#define IS_QLA8XXX_TYPE(ha)    (IS_QLA81XX(ha) || IS_QLA82XX(ha))
 #define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
-                               IS_QLA25XX(ha) || IS_QLA81XX(ha))
+                               IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
+                               IS_QLA82XX(ha))
 #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha))
 #define IS_NOPOLLING_TYPE(ha)  ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \
                                (ha)->flags.msix_enabled)
@@ -2496,6 +2615,9 @@ struct qla_hw_data {
        dma_addr_t      ex_init_cb_dma;
        struct ex_init_cb_81xx *ex_init_cb;
 
+       void            *async_pd;
+       dma_addr_t      async_pd_dma;
+
        /* These are used by mailbox operations. */
        volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
 
@@ -2598,6 +2720,8 @@ struct qla_hw_data {
        uint32_t        flt_region_nvram;
        uint32_t        flt_region_npiv_conf;
        uint32_t        flt_region_gold_fw;
+       uint32_t        flt_region_fcp_prio;
+       uint32_t        flt_region_bootload;
 
        /* Needed for BEACON */
        uint16_t        beacon_blink_led;
@@ -2626,6 +2750,39 @@ struct qla_hw_data {
        struct isp_operations *isp_ops;
        struct workqueue_struct *wq;
        struct qlfc_fw fw_buf;
+
+       /* FCP_CMND priority support */
+       struct qla_fcp_prio_cfg *fcp_prio_cfg;
+
+       struct dma_pool *dl_dma_pool;
+#define DSD_LIST_DMA_POOL_SIZE  512
+
+       struct dma_pool *fcp_cmnd_dma_pool;
+       mempool_t       *ctx_mempool;
+#define FCP_CMND_DMA_POOL_SIZE 512
+
+       unsigned long   nx_pcibase;             /* Base I/O address */
+       uint8_t         *nxdb_rd_ptr;           /* Doorbell read pointer */
+       unsigned long   nxdb_wr_ptr;            /* Door bell write pointer */
+
+       uint32_t        crb_win;
+       uint32_t        curr_window;
+       uint32_t        ddr_mn_window;
+       unsigned long   mn_win_crb;
+       unsigned long   ms_win_crb;
+       int             qdr_sn_window;
+       uint32_t        nx_dev_init_timeout;
+       uint32_t        nx_reset_timeout;
+       rwlock_t        hw_lock;
+       uint16_t        portnum;                /* port number */
+       int             link_width;
+       struct fw_blob  *hablob;
+       struct qla82xx_legacy_intr_set nx_legacy_intr;
+
+       uint16_t        gbl_dsd_inuse;
+       uint16_t        gbl_dsd_avail;
+       struct list_head gbl_dsd_list;
+#define NUM_DSD_CHAIN 4096
 };
 
 /*
@@ -2650,6 +2807,7 @@ typedef struct scsi_qla_host {
 
                uint32_t        management_server_logged_in :1;
                uint32_t        process_response_queue  :1;
+               uint32_t        difdix_supported:1;
        } flags;
 
        atomic_t        loop_state;
@@ -2678,10 +2836,13 @@ typedef struct scsi_qla_host {
 #define VP_DPC_NEEDED          14      /* wake up for VP dpc handling */
 #define UNLOADING              15
 #define NPIV_CONFIG_NEEDED     16
+#define ISP_UNRECOVERABLE      17
+#define FCOE_CTX_RESET_NEEDED  18      /* Initiate FCoE context reset */
 
        uint32_t        device_flags;
 #define SWITCH_FOUND           BIT_0
 #define DFLG_NO_CABLE          BIT_1
+#define DFLG_DEV_FAILED                BIT_5
 
        /* ISP configuration data. */
        uint16_t        loop_id;                /* Host adapter loop id */
@@ -2739,6 +2900,8 @@ typedef struct scsi_qla_host {
 #define VP_ERR_ADAP_NORESOURCES        5
        struct qla_hw_data *hw;
        struct req_que *req;
+       int             fw_heartbeat_counter;
+       int             seconds_since_last_heartbeat;
 } scsi_qla_host_t;
 
 /*
@@ -2791,134 +2954,16 @@ typedef struct scsi_qla_host {
 #define OPTROM_SIZE_24XX       0x100000
 #define OPTROM_SIZE_25XX       0x200000
 #define OPTROM_SIZE_81XX       0x400000
+#define OPTROM_SIZE_82XX       0x800000
+
+#define OPTROM_BURST_SIZE      0x1000
+#define OPTROM_BURST_DWORDS    (OPTROM_BURST_SIZE / 4)
+
+#define        QLA_DSDS_PER_IOCB       37
 
 #include "qla_gbl.h"
 #include "qla_dbg.h"
 #include "qla_inline.h"
 
 #define CMD_SP(Cmnd)           ((Cmnd)->SCp.ptr)
-
-/*
- * BSG Vendor specific commands
- */
-
-#define QL_VND_LOOPBACK                0x01
-#define QLA84_RESET            0x02
-#define QLA84_UPDATE_FW                0x03
-#define QLA84_MGMT_CMD         0x04
-
-/* BSG definations for interpreting CommandSent field */
-#define INT_DEF_LB_LOOPBACK_CMD         0
-#define INT_DEF_LB_ECHO_CMD             1
-
-/* BSG Vendor specific definations */
-typedef struct _A84_RESET {
-       uint16_t Flags;
-       uint16_t Reserved;
-#define A84_RESET_FLAG_ENABLE_DIAG_FW   1
-} __attribute__((packed)) A84_RESET, *PA84_RESET;
-
-#define A84_ISSUE_WRITE_TYPE_CMD        0
-#define A84_ISSUE_READ_TYPE_CMD         1
-#define A84_CLEANUP_CMD                 2
-#define A84_ISSUE_RESET_OP_FW           3
-#define A84_ISSUE_RESET_DIAG_FW         4
-#define A84_ISSUE_UPDATE_OPFW_CMD       5
-#define A84_ISSUE_UPDATE_DIAGFW_CMD     6
-
-struct qla84_mgmt_param {
-       union {
-               struct {
-                       uint32_t start_addr;
-               } mem; /* for QLA84_MGMT_READ/WRITE_MEM */
-               struct {
-                       uint32_t id;
-#define QLA84_MGMT_CONFIG_ID_UIF        1
-#define QLA84_MGMT_CONFIG_ID_FCOE_COS   2
-#define QLA84_MGMT_CONFIG_ID_PAUSE      3
-#define QLA84_MGMT_CONFIG_ID_TIMEOUTS   4
-
-               uint32_t param0;
-               uint32_t param1;
-       } config; /* for QLA84_MGMT_CHNG_CONFIG */
-
-       struct {
-               uint32_t type;
-#define QLA84_MGMT_INFO_CONFIG_LOG_DATA         1 /* Get Config Log Data */
-#define QLA84_MGMT_INFO_LOG_DATA                2 /* Get Log Data */
-#define QLA84_MGMT_INFO_PORT_STAT               3 /* Get Port Statistics */
-#define QLA84_MGMT_INFO_LIF_STAT                4 /* Get LIF Statistics  */
-#define QLA84_MGMT_INFO_ASIC_STAT               5 /* Get ASIC Statistics */
-#define QLA84_MGMT_INFO_CONFIG_PARAMS           6 /* Get Config Parameters */
-#define QLA84_MGMT_INFO_PANIC_LOG               7 /* Get Panic Log */
-
-               uint32_t context;
-/*
-* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA
-*/
-#define IC_LOG_DATA_LOG_ID_DEBUG_LOG                    0
-#define IC_LOG_DATA_LOG_ID_LEARN_LOG                    1
-#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG           2
-#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG            3
-#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG     4
-#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG      5
-#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG         6
-#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG          7
-#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG               8
-#define IC_LOG_DATA_LOG_ID_DCX_LOG                      9
-
-/*
-* context definitions for QLA84_MGMT_INFO_PORT_STAT
-*/
-#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0   0
-#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1   1
-#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0        2
-#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1        3
-#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0         4
-#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1         5
-
-
-/*
-* context definitions for QLA84_MGMT_INFO_LIF_STAT
-*/
-#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0     0
-#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1     1
-#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0           2
-#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1           3
-#define IC_LIF_STATISTICS_LIF_NUMBER_CPU                6
-
-               } info; /* for QLA84_MGMT_GET_INFO */
-       } u;
-};
-
-struct qla84_msg_mgmt {
-       uint16_t cmd;
-#define QLA84_MGMT_READ_MEM     0x00
-#define QLA84_MGMT_WRITE_MEM    0x01
-#define QLA84_MGMT_CHNG_CONFIG  0x02
-#define QLA84_MGMT_GET_INFO     0x03
-       uint16_t rsrvd;
-       struct qla84_mgmt_param mgmtp;/* parameters for cmd */
-       uint32_t len; /* bytes in payload following this struct */
-       uint8_t payload[0]; /* payload for cmd */
-};
-
-struct msg_update_fw {
-       /*
-       * diag_fw = 0  operational fw
-       *      otherwise diagnostic fw
-       * offset, len, fw_len are present to overcome the current limitation
-       * of 128Kb xfer size. The fw is sent in smaller chunks. Each chunk
-       * specifies the byte "offset" where it fits in the fw buffer. The
-       * number of bytes in each chunk is specified in "len". "fw_len"
-       * is the total size of fw. The first chunk should start at offset = 0.
-       * When offset+len == fw_len, the fw is written to the HBA.
-       */
-       uint32_t diag_fw;
-       uint32_t offset;/* start offset */
-       uint32_t len;   /* num bytes in cur xfer */
-       uint32_t fw_len; /* size of fw in bytes */
-       uint8_t fw_bytes[0];
-};
-
 #endif
index 42c5587..93f8339 100644 (file)
@@ -400,6 +400,7 @@ struct cmd_type_6 {
        struct scsi_lun lun;            /* FCP LUN (BE). */
 
        uint16_t control_flags;         /* Control flags. */
+#define CF_DIF_SEG_DESCR_ENABLE                BIT_3
 #define CF_DATA_SEG_DESCR_ENABLE       BIT_2
 #define CF_READ_DATA                   BIT_1
 #define CF_WRITE_DATA                  BIT_0
@@ -466,6 +467,43 @@ struct cmd_type_7 {
        uint32_t dseg_0_len;            /* Data segment 0 length. */
 };
 
+#define COMMAND_TYPE_CRC_2     0x6A    /* Command Type CRC_2 (Type 6)
+                                        * (T10-DIF) */
+struct cmd_type_crc_2 {
+       uint8_t entry_type;             /* Entry type. */
+       uint8_t entry_count;            /* Entry count. */
+       uint8_t sys_define;             /* System defined. */
+       uint8_t entry_status;           /* Entry Status. */
+
+       uint32_t handle;                /* System handle. */
+
+       uint16_t nport_handle;          /* N_PORT handle. */
+       uint16_t timeout;               /* Command timeout. */
+
+       uint16_t dseg_count;            /* Data segment count. */
+
+       uint16_t fcp_rsp_dseg_len;      /* FCP_RSP DSD length. */
+
+       struct scsi_lun lun;            /* FCP LUN (BE). */
+
+       uint16_t control_flags;         /* Control flags. */
+
+       uint16_t fcp_cmnd_dseg_len;             /* Data segment length. */
+       uint32_t fcp_cmnd_dseg_address[2];      /* Data segment address. */
+
+       uint32_t fcp_rsp_dseg_address[2];       /* Data segment address. */
+
+       uint32_t byte_count;            /* Total byte count. */
+
+       uint8_t port_id[3];             /* PortID of destination port. */
+       uint8_t vp_index;
+
+       uint32_t crc_context_address[2];        /* Data segment address. */
+       uint16_t crc_context_len;               /* Data segment length. */
+       uint16_t reserved_1;                    /* MUST be set to 0. */
+};
+
+
 /*
  * ISP queue - status entry structure definition.
  */
@@ -496,10 +534,17 @@ struct sts_entry_24xx {
 
        uint32_t sense_len;             /* FCP SENSE length. */
        uint32_t rsp_data_len;          /* FCP response data length. */
-
        uint8_t data[28];               /* FCP response/sense information. */
+       /*
+        * If DIF Error is set in comp_status, these additional fields are
+        * defined:
+        * &data[10] : uint8_t report_runt_bg[2];       - computed guard
+        * &data[12] : uint8_t actual_dif[8];           - DIF Data recieved
+        * &data[20] : uint8_t expected_dif[8];         - DIF Data computed
+       */
 };
 
+
 /*
  * Status entry completion status
  */
@@ -841,6 +886,8 @@ struct device_reg_24xx {
 #define FA_HW_EVENT_ENTRY_SIZE 4
 #define FA_NPIV_CONF0_ADDR     0x5C000
 #define FA_NPIV_CONF1_ADDR     0x5D000
+#define FA_FCP_PRIO0_ADDR      0x10000
+#define FA_FCP_PRIO1_ADDR      0x12000
 
 /*
  * Flash Error Log Event Codes.
@@ -1274,6 +1321,8 @@ struct qla_flt_header {
 #define FLT_REG_NPIV_CONF_0    0x29
 #define FLT_REG_NPIV_CONF_1    0x2a
 #define FLT_REG_GOLD_FW                0x2f
+#define FLT_REG_FCP_PRIO_0     0x87
+#define FLT_REG_FCP_PRIO_1     0x88
 
 struct qla_flt_region {
        uint32_t code;
@@ -1750,6 +1799,61 @@ struct ex_init_cb_81xx {
 #define FARX_ACCESS_FLASH_CONF_81XX    0x7FFD0000
 #define FARX_ACCESS_FLASH_DATA_81XX    0x7F800000
 
+/* FCP priority config defines *************************************/
+/* operations */
+#define QLFC_FCP_PRIO_DISABLE           0x0
+#define QLFC_FCP_PRIO_ENABLE            0x1
+#define QLFC_FCP_PRIO_GET_CONFIG        0x2
+#define QLFC_FCP_PRIO_SET_CONFIG        0x3
+
+struct qla_fcp_prio_entry {
+       uint16_t flags;         /* Describes parameter(s) in FCP        */
+       /* priority entry that are valid        */
+#define FCP_PRIO_ENTRY_VALID            0x1
+#define FCP_PRIO_ENTRY_TAG_VALID        0x2
+#define FCP_PRIO_ENTRY_SPID_VALID       0x4
+#define FCP_PRIO_ENTRY_DPID_VALID       0x8
+#define FCP_PRIO_ENTRY_LUNB_VALID       0x10
+#define FCP_PRIO_ENTRY_LUNE_VALID       0x20
+#define FCP_PRIO_ENTRY_SWWN_VALID       0x40
+#define FCP_PRIO_ENTRY_DWWN_VALID       0x80
+       uint8_t  tag;           /* Priority value                   */
+       uint8_t  reserved;      /* Reserved for future use          */
+       uint32_t src_pid;       /* Src port id. high order byte     */
+                               /* unused; -1 (wild card)           */
+       uint32_t dst_pid;       /* Src port id. high order byte     */
+       /* unused; -1 (wild card)           */
+       uint16_t lun_beg;       /* 1st lun num of lun range.        */
+                               /* -1 (wild card)                   */
+       uint16_t lun_end;       /* 2nd lun num of lun range.        */
+                               /* -1 (wild card)                   */
+       uint8_t  src_wwpn[8];   /* Source WWPN: -1 (wild card)      */
+       uint8_t  dst_wwpn[8];   /* Destination WWPN: -1 (wild card) */
+};
+
+struct qla_fcp_prio_cfg {
+       uint8_t  signature[4];  /* "HQOS" signature of config data  */
+       uint16_t version;       /* 1: Initial version               */
+       uint16_t length;        /* config data size in num bytes    */
+       uint16_t checksum;      /* config data bytes checksum       */
+       uint16_t num_entries;   /* Number of entries                */
+       uint16_t size_of_entry; /* Size of each entry in num bytes  */
+       uint8_t  attributes;    /* enable/disable, persistence      */
+#define FCP_PRIO_ATTR_DISABLE   0x0
+#define FCP_PRIO_ATTR_ENABLE    0x1
+#define FCP_PRIO_ATTR_PERSIST   0x2
+       uint8_t  reserved;      /* Reserved for future use          */
+#define FCP_PRIO_CFG_HDR_SIZE   0x10
+       struct qla_fcp_prio_entry entry[1];     /* fcp priority entries  */
+#define FCP_PRIO_CFG_ENTRY_SIZE 0x20
+};
+
+#define FCP_PRIO_CFG_SIZE       (32*1024) /* fcp prio data per port*/
+
+/* 25XX Support ****************************************************/
+#define FA_FCP_PRIO0_ADDR_25   0x3C000
+#define FA_FCP_PRIO1_ADDR_25   0x3E000
+
 /* 81XX Flash locations -- occupies second 2MB region. */
 #define FA_BOOT_CODE_ADDR_81   0x80000
 #define FA_RISC_CODE_ADDR_81   0xA0000
index 3a89bc5..8217c3b 100644 (file)
@@ -44,6 +44,7 @@ extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
 extern void qla2x00_update_fcports(scsi_qla_host_t *);
 
 extern int qla2x00_abort_isp(scsi_qla_host_t *);
+extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *);
 
 extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
 
@@ -55,10 +56,20 @@ extern void qla84xx_put_chip(struct scsi_qla_host *);
 extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
 extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
-extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
+extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
-extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
+extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
+extern int qla2x00_async_marker(fc_port_t *, uint16_t, uint8_t);
+extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
+extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
+    uint16_t *);
+extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *,
+    uint16_t *);
+extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *,
+       struct srb_iocb *);
+extern void qla2x00_async_marker_done(struct scsi_qla_host *, fc_port_t *,
+       struct srb_iocb *);
 
 extern fc_port_t *
 qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
@@ -79,6 +90,13 @@ extern int ql2xmaxqueues;
 extern int ql2xmultique_tag;
 extern int ql2xfwloadbin;
 extern int ql2xetsenable;
+extern int ql2xshiftctondsd;
+extern int ql2xdbwr;
+extern int ql2xdontresethba;
+extern int ql2xasynctmfenable;
+extern int ql2xenabledif;
+extern int ql2xenablehba_err_chk;
+extern int ql2xtargetreset;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -93,6 +111,10 @@ extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
 extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *,
     fc_port_t *, uint16_t *);
+extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
+    uint16_t *);
+extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
+    fc_port_t *, uint16_t *);
 extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
 
 extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -135,6 +157,7 @@ extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
 
 extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
 extern int qla2x00_wait_for_chip_reset(scsi_qla_host_t *);
+extern int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *);
 
 extern void qla2xxx_wake_dpc(struct scsi_qla_host *);
 extern void qla2x00_alert_all_vps(struct rsp_que *, uint16_t *);
@@ -157,6 +180,10 @@ int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
                                                uint16_t, uint16_t, uint8_t);
 extern int qla2x00_start_sp(srb_t *);
 extern void qla2x00_ctx_sp_free(srb_t *);
+extern uint16_t qla24xx_calc_iocbs(uint16_t);
+extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
+extern int qla24xx_dif_start_scsi(srb_t *);
+
 
 /*
  * Global Function Prototypes in qla_mbx.c source file.
@@ -328,6 +355,9 @@ extern int
 qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
 
 extern int qla2x00_get_data_rate(scsi_qla_host_t *);
+extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t,
+       uint16_t *);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
@@ -340,6 +370,7 @@ qla24xx_process_response_queue(struct scsi_qla_host *, struct rsp_que *);
 extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *);
 extern void qla2x00_free_irqs(scsi_qla_host_t *);
 
+extern int qla2x00_get_data_rate(scsi_qla_host_t *);
 /*
  * Global Function Prototypes in qla_sup.c source file.
  */
@@ -384,6 +415,7 @@ extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
 extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
 
 extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *);
+extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *);
 
 /*
  * Global Function Prototypes in qla_dbg.c source file.
@@ -395,6 +427,7 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla81xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla2x00_dump_regs(scsi_qla_host_t *);
 extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
+extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
 
 /*
  * Global Function Prototypes in qla_gs.c source file.
@@ -430,7 +463,10 @@ extern void qla2x00_init_host_attr(scsi_qla_host_t *);
 extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
 extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
 extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
-extern int qla2x00_echo_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *);
+extern int qla2x00_echo_test(scsi_qla_host_t *,
+       struct msg_echo_lb *, uint16_t *);
+extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *);
+extern int qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *, uint8_t);
 
 /*
  * Global Function Prototypes in qla_dfs.c source file.
@@ -459,4 +495,88 @@ extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
 extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
 
+/* qla82xx related functions */
+
+/* PCI related functions */
+extern int qla82xx_pci_config(struct scsi_qla_host *);
+extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int);
+extern int qla82xx_pci_mem_write_2M(struct qla_hw_data *, u64, void *, int);
+extern char *qla82xx_pci_info_str(struct scsi_qla_host *, char *);
+extern int qla82xx_pci_region_offset(struct pci_dev *, int);
+extern int qla82xx_pci_region_len(struct pci_dev *, int);
+extern int qla82xx_iospace_config(struct qla_hw_data *);
+
+/* Initialization related functions */
+extern void qla82xx_reset_chip(struct scsi_qla_host *);
+extern void qla82xx_config_rings(struct scsi_qla_host *);
+extern int qla82xx_nvram_config(struct scsi_qla_host *);
+extern int qla82xx_pinit_from_rom(scsi_qla_host_t *);
+extern int qla82xx_load_firmware(scsi_qla_host_t *);
+extern int qla82xx_reset_hw(scsi_qla_host_t *);
+extern int qla82xx_load_risc_blob(scsi_qla_host_t *, uint32_t *);
+extern void qla82xx_watchdog(scsi_qla_host_t *);
+
+/* Firmware and flash related functions */
+extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *);
+extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+    uint32_t, uint32_t);
+extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
+    uint32_t, uint32_t);
+
+/* Mailbox related functions */
+extern int qla82xx_abort_isp(scsi_qla_host_t *);
+extern int qla82xx_restart_isp(scsi_qla_host_t *);
+
+/* IOCB related functions */
+extern int qla82xx_start_scsi(srb_t *);
+
+/* Interrupt related */
+extern irqreturn_t qla82xx_intr_handler(int, void *);
+extern irqreturn_t qla82xx_msi_handler(int, void *);
+extern irqreturn_t qla82xx_msix_default(int, void *);
+extern irqreturn_t qla82xx_msix_rsp_q(int, void *);
+extern void qla82xx_enable_intrs(struct qla_hw_data *);
+extern void qla82xx_disable_intrs(struct qla_hw_data *);
+extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t);
+extern void qla82xx_poll(int, void *);
+extern void qla82xx_init_flags(struct qla_hw_data *);
+
+/* ISP 8021 hardware related */
+extern int qla82xx_crb_win_lock(struct qla_hw_data *);
+extern void qla82xx_crb_win_unlock(struct qla_hw_data *);
+extern int qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *, ulong *);
+extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32);
+extern int qla82xx_rd_32(struct qla_hw_data *, ulong);
+extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int);
+extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int);
+extern int qla82xx_check_for_bad_spd(struct qla_hw_data *);
+extern int qla82xx_load_fw(scsi_qla_host_t *);
+extern int qla82xx_rom_lock(struct qla_hw_data *);
+extern void qla82xx_rom_unlock(struct qla_hw_data *);
+extern int qla82xx_rom_fast_read(struct qla_hw_data *, int , int *);
+extern int qla82xx_do_rom_fast_read(struct qla_hw_data *, int, int *);
+extern unsigned long qla82xx_decode_crb_addr(unsigned long);
+
+/* ISP 8021 IDC */
+extern void qla82xx_clear_drv_active(struct qla_hw_data *);
+extern int qla82xx_idc_lock(struct qla_hw_data *);
+extern void qla82xx_idc_unlock(struct qla_hw_data *);
+extern int qla82xx_device_state_handler(scsi_qla_host_t *);
+
+extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
+    size_t, char *);
+extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
+extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
+extern void qla82xx_start_iocbs(srb_t *);
+extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *);
+extern void qla82xx_wait_for_pending_commands(scsi_qla_host_t *);
+
+/* BSG related functions */
+extern int qla24xx_bsg_request(struct fc_bsg_job *);
+extern int qla24xx_bsg_timeout(struct fc_bsg_job *);
+extern int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t);
+extern int qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *,
+       dma_addr_t, size_t, uint32_t);
+extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t,
+       uint16_t *, uint16_t *);
 #endif /* _QLA_GBL_H */
index 4647015..872c55f 100644 (file)
@@ -1535,7 +1535,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
        eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
        eiter->len = __constant_cpu_to_be16(4 + 4);
-       if (IS_QLA81XX(ha))
+       if (IS_QLA8XXX_TYPE(ha))
                eiter->a.sup_speed = __constant_cpu_to_be32(
                    FDMI_PORT_SPEED_10GB);
        else if (IS_QLA25XX(ha))
index 4229bb4..ab2cc71 100644 (file)
@@ -48,6 +48,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data)
 {
        srb_t *sp = (srb_t *)__data;
        struct srb_ctx *ctx;
+       struct srb_iocb *iocb;
        fc_port_t *fcport = sp->fcport;
        struct qla_hw_data *ha = fcport->vha->hw;
        struct req_que *req;
@@ -57,17 +58,21 @@ qla2x00_ctx_sp_timeout(unsigned long __data)
        req = ha->req_q_map[0];
        req->outstanding_cmds[sp->handle] = NULL;
        ctx = sp->ctx;
-       ctx->timeout(sp);
+       iocb = ctx->u.iocb_cmd;
+       iocb->timeout(sp);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       ctx->free(sp);
+       iocb->free(sp);
 }
 
 void
 qla2x00_ctx_sp_free(srb_t *sp)
 {
        struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = ctx->u.iocb_cmd;
 
+       del_timer_sync(&iocb->timer);
+       kfree(iocb);
        kfree(ctx);
        mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
 }
@@ -79,6 +84,7 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
        srb_t *sp;
        struct qla_hw_data *ha = vha->hw;
        struct srb_ctx *ctx;
+       struct srb_iocb *iocb;
 
        sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
        if (!sp)
@@ -86,21 +92,30 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
        ctx = kzalloc(size, GFP_KERNEL);
        if (!ctx) {
                mempool_free(sp, ha->srb_mempool);
+               sp = NULL;
+               goto done;
+       }
+       iocb = kzalloc(sizeof(struct srb_iocb), GFP_KERNEL);
+       if (!iocb) {
+               mempool_free(sp, ha->srb_mempool);
+               sp = NULL;
+               kfree(ctx);
                goto done;
        }
 
        memset(sp, 0, sizeof(*sp));
        sp->fcport = fcport;
        sp->ctx = ctx;
-       ctx->free = qla2x00_ctx_sp_free;
+       ctx->u.iocb_cmd = iocb;
+       iocb->free = qla2x00_ctx_sp_free;
 
-       init_timer(&ctx->timer);
+       init_timer(&iocb->timer);
        if (!tmo)
                goto done;
-       ctx->timer.expires = jiffies + tmo * HZ;
-       ctx->timer.data = (unsigned long)sp;
-       ctx->timer.function = qla2x00_ctx_sp_timeout;
-       add_timer(&ctx->timer);
+       iocb->timer.expires = jiffies + tmo * HZ;
+       iocb->timer.data = (unsigned long)sp;
+       iocb->timer.function = qla2x00_ctx_sp_timeout;
+       add_timer(&iocb->timer);
 done:
        return sp;
 }
@@ -110,41 +125,56 @@ done:
 #define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
 
 static void
-qla2x00_async_logio_timeout(srb_t *sp)
+qla2x00_async_iocb_timeout(srb_t *sp)
 {
        fc_port_t *fcport = sp->fcport;
-       struct srb_logio *lio = sp->ctx;
+       struct srb_ctx *ctx = sp->ctx;
 
        DEBUG2(printk(KERN_WARNING
            "scsi(%ld:%x): Async-%s timeout.\n",
-           fcport->vha->host_no, sp->handle,
-           lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout"));
+           fcport->vha->host_no, sp->handle, ctx->name));
 
-       if (lio->ctx.type == SRB_LOGIN_CMD)
+       fcport->flags &= ~FCF_ASYNC_SENT;
+       if (ctx->type == SRB_LOGIN_CMD)
                qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
 }
 
+static void
+qla2x00_async_login_ctx_done(srb_t *sp)
+{
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *lio = ctx->u.iocb_cmd;
+
+       qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport,
+               lio->u.logio.data);
+       lio->free(sp);
+}
+
 int
 qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
        struct qla_hw_data *ha = vha->hw;
        srb_t *sp;
-       struct srb_logio *lio;
+       struct srb_ctx *ctx;
+       struct srb_iocb *lio;
        int rval;
 
        rval = QLA_FUNCTION_FAILED;
-       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
+       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
            ELS_TMO_2_RATOV(ha) + 2);
        if (!sp)
                goto done;
 
-       lio = sp->ctx;
-       lio->ctx.type = SRB_LOGIN_CMD;
-       lio->ctx.timeout = qla2x00_async_logio_timeout;
-       lio->flags |= SRB_LOGIN_COND_PLOGI;
+       ctx = sp->ctx;
+       ctx->type = SRB_LOGIN_CMD;
+       ctx->name = "login";
+       lio = ctx->u.iocb_cmd;
+       lio->timeout = qla2x00_async_iocb_timeout;
+       lio->done = qla2x00_async_login_ctx_done;
+       lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
        if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
-               lio->flags |= SRB_LOGIN_RETRIED;
+               lio->u.logio.flags |= SRB_LOGIN_RETRIED;
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
@@ -157,29 +187,43 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
        return rval;
 
 done_free_sp:
-       del_timer_sync(&lio->ctx.timer);
-       lio->ctx.free(sp);
+       lio->free(sp);
 done:
        return rval;
 }
 
+static void
+qla2x00_async_logout_ctx_done(srb_t *sp)
+{
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *lio = ctx->u.iocb_cmd;
+
+       qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport,
+           lio->u.logio.data);
+       lio->free(sp);
+}
+
 int
 qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
        struct qla_hw_data *ha = vha->hw;
        srb_t *sp;
-       struct srb_logio *lio;
+       struct srb_ctx *ctx;
+       struct srb_iocb *lio;
        int rval;
 
        rval = QLA_FUNCTION_FAILED;
-       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
+       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
            ELS_TMO_2_RATOV(ha) + 2);
        if (!sp)
                goto done;
 
-       lio = sp->ctx;
-       lio->ctx.type = SRB_LOGOUT_CMD;
-       lio->ctx.timeout = qla2x00_async_logio_timeout;
+       ctx = sp->ctx;
+       ctx->type = SRB_LOGOUT_CMD;
+       ctx->name = "logout";
+       lio = ctx->u.iocb_cmd;
+       lio->timeout = qla2x00_async_iocb_timeout;
+       lio->done = qla2x00_async_logout_ctx_done;
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
@@ -191,30 +235,186 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       del_timer_sync(&lio->ctx.timer);
-       lio->ctx.free(sp);
+       lio->free(sp);
 done:
        return rval;
 }
 
+static void
+qla2x00_async_adisc_ctx_done(srb_t *sp)
+{
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *lio = ctx->u.iocb_cmd;
+
+       qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport,
+           lio->u.logio.data);
+       lio->free(sp);
+}
+
 int
+qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
+    uint16_t *data)
+{
+       struct qla_hw_data *ha = vha->hw;
+       srb_t *sp;
+       struct srb_ctx *ctx;
+       struct srb_iocb *lio;
+       int rval;
+
+       rval = QLA_FUNCTION_FAILED;
+       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
+           ELS_TMO_2_RATOV(ha) + 2);
+       if (!sp)
+               goto done;
+
+       ctx = sp->ctx;
+       ctx->type = SRB_ADISC_CMD;
+       ctx->name = "adisc";
+       lio = ctx->u.iocb_cmd;
+       lio->timeout = qla2x00_async_iocb_timeout;
+       lio->done = qla2x00_async_adisc_ctx_done;
+       if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
+               lio->u.logio.flags |= SRB_LOGIN_RETRIED;
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       DEBUG2(printk(KERN_DEBUG
+           "scsi(%ld:%x): Async-adisc - loop-id=%x portid=%02x%02x%02x.\n",
+           fcport->vha->host_no, sp->handle, fcport->loop_id,
+           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
+
+       return rval;
+
+done_free_sp:
+       lio->free(sp);
+done:
+       return rval;
+}
+
+static void
+qla2x00_async_tm_cmd_ctx_done(srb_t *sp)
+{
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
+
+       qla2x00_async_tm_cmd_done(sp->fcport->vha, sp->fcport, iocb);
+       iocb->free(sp);
+}
+
+int
+qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+       uint32_t tag)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       srb_t *sp;
+       struct srb_ctx *ctx;
+       struct srb_iocb *tcf;
+       int rval;
+
+       rval = QLA_FUNCTION_FAILED;
+       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
+           ELS_TMO_2_RATOV(ha) + 2);
+       if (!sp)
+               goto done;
+
+       ctx = sp->ctx;
+       ctx->type = SRB_TM_CMD;
+       ctx->name = "tmf";
+       tcf = ctx->u.iocb_cmd;
+       tcf->u.tmf.flags = flags;
+       tcf->u.tmf.lun = lun;
+       tcf->u.tmf.data = tag;
+       tcf->timeout = qla2x00_async_iocb_timeout;
+       tcf->done = qla2x00_async_tm_cmd_ctx_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       DEBUG2(printk(KERN_DEBUG
+           "scsi(%ld:%x): Async-tmf - loop-id=%x portid=%02x%02x%02x.\n",
+           fcport->vha->host_no, sp->handle, fcport->loop_id,
+           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
+
+       return rval;
+
+done_free_sp:
+       tcf->free(sp);
+done:
+       return rval;
+}
+
+static void
+qla2x00_async_marker_ctx_done(srb_t *sp)
+{
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
+
+       qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb);
+       iocb->free(sp);
+}
+
+int
+qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       srb_t *sp;
+       struct srb_ctx *ctx;
+       struct srb_iocb *mrk;
+       int rval;
+
+       rval = QLA_FUNCTION_FAILED;
+       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0);
+       if (!sp)
+               goto done;
+
+       ctx = sp->ctx;
+       ctx->type = SRB_MARKER_CMD;
+       ctx->name = "marker";
+       mrk = ctx->u.iocb_cmd;
+       mrk->u.marker.lun = lun;
+       mrk->u.marker.modif = modif;
+       mrk->timeout = qla2x00_async_iocb_timeout;
+       mrk->done = qla2x00_async_marker_ctx_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       DEBUG2(printk(KERN_DEBUG
+           "scsi(%ld:%x): Async-marker - loop-id=%x "
+           "portid=%02x%02x%02x.\n",
+           fcport->vha->host_no, sp->handle, fcport->loop_id,
+           fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa));
+
+       return rval;
+
+done_free_sp:
+       mrk->free(sp);
+done:
+       return rval;
+}
+
+void
 qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
        int rval;
-       uint8_t opts = 0;
 
        switch (data[0]) {
        case MBS_COMMAND_COMPLETE:
-               if (fcport->flags & FCF_FCP2_DEVICE)
-                       opts |= BIT_1;
-               rval = qla2x00_get_port_database(vha, fcport, opts);
-               if (rval != QLA_SUCCESS)
-                       qla2x00_mark_device_lost(vha, fcport, 1, 0);
-               else
-                       qla2x00_update_fcport(vha, fcport);
+               if (fcport->flags & FCF_FCP2_DEVICE) {
+                       fcport->flags |= FCF_ASYNC_SENT;
+                       qla2x00_post_async_adisc_work(vha, fcport, data);
+                       break;
+               }
+               qla2x00_update_fcport(vha, fcport);
                break;
        case MBS_COMMAND_ERROR:
+               fcport->flags &= ~FCF_ASYNC_SENT;
                if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
                        set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
                else
@@ -228,21 +428,84 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
                fcport->loop_id++;
                rval = qla2x00_find_new_loop_id(vha, fcport);
                if (rval != QLA_SUCCESS) {
+                       fcport->flags &= ~FCF_ASYNC_SENT;
                        qla2x00_mark_device_lost(vha, fcport, 1, 0);
                        break;
                }
                qla2x00_post_async_login_work(vha, fcport, NULL);
                break;
        }
-       return QLA_SUCCESS;
+       return;
 }
 
-int
+void
 qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
        qla2x00_mark_device_lost(vha, fcport, 1, 0);
-       return QLA_SUCCESS;
+       return;
+}
+
+void
+qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+    uint16_t *data)
+{
+       if (data[0] == MBS_COMMAND_COMPLETE) {
+               qla2x00_update_fcport(vha, fcport);
+
+               return;
+       }
+
+       /* Retry login. */
+       fcport->flags &= ~FCF_ASYNC_SENT;
+       if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
+               set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+       else
+               qla2x00_mark_device_lost(vha, fcport, 1, 0);
+
+       return;
+}
+
+void
+qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+    struct srb_iocb *iocb)
+{
+       int rval;
+       uint32_t flags;
+       uint16_t lun;
+
+       flags = iocb->u.tmf.flags;
+       lun = (uint16_t)iocb->u.tmf.lun;
+
+       /* Issue Marker IOCB */
+       rval = qla2x00_async_marker(fcport, lun,
+               flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
+
+       if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
+               DEBUG2_3_11(printk(KERN_WARNING
+                       "%s(%ld): TM IOCB failed (%x).\n",
+                       __func__, vha->host_no, rval));
+       }
+
+       return;
+}
+
+void
+qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+    struct srb_iocb *iocb)
+{
+       /*
+        * Currently we dont have any specific post response processing
+        * for this IOCB. We'll just return success or failed
+        * depending on whether the IOCB command succeeded or failed.
+        */
+       if (iocb->u.tmf.data) {
+               DEBUG2_3_11(printk(KERN_WARNING
+                   "%s(%ld): Marker IOCB failed (%x).\n",
+                   __func__, vha->host_no, iocb->u.tmf.data));
+       }
+
+       return;
 }
 
 /****************************************************************************/
@@ -328,6 +591,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
                if (rval)
                        return (rval);
        }
+
        if (IS_QLA84XX(ha)) {
                ha->cs84xx = qla84xx_get_chip(vha);
                if (!ha->cs84xx) {
@@ -340,7 +604,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
        ha->flags.chip_reset_done = 1;
 
        if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
-       /* Issue verify 84xx FW IOCB to complete 84xx initialization */
+               /* Issue verify 84xx FW IOCB to complete 84xx initialization */
                rval = qla84xx_init_chip(vha);
                if (rval != QLA_SUCCESS) {
                        qla_printk(KERN_ERR, ha,
@@ -349,6 +613,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
                }
        }
 
+       if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) {
+               if (qla24xx_read_fcp_prio_cfg(vha))
+                       qla_printk(KERN_ERR, ha,
+                       "Unable to read FCP priority data.\n");
+       }
+
        return (rval);
 }
 
@@ -955,6 +1225,9 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
 
+       if (IS_QLA82XX(ha))
+               return QLA_SUCCESS;
+
        ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
 
        rval = qla2x00_mbx_reg_test(vha);
@@ -1177,6 +1450,12 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
        unsigned long flags;
        uint16_t fw_major_version;
 
+       if (IS_QLA82XX(ha)) {
+               rval = ha->isp_ops->load_risc(vha, &srisc_address);
+               if (rval == QLA_SUCCESS)
+                       goto enable_82xx_npiv;
+       }
+
        if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
                /* Disable SRAM, Instruction RAM and GP RAM parity.  */
                spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1202,6 +1481,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
                        rval = qla2x00_execute_fw(vha, srisc_address);
                        /* Retrieve firmware information. */
                        if (rval == QLA_SUCCESS) {
+enable_82xx_npiv:
                                fw_major_version = ha->fw_major_version;
                                rval = qla2x00_get_fw_version(vha,
                                    &ha->fw_major_version,
@@ -1226,8 +1506,10 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
                                    &ha->fw_xcb_count, NULL, NULL,
                                    &ha->max_npiv_vports, NULL);
 
-                               if (!fw_major_version && ql2xallocfwdump)
-                                       qla2x00_alloc_fw_dump(vha);
+                               if (!fw_major_version && ql2xallocfwdump) {
+                                       if (!IS_QLA82XX(ha))
+                                               qla2x00_alloc_fw_dump(vha);
+                               }
                        }
                } else {
                        DEBUG2(printk(KERN_INFO
@@ -1384,6 +1666,9 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
        int rval;
        struct qla_hw_data *ha = vha->hw;
 
+       if (IS_QLA82XX(ha))
+               return;
+
        /* Update Serial Link options. */
        if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
                return;
@@ -1818,7 +2103,7 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
        return(rval);
 }
 
-static inline void
+inline void
 qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
        char *def)
 {
@@ -1826,7 +2111,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
        uint16_t index;
        struct qla_hw_data *ha = vha->hw;
        int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
-           !IS_QLA81XX(ha);
+           !IS_QLA8XXX_TYPE(ha);
 
        if (memcmp(model, BINZERO, len) != 0) {
                strncpy(ha->model_number, model, len);
@@ -2017,6 +2302,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
        if (IS_QLA23XX(ha)) {
                nv->firmware_options[0] |= BIT_2;
                nv->firmware_options[0] &= ~BIT_3;
+               nv->firmware_options[0] &= ~BIT_6;
                nv->add_firmware_options[1] |= BIT_5 | BIT_4;
 
                if (IS_QLA2300(ha)) {
@@ -2635,7 +2921,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
            PORT_RETRY_TIME;
        atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
            PORT_RETRY_TIME);
-       fcport->flags &= ~FCF_LOGIN_NEEDED;
+       fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
 
        qla2x00_iidma_fcport(vha, fcport);
 
@@ -2864,7 +3150,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
        sw_info_t       *swl;
        int             swl_idx;
        int             first_dev, last_dev;
-       port_id_t       wrap, nxt_d_id;
+       port_id_t       wrap = {}, nxt_d_id;
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
        struct scsi_qla_host *tvp;
@@ -3167,7 +3453,7 @@ qla2x00_device_resync(scsi_qla_host_t *vha)
        uint32_t rscn_entry;
        uint8_t rscn_out_iter;
        uint8_t format;
-       port_id_t d_id;
+       port_id_t d_id = {};
 
        rval = QLA_RSCNS_HANDLED;
 
@@ -3281,11 +3567,15 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
        retry = 0;
 
        if (IS_ALOGIO_CAPABLE(ha)) {
+               if (fcport->flags & FCF_ASYNC_SENT)
+                       return rval;
+               fcport->flags |= FCF_ASYNC_SENT;
                rval = qla2x00_post_async_login_work(vha, fcport, NULL);
                if (!rval)
                        return rval;
        }
 
+       fcport->flags &= ~FCF_ASYNC_SENT;
        rval = qla2x00_fabric_login(vha, fcport, next_loopid);
        if (rval == QLA_SUCCESS) {
                /* Send an ADISC to FCP2 devices.*/
@@ -3546,6 +3836,45 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
                                qla2x00_rport_del(fcport);
 }
 
+void
+qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
+       struct scsi_qla_host *tvp;
+
+       vha->flags.online = 0;
+       ha->flags.chip_reset_done = 0;
+       clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+       ha->qla_stats.total_isp_aborts++;
+
+       qla_printk(KERN_INFO, ha,
+           "Performing ISP error recovery - ha= %p.\n", ha);
+
+       /* Chip reset does not apply to 82XX */
+       if (!IS_QLA82XX(ha))
+               ha->isp_ops->reset_chip(vha);
+
+       atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+       if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+               atomic_set(&vha->loop_state, LOOP_DOWN);
+               qla2x00_mark_all_devices_lost(vha, 0);
+               list_for_each_entry_safe(vp, tvp, &base_vha->hw->vp_list, list)
+                       qla2x00_mark_all_devices_lost(vp, 0);
+       } else {
+               if (!atomic_read(&vha->loop_down_timer))
+                       atomic_set(&vha->loop_down_timer,
+                           LOOP_DOWN_TIME);
+       }
+
+       /* Make sure for ISP 82XX IO DMA is complete */
+       if (IS_QLA82XX(ha))
+               qla82xx_wait_for_pending_commands(vha);
+
+       /* Requeue all commands in outstanding command list. */
+       qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+}
+
 /*
 *  qla2x00_abort_isp
 *      Resets ISP and aborts all outstanding commands.
@@ -3567,27 +3896,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
        struct req_que *req = ha->req_q_map[0];
 
        if (vha->flags.online) {
-               vha->flags.online = 0;
-               ha->flags.chip_reset_done = 0;
-               clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
-               ha->qla_stats.total_isp_aborts++;
-
-               qla_printk(KERN_INFO, ha,
-                   "Performing ISP error recovery - ha= %p.\n", ha);
-               ha->isp_ops->reset_chip(vha);
-
-               atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
-               if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
-                       atomic_set(&vha->loop_state, LOOP_DOWN);
-                       qla2x00_mark_all_devices_lost(vha, 0);
-               } else {
-                       if (!atomic_read(&vha->loop_down_timer))
-                               atomic_set(&vha->loop_down_timer,
-                                   LOOP_DOWN_TIME);
-               }
-
-               /* Requeue all commands in outstanding command list. */
-               qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+               qla2x00_abort_isp_cleanup(vha);
 
                if (unlikely(pci_channel_offline(ha->pdev) &&
                    ha->flags.pci_channel_io_perm_failure)) {
@@ -3843,6 +4152,9 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
+       if (IS_QLA82XX(ha))
+               return;
+
        vha->flags.online = 0;
        ha->isp_ops->disable_intrs(ha);
 
@@ -3906,6 +4218,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        }
        ha->nvram_size = sizeof(struct nvram_24xx);
        ha->vpd_size = FA_NVRAM_VPD_SIZE;
+       if (IS_QLA82XX(ha))
+               ha->vpd_size = FA_VPD_SIZE_82XX;
 
        /* Get VPD data into cache */
        ha->vpd = ha->nvram + VPD_OFFSET;
@@ -4769,7 +5083,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
         * Setup driver NVRAM options.
         */
        qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
-           "QLE81XX");
+           "QLE8XXX");
 
        /* Use alternate WWN? */
        if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
@@ -4892,6 +5206,114 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        return (rval);
 }
 
+int
+qla82xx_restart_isp(scsi_qla_host_t *vha)
+{
+       int status, rval;
+       uint32_t wait_time;
+       struct qla_hw_data *ha = vha->hw;
+       struct req_que *req = ha->req_q_map[0];
+       struct rsp_que *rsp = ha->rsp_q_map[0];
+       struct scsi_qla_host *vp;
+       struct scsi_qla_host *tvp;
+
+       status = qla2x00_init_rings(vha);
+       if (!status) {
+               clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
+               ha->flags.chip_reset_done = 1;
+
+               status = qla2x00_fw_ready(vha);
+               if (!status) {
+                       qla_printk(KERN_INFO, ha,
+                       "%s(): Start configure loop, "
+                       "status = %d\n", __func__, status);
+
+                       /* Issue a marker after FW becomes ready. */
+                       qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
+
+                       vha->flags.online = 1;
+                       /* Wait at most MAX_TARGET RSCNs for a stable link. */
+                       wait_time = 256;
+                       do {
+                               clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+                               qla2x00_configure_loop(vha);
+                               wait_time--;
+                       } while (!atomic_read(&vha->loop_down_timer) &&
+                           !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) &&
+                           wait_time &&
+                           (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)));
+               }
+
+               /* if no cable then assume it's good */
+               if ((vha->device_flags & DFLG_NO_CABLE))
+                       status = 0;
+
+               qla_printk(KERN_INFO, ha,
+                       "%s(): Configure loop done, status = 0x%x\n",
+                       __func__, status);
+       }
+
+       if (!status) {
+               clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
+
+               if (!atomic_read(&vha->loop_down_timer)) {
+                       /*
+                        * Issue marker command only when we are going
+                        * to start the I/O .
+                        */
+                       vha->marker_needed = 1;
+               }
+
+               vha->flags.online = 1;
+
+               ha->isp_ops->enable_intrs(ha);
+
+               ha->isp_abort_cnt = 0;
+               clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
+
+               if (ha->fce) {
+                       ha->flags.fce_enabled = 1;
+                       memset(ha->fce, 0,
+                           fce_calc_size(ha->fce_bufs));
+                       rval = qla2x00_enable_fce_trace(vha,
+                           ha->fce_dma, ha->fce_bufs, ha->fce_mb,
+                           &ha->fce_bufs);
+                       if (rval) {
+                               qla_printk(KERN_WARNING, ha,
+                                   "Unable to reinitialize FCE "
+                                   "(%d).\n", rval);
+                               ha->flags.fce_enabled = 0;
+                       }
+               }
+
+               if (ha->eft) {
+                       memset(ha->eft, 0, EFT_SIZE);
+                       rval = qla2x00_enable_eft_trace(vha,
+                           ha->eft_dma, EFT_NUM_BUFFERS);
+                       if (rval) {
+                               qla_printk(KERN_WARNING, ha,
+                                   "Unable to reinitialize EFT "
+                                   "(%d).\n", rval);
+                       }
+               }
+       }
+
+       if (!status) {
+               DEBUG(printk(KERN_INFO
+                       "qla82xx_restart_isp(%ld): succeeded.\n",
+                       vha->host_no));
+               list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
+                       if (vp->vp_idx)
+                               qla2x00_vp_abort_isp(vp);
+               }
+       } else {
+               qla_printk(KERN_INFO, ha,
+                       "qla82xx_restart_isp: **** FAILED ****\n");
+       }
+
+       return status;
+}
+
 void
 qla81xx_update_fw_options(scsi_qla_host_t *vha)
 {
@@ -4905,3 +5327,165 @@ qla81xx_update_fw_options(scsi_qla_host_t *vha)
        ha->fw_options[2] |= BIT_9;
        qla2x00_set_fw_options(vha, ha->fw_options);
 }
+
+/*
+ * qla24xx_get_fcp_prio
+ *     Gets the fcp cmd priority value for the logged in port.
+ *     Looks for a match of the port descriptors within
+ *     each of the fcp prio config entries. If a match is found,
+ *     the tag (priority) value is returned.
+ *
+ * Input:
+ *     ha = adapter block po
+ *     fcport = port structure pointer.
+ *
+ * Return:
+ *     non-zero (if found)
+ *     0 (if not found)
+ *
+ * Context:
+ *     Kernel context
+ */
+uint8_t
+qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
+{
+       int i, entries;
+       uint8_t pid_match, wwn_match;
+       uint8_t priority;
+       uint32_t pid1, pid2;
+       uint64_t wwn1, wwn2;
+       struct qla_fcp_prio_entry *pri_entry;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled)
+               return 0;
+
+       priority = 0;
+       entries = ha->fcp_prio_cfg->num_entries;
+       pri_entry = &ha->fcp_prio_cfg->entry[0];
+
+       for (i = 0; i < entries; i++) {
+               pid_match = wwn_match = 0;
+
+               if (!(pri_entry->flags & FCP_PRIO_ENTRY_VALID)) {
+                       pri_entry++;
+                       continue;
+               }
+
+               /* check source pid for a match */
+               if (pri_entry->flags & FCP_PRIO_ENTRY_SPID_VALID) {
+                       pid1 = pri_entry->src_pid & INVALID_PORT_ID;
+                       pid2 = vha->d_id.b24 & INVALID_PORT_ID;
+                       if (pid1 == INVALID_PORT_ID)
+                               pid_match++;
+                       else if (pid1 == pid2)
+                               pid_match++;
+               }
+
+               /* check destination pid for a match */
+               if (pri_entry->flags & FCP_PRIO_ENTRY_DPID_VALID) {
+                       pid1 = pri_entry->dst_pid & INVALID_PORT_ID;
+                       pid2 = fcport->d_id.b24 & INVALID_PORT_ID;
+                       if (pid1 == INVALID_PORT_ID)
+                               pid_match++;
+                       else if (pid1 == pid2)
+                               pid_match++;
+               }
+
+               /* check source WWN for a match */
+               if (pri_entry->flags & FCP_PRIO_ENTRY_SWWN_VALID) {
+                       wwn1 = wwn_to_u64(vha->port_name);
+                       wwn2 = wwn_to_u64(pri_entry->src_wwpn);
+                       if (wwn2 == (uint64_t)-1)
+                               wwn_match++;
+                       else if (wwn1 == wwn2)
+                               wwn_match++;
+               }
+
+               /* check destination WWN for a match */
+               if (pri_entry->flags & FCP_PRIO_ENTRY_DWWN_VALID) {
+                       wwn1 = wwn_to_u64(fcport->port_name);
+                       wwn2 = wwn_to_u64(pri_entry->dst_wwpn);
+                       if (wwn2 == (uint64_t)-1)
+                               wwn_match++;
+                       else if (wwn1 == wwn2)
+                               wwn_match++;
+               }
+
+               if (pid_match == 2 || wwn_match == 2) {
+                       /* Found a matching entry */
+                       if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
+                               priority = pri_entry->tag;
+                       break;
+               }
+
+               pri_entry++;
+       }
+
+       return priority;
+}
+
+/*
+ * qla24xx_update_fcport_fcp_prio
+ *     Activates fcp priority for the logged in fc port
+ *
+ * Input:
+ *     ha = adapter block pointer.
+ *     fcp = port structure pointer.
+ *
+ * Return:
+ *     QLA_SUCCESS or QLA_FUNCTION_FAILED
+ *
+ * Context:
+ *     Kernel context.
+ */
+int
+qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+       int ret;
+       uint8_t priority;
+       uint16_t mb[5];
+
+       if (atomic_read(&fcport->state) == FCS_UNCONFIGURED ||
+               fcport->port_type != FCT_TARGET ||
+               fcport->loop_id == FC_NO_LOOP_ID)
+               return QLA_FUNCTION_FAILED;
+
+       priority = qla24xx_get_fcp_prio(ha, fcport);
+       ret = qla24xx_set_fcp_prio(ha, fcport->loop_id, priority, mb);
+       if (ret == QLA_SUCCESS)
+               fcport->fcp_prio = priority;
+       else
+               DEBUG2(printk(KERN_WARNING
+                       "scsi(%ld): Unable to activate fcp priority, "
+                       " ret=0x%x\n", ha->host_no, ret));
+
+       return  ret;
+}
+
+/*
+ * qla24xx_update_all_fcp_prio
+ *     Activates fcp priority for all the logged in ports
+ *
+ * Input:
+ *     ha = adapter block pointer.
+ *
+ * Return:
+ *     QLA_SUCCESS or QLA_FUNCTION_FAILED
+ *
+ * Context:
+ *     Kernel context.
+ */
+int
+qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha)
+{
+       int ret;
+       fc_port_t *fcport;
+
+       ret = QLA_FUNCTION_FAILED;
+       /* We need to set priority for all logged in ports */
+       list_for_each_entry(fcport, &vha->vp_fcports, list)
+               ret = qla24xx_update_fcport_fcp_prio(vha, fcport);
+
+       return ret;
+}
index 5e0a709..84c2fea 100644 (file)
@@ -37,7 +37,10 @@ qla2x00_poll(struct rsp_que *rsp)
        unsigned long flags;
        struct qla_hw_data *ha = rsp->hw;
        local_irq_save(flags);
-       ha->isp_ops->intr_handler(0, rsp);
+       if (IS_QLA82XX(ha))
+               qla82xx_poll(0, rsp);
+       else
+               ha->isp_ops->intr_handler(0, rsp);
        local_irq_restore(flags);
 }
 
@@ -64,3 +67,19 @@ qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id)
        return ((loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
            loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST);
 }
+
+static inline void
+qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp)
+{
+       struct dsd_dma *dsd_ptr, *tdsd_ptr;
+
+       /* clean up allocated prev pool */
+       list_for_each_entry_safe(dsd_ptr, tdsd_ptr,
+           &((struct crc_context *)sp->ctx)->dsd_list, list) {
+               dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr,
+                   dsd_ptr->dsd_list_dma);
+               list_del(&dsd_ptr->list);
+               kfree(dsd_ptr);
+       }
+       INIT_LIST_HEAD(&((struct crc_context *)sp->ctx)->dsd_list);
+}
index 8299a98..8ef9453 100644 (file)
@@ -145,7 +145,49 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha)
        return (cont_pkt);
 }
 
-/**
+static inline int
+qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts)
+{
+       uint8_t guard = scsi_host_get_guard(sp->cmd->device->host);
+
+       /* We only support T10 DIF right now */
+       if (guard != SHOST_DIX_GUARD_CRC) {
+               DEBUG2(printk(KERN_ERR "Unsupported guard: %d\n", guard));
+               return 0;
+       }
+
+       /* We always use DIFF Bundling for best performance */
+       *fw_prot_opts = 0;
+
+       /* Translate SCSI opcode to a protection opcode */
+       switch (scsi_get_prot_op(sp->cmd)) {
+       case SCSI_PROT_READ_STRIP:
+               *fw_prot_opts |= PO_MODE_DIF_REMOVE;
+               break;
+       case SCSI_PROT_WRITE_INSERT:
+               *fw_prot_opts |= PO_MODE_DIF_INSERT;
+               break;
+       case SCSI_PROT_READ_INSERT:
+               *fw_prot_opts |= PO_MODE_DIF_INSERT;
+               break;
+       case SCSI_PROT_WRITE_STRIP:
+               *fw_prot_opts |= PO_MODE_DIF_REMOVE;
+               break;
+       case SCSI_PROT_READ_PASS:
+               *fw_prot_opts |= PO_MODE_DIF_PASS;
+               break;
+       case SCSI_PROT_WRITE_PASS:
+               *fw_prot_opts |= PO_MODE_DIF_PASS;
+               break;
+       default:        /* Normal Request */
+               *fw_prot_opts |= PO_MODE_DIF_PASS;
+               break;
+       }
+
+       return scsi_prot_sg_count(sp->cmd);
+}
+
+/*
  * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit
  * capable IOCB types.
  *
@@ -506,7 +548,10 @@ qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req,
                                cnt = (uint16_t)
                                        RD_REG_DWORD(&reg->isp25mq.req_q_out);
                        else {
-                               if (IS_FWI2_CAPABLE(ha))
+                               if (IS_QLA82XX(ha))
+                                       cnt = (uint16_t)RD_REG_DWORD(
+                                           &reg->isp82.req_q_out);
+                               else if (IS_FWI2_CAPABLE(ha))
                                        cnt = (uint16_t)RD_REG_DWORD(
                                                &reg->isp24.req_q_out);
                                else
@@ -579,11 +624,29 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)
                req->ring_ptr++;
 
        /* Set chip new ring index. */
-       if (ha->mqenable) {
+       if (IS_QLA82XX(ha)) {
+               uint32_t dbval = 0x04 | (ha->portnum << 5);
+
+               /* write, read and verify logic */
+               dbval = dbval | (req->id << 8) | (req->ring_index << 16);
+               if (ql2xdbwr)
+                       qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
+               else {
+                       WRT_REG_DWORD(
+                               (unsigned long __iomem *)ha->nxdb_wr_ptr,
+                               dbval);
+                       wmb();
+                       while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
+                               WRT_REG_DWORD((unsigned long __iomem *)
+                                       ha->nxdb_wr_ptr, dbval);
+                               wmb();
+                       }
+               }
+       } else if (ha->mqenable) {
+               /* Set chip new ring index. */
                WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
                RD_REG_DWORD(&ioreg->hccr);
-       }
-       else {
+       } else {
                if (IS_FWI2_CAPABLE(ha)) {
                        WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
                        RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
@@ -604,7 +667,7 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)
  *
  * Returns the number of IOCB entries needed to store @dsds.
  */
-static inline uint16_t
+inline uint16_t
 qla24xx_calc_iocbs(uint16_t dsds)
 {
        uint16_t iocbs;
@@ -615,6 +678,8 @@ qla24xx_calc_iocbs(uint16_t dsds)
                if ((dsds - 1) % 5)
                        iocbs++;
        }
+       DEBUG3(printk(KERN_DEBUG "%s(): Required PKT(s) = %d\n",
+           __func__, iocbs));
        return iocbs;
 }
 
@@ -626,7 +691,7 @@ qla24xx_calc_iocbs(uint16_t dsds)
  * @cmd_pkt: Command type 3 IOCB
  * @tot_dsds: Total number of segments to transfer
  */
-static inline void
+inline void
 qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
     uint16_t tot_dsds)
 {
@@ -695,6 +760,453 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
        }
 }
 
+struct fw_dif_context {
+       uint32_t ref_tag;
+       uint16_t app_tag;
+       uint8_t ref_tag_mask[4];        /* Validation/Replacement Mask*/
+       uint8_t app_tag_mask[2];        /* Validation/Replacement Mask*/
+};
+
+/*
+ * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command
+ *
+ */
+static inline void
+qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
+    unsigned int protcnt)
+{
+       struct sd_dif_tuple *spt;
+       unsigned char op = scsi_get_prot_op(cmd);
+
+       switch (scsi_get_prot_type(cmd)) {
+       /* For TYPE 0 protection: no checking */
+       case SCSI_PROT_DIF_TYPE0:
+               pkt->ref_tag_mask[0] = 0x00;
+               pkt->ref_tag_mask[1] = 0x00;
+               pkt->ref_tag_mask[2] = 0x00;
+               pkt->ref_tag_mask[3] = 0x00;
+               break;
+
+       /*
+        * For TYPE 2 protection: 16 bit GUARD + 32 bit REF tag has to
+        * match LBA in CDB + N
+        */
+       case SCSI_PROT_DIF_TYPE2:
+               break;
+
+       /* For Type 3 protection: 16 bit GUARD only */
+       case SCSI_PROT_DIF_TYPE3:
+               pkt->ref_tag_mask[0] = pkt->ref_tag_mask[1] =
+                       pkt->ref_tag_mask[2] = pkt->ref_tag_mask[3] =
+                                                               0x00;
+               break;
+
+       /*
+        * For TYpe 1 protection: 16 bit GUARD tag, 32 bit REF tag, and
+        * 16 bit app tag.
+        */
+       case SCSI_PROT_DIF_TYPE1:
+               if (!ql2xenablehba_err_chk)
+                       break;
+
+               if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
+                   op == SCSI_PROT_WRITE_PASS)) {
+                       spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
+                           scsi_prot_sglist(cmd)[0].offset;
+                       DEBUG18(printk(KERN_DEBUG
+                           "%s(): LBA from user %p, lba = 0x%x\n",
+                           __func__, spt, (int)spt->ref_tag));
+                       pkt->ref_tag = swab32(spt->ref_tag);
+                       pkt->app_tag_mask[0] = 0x0;
+                       pkt->app_tag_mask[1] = 0x0;
+               } else {
+                       pkt->ref_tag = cpu_to_le32((uint32_t)
+                           (0xffffffff & scsi_get_lba(cmd)));
+                       pkt->app_tag = __constant_cpu_to_le16(0);
+                       pkt->app_tag_mask[0] = 0x0;
+                       pkt->app_tag_mask[1] = 0x0;
+               }
+               /* enable ALL bytes of the ref tag */
+               pkt->ref_tag_mask[0] = 0xff;
+               pkt->ref_tag_mask[1] = 0xff;
+               pkt->ref_tag_mask[2] = 0xff;
+               pkt->ref_tag_mask[3] = 0xff;
+               break;
+       }
+
+       DEBUG18(printk(KERN_DEBUG
+           "%s(): Setting protection Tags: (BIG) ref tag = 0x%x,"
+           " app tag = 0x%x, prot SG count %d , cmd lba 0x%x,"
+           " prot_type=%u\n", __func__, pkt->ref_tag, pkt->app_tag, protcnt,
+           (int)scsi_get_lba(cmd), scsi_get_prot_type(cmd)));
+}
+
+
+static int
+qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
+       uint16_t tot_dsds)
+{
+       void *next_dsd;
+       uint8_t avail_dsds = 0;
+       uint32_t dsd_list_len;
+       struct dsd_dma *dsd_ptr;
+       struct scatterlist *sg;
+       uint32_t *cur_dsd = dsd;
+       int     i;
+       uint16_t        used_dsds = tot_dsds;
+
+       uint8_t         *cp;
+
+       scsi_for_each_sg(sp->cmd, sg, tot_dsds, i) {
+               dma_addr_t      sle_dma;
+
+               /* Allocate additional continuation packets? */
+               if (avail_dsds == 0) {
+                       avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
+                                       QLA_DSDS_PER_IOCB : used_dsds;
+                       dsd_list_len = (avail_dsds + 1) * 12;
+                       used_dsds -= avail_dsds;
+
+                       /* allocate tracking DS */
+                       dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
+                       if (!dsd_ptr)
+                               return 1;
+
+                       /* allocate new list */
+                       dsd_ptr->dsd_addr = next_dsd =
+                           dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
+                               &dsd_ptr->dsd_list_dma);
+
+                       if (!next_dsd) {
+                               /*
+                                * Need to cleanup only this dsd_ptr, rest
+                                * will be done by sp_free_dma()
+                                */
+                               kfree(dsd_ptr);
+                               return 1;
+                       }
+
+                       list_add_tail(&dsd_ptr->list,
+                           &((struct crc_context *)sp->ctx)->dsd_list);
+
+                       sp->flags |= SRB_CRC_CTX_DSD_VALID;
+
+                       /* add new list to cmd iocb or last list */
+                       *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
+                       *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
+                       *cur_dsd++ = dsd_list_len;
+                       cur_dsd = (uint32_t *)next_dsd;
+               }
+               sle_dma = sg_dma_address(sg);
+               DEBUG18(printk("%s(): %p, sg entry %d - addr =0x%x 0x%x,"
+                   " len =%d\n", __func__ , cur_dsd, i, LSD(sle_dma),
+                   MSD(sle_dma), sg_dma_len(sg)));
+               *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+               *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+               *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+               avail_dsds--;
+
+               if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
+                       cp = page_address(sg_page(sg)) + sg->offset;
+                       DEBUG18(printk("%s(): User Data buffer= %p:\n",
+                           __func__ , cp));
+               }
+       }
+       /* Null termination */
+       *cur_dsd++ = 0;
+       *cur_dsd++ = 0;
+       *cur_dsd++ = 0;
+       return 0;
+}
+
+static int
+qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
+                                                       uint32_t *dsd,
+       uint16_t tot_dsds)
+{
+       void *next_dsd;
+       uint8_t avail_dsds = 0;
+       uint32_t dsd_list_len;
+       struct dsd_dma *dsd_ptr;
+       struct scatterlist *sg;
+       int     i;
+       struct scsi_cmnd *cmd;
+       uint32_t *cur_dsd = dsd;
+       uint16_t        used_dsds = tot_dsds;
+
+       uint8_t         *cp;
+
+
+       cmd = sp->cmd;
+       scsi_for_each_prot_sg(cmd, sg, tot_dsds, i) {
+               dma_addr_t      sle_dma;
+
+               /* Allocate additional continuation packets? */
+               if (avail_dsds == 0) {
+                       avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ?
+                                               QLA_DSDS_PER_IOCB : used_dsds;
+                       dsd_list_len = (avail_dsds + 1) * 12;
+                       used_dsds -= avail_dsds;
+
+                       /* allocate tracking DS */
+                       dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
+                       if (!dsd_ptr)
+                               return 1;
+
+                       /* allocate new list */
+                       dsd_ptr->dsd_addr = next_dsd =
+                           dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC,
+                               &dsd_ptr->dsd_list_dma);
+
+                       if (!next_dsd) {
+                               /*
+                                * Need to cleanup only this dsd_ptr, rest
+                                * will be done by sp_free_dma()
+                                */
+                               kfree(dsd_ptr);
+                               return 1;
+                       }
+
+                       list_add_tail(&dsd_ptr->list,
+                           &((struct crc_context *)sp->ctx)->dsd_list);
+
+                       sp->flags |= SRB_CRC_CTX_DSD_VALID;
+
+                       /* add new list to cmd iocb or last list */
+                       *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
+                       *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
+                       *cur_dsd++ = dsd_list_len;
+                       cur_dsd = (uint32_t *)next_dsd;
+               }
+               sle_dma = sg_dma_address(sg);
+               if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
+                       DEBUG18(printk(KERN_DEBUG
+                           "%s(): %p, sg entry %d - addr =0x%x"
+                           "0x%x, len =%d\n", __func__ , cur_dsd, i,
+                           LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg)));
+               }
+               *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+               *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+               *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+
+               if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
+                       cp = page_address(sg_page(sg)) + sg->offset;
+                       DEBUG18(printk("%s(): Protection Data buffer = %p:\n",
+                           __func__ , cp));
+               }
+               avail_dsds--;
+       }
+       /* Null termination */
+       *cur_dsd++ = 0;
+       *cur_dsd++ = 0;
+       *cur_dsd++ = 0;
+       return 0;
+}
+
+/**
+ * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command
+ *                                                     Type 6 IOCB types.
+ *
+ * @sp: SRB command to process
+ * @cmd_pkt: Command type 3 IOCB
+ * @tot_dsds: Total number of segments to transfer
+ */
+static inline int
+qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
+    uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts)
+{
+       uint32_t                *cur_dsd, *fcp_dl;
+       scsi_qla_host_t         *vha;
+       struct scsi_cmnd        *cmd;
+       struct scatterlist      *cur_seg;
+       int                     sgc;
+       uint32_t                total_bytes;
+       uint32_t                data_bytes;
+       uint32_t                dif_bytes;
+       uint8_t                 bundling = 1;
+       uint16_t                blk_size;
+       uint8_t                 *clr_ptr;
+       struct crc_context      *crc_ctx_pkt = NULL;
+       struct qla_hw_data      *ha;
+       uint8_t                 additional_fcpcdb_len;
+       uint16_t                fcp_cmnd_len;
+       struct fcp_cmnd         *fcp_cmnd;
+       dma_addr_t              crc_ctx_dma;
+
+       cmd = sp->cmd;
+
+       sgc = 0;
+       /* Update entry type to indicate Command Type CRC_2 IOCB */
+       *((uint32_t *)(&cmd_pkt->entry_type)) =
+           __constant_cpu_to_le32(COMMAND_TYPE_CRC_2);
+
+       /* No data transfer */
+       data_bytes = scsi_bufflen(cmd);
+       if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
+               DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n",
+                   __func__, data_bytes));
+               cmd_pkt->byte_count = __constant_cpu_to_le32(0);
+               return QLA_SUCCESS;
+       }
+
+       vha = sp->fcport->vha;
+       ha = vha->hw;
+
+       DEBUG18(printk(KERN_DEBUG
+           "%s(%ld): Executing cmd sp %p, pid=%ld, prot_op=%u.\n", __func__,
+           vha->host_no, sp, cmd->serial_number, scsi_get_prot_op(sp->cmd)));
+
+       cmd_pkt->vp_index = sp->fcport->vp_idx;
+
+       /* Set transfer direction */
+       if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+               cmd_pkt->control_flags =
+                   __constant_cpu_to_le16(CF_WRITE_DATA);
+       } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+               cmd_pkt->control_flags =
+                   __constant_cpu_to_le16(CF_READ_DATA);
+       }
+
+       tot_prot_dsds = scsi_prot_sg_count(cmd);
+       if (!tot_prot_dsds)
+               bundling = 0;
+
+       /* Allocate CRC context from global pool */
+       crc_ctx_pkt = sp->ctx = dma_pool_alloc(ha->dl_dma_pool,
+           GFP_ATOMIC, &crc_ctx_dma);
+
+       if (!crc_ctx_pkt)
+               goto crc_queuing_error;
+
+       /* Zero out CTX area. */
+       clr_ptr = (uint8_t *)crc_ctx_pkt;
+       memset(clr_ptr, 0, sizeof(*crc_ctx_pkt));
+
+       crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma;
+
+       sp->flags |= SRB_CRC_CTX_DMA_VALID;
+
+       /* Set handle */
+       crc_ctx_pkt->handle = cmd_pkt->handle;
+
+       INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list);
+
+       qla24xx_set_t10dif_tags(cmd, (struct fw_dif_context *)
+           &crc_ctx_pkt->ref_tag, tot_prot_dsds);
+
+       cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma));
+       cmd_pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma));
+       cmd_pkt->crc_context_len = CRC_CONTEXT_LEN_FW;
+
+       /* Determine SCSI command length -- align to 4 byte boundary */
+       if (cmd->cmd_len > 16) {
+               DEBUG18(printk(KERN_INFO "%s(): **** SCSI CMD > 16\n",
+                   __func__));
+               additional_fcpcdb_len = cmd->cmd_len - 16;
+               if ((cmd->cmd_len % 4) != 0) {
+                       /* SCSI cmd > 16 bytes must be multiple of 4 */
+                       goto crc_queuing_error;
+               }
+               fcp_cmnd_len = 12 + cmd->cmd_len + 4;
+       } else {
+               additional_fcpcdb_len = 0;
+               fcp_cmnd_len = 12 + 16 + 4;
+       }
+
+       fcp_cmnd = &crc_ctx_pkt->fcp_cmnd;
+
+       fcp_cmnd->additional_cdb_len = additional_fcpcdb_len;
+       if (cmd->sc_data_direction == DMA_TO_DEVICE)
+               fcp_cmnd->additional_cdb_len |= 1;
+       else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+               fcp_cmnd->additional_cdb_len |= 2;
+
+       int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun);
+       memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
+       cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len);
+       cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32(
+           LSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
+       cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32(
+           MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
+       fcp_cmnd->task_attribute = 0;
+       fcp_cmnd->task_managment = 0;
+
+       cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
+
+       DEBUG18(printk(KERN_INFO "%s(%ld): Total SG(s) Entries %d, Data"
+           "entries %d, data bytes %d, Protection entries %d\n",
+           __func__, vha->host_no, tot_dsds, (tot_dsds-tot_prot_dsds),
+           data_bytes, tot_prot_dsds));
+
+       /* Compute dif len and adjust data len to incude protection */
+       total_bytes = data_bytes;
+       dif_bytes = 0;
+       blk_size = cmd->device->sector_size;
+       if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE1) {
+               dif_bytes = (data_bytes / blk_size) * 8;
+               total_bytes += dif_bytes;
+       }
+
+       if (!ql2xenablehba_err_chk)
+               fw_prot_opts |= 0x10; /* Disable Guard tag checking */
+
+       if (!bundling) {
+               cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address;
+       } else {
+               /*
+                * Configure Bundling if we need to fetch interlaving
+                * protection PCI accesses
+                */
+               fw_prot_opts |= PO_ENABLE_DIF_BUNDLING;
+               crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes);
+               crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds -
+                                                       tot_prot_dsds);
+               cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address;
+       }
+
+       /* Finish the common fields of CRC pkt */
+       crc_ctx_pkt->blk_size = cpu_to_le16(blk_size);
+       crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts);
+       crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes);
+       crc_ctx_pkt->guard_seed = __constant_cpu_to_le16(0);
+       /* Fibre channel byte count */
+       cmd_pkt->byte_count = cpu_to_le32(total_bytes);
+       fcp_dl = (uint32_t *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 +
+           additional_fcpcdb_len);
+       *fcp_dl = htonl(total_bytes);
+
+       DEBUG18(printk(KERN_INFO "%s(%ld): dif bytes = 0x%x (%d), total bytes"
+           " = 0x%x (%d), dat block size =0x%x (%d)\n", __func__,
+           vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes,
+           crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size));
+
+       /* Walks data segments */
+
+       cmd_pkt->control_flags |=
+           __constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE);
+       if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd,
+           (tot_dsds - tot_prot_dsds)))
+               goto crc_queuing_error;
+
+       if (bundling && tot_prot_dsds) {
+               /* Walks dif segments */
+               cur_seg = scsi_prot_sglist(cmd);
+               cmd_pkt->control_flags |=
+                       __constant_cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE);
+               cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address;
+               if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd,
+                   tot_prot_dsds))
+                       goto crc_queuing_error;
+       }
+       return QLA_SUCCESS;
+
+crc_queuing_error:
+       DEBUG18(qla_printk(KERN_INFO, ha,
+           "CMD sent FAILED crc_q error:sp = %p\n", sp));
+       /* Cleanup will be performed by the caller */
+
+       return QLA_FUNCTION_FAILED;
+}
 
 /**
  * qla24xx_start_scsi() - Send a SCSI command to the ISP
@@ -848,6 +1360,191 @@ queuing_error:
        return QLA_FUNCTION_FAILED;
 }
 
+
+/**
+ * qla24xx_dif_start_scsi() - Send a SCSI command to the ISP
+ * @sp: command to send to the ISP
+ *
+ * Returns non-zero if a failure occurred, else zero.
+ */
+int
+qla24xx_dif_start_scsi(srb_t *sp)
+{
+       int                     nseg;
+       unsigned long           flags;
+       uint32_t                *clr_ptr;
+       uint32_t                index;
+       uint32_t                handle;
+       uint16_t                cnt;
+       uint16_t                req_cnt = 0;
+       uint16_t                tot_dsds;
+       uint16_t                tot_prot_dsds;
+       uint16_t                fw_prot_opts = 0;
+       struct req_que          *req = NULL;
+       struct rsp_que          *rsp = NULL;
+       struct scsi_cmnd        *cmd = sp->cmd;
+       struct scsi_qla_host    *vha = sp->fcport->vha;
+       struct qla_hw_data      *ha = vha->hw;
+       struct cmd_type_crc_2   *cmd_pkt;
+       uint32_t                status = 0;
+
+#define QDSS_GOT_Q_SPACE       BIT_0
+
+       /* Only process protection in this routine */
+       if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL)
+               return qla24xx_start_scsi(sp);
+
+       /* Setup device pointers. */
+
+       qla25xx_set_que(sp, &rsp);
+       req = vha->req;
+
+       /* So we know we haven't pci_map'ed anything yet */
+       tot_dsds = 0;
+
+       /* Send marker if required */
+       if (vha->marker_needed != 0) {
+               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
+                   QLA_SUCCESS)
+                       return QLA_FUNCTION_FAILED;
+               vha->marker_needed = 0;
+       }
+
+       /* Acquire ring specific lock */
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+
+       /* Check for room in outstanding command list. */
+       handle = req->current_outstanding_cmd;
+       for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
+               handle++;
+               if (handle == MAX_OUTSTANDING_COMMANDS)
+                       handle = 1;
+               if (!req->outstanding_cmds[handle])
+                       break;
+       }
+
+       if (index == MAX_OUTSTANDING_COMMANDS)
+               goto queuing_error;
+
+       /* Compute number of required data segments */
+       /* Map the sg table so we have an accurate count of sg entries needed */
+       if (scsi_sg_count(cmd)) {
+               nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+                   scsi_sg_count(cmd), cmd->sc_data_direction);
+               if (unlikely(!nseg))
+                       goto queuing_error;
+               else
+                       sp->flags |= SRB_DMA_VALID;
+       } else
+               nseg = 0;
+
+       /* number of required data segments */
+       tot_dsds = nseg;
+
+       /* Compute number of required protection segments */
+       if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) {
+               nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
+                   scsi_prot_sg_count(cmd), cmd->sc_data_direction);
+               if (unlikely(!nseg))
+                       goto queuing_error;
+               else
+                       sp->flags |= SRB_CRC_PROT_DMA_VALID;
+       } else {
+               nseg = 0;
+       }
+
+       req_cnt = 1;
+       /* Total Data and protection sg segment(s) */
+       tot_prot_dsds = nseg;
+       tot_dsds += nseg;
+       if (req->cnt < (req_cnt + 2)) {
+               cnt = RD_REG_DWORD_RELAXED(req->req_q_out);
+
+               if (req->ring_index < cnt)
+                       req->cnt = cnt - req->ring_index;
+               else
+                       req->cnt = req->length -
+                               (req->ring_index - cnt);
+       }
+
+       if (req->cnt < (req_cnt + 2))
+               goto queuing_error;
+
+       status |= QDSS_GOT_Q_SPACE;
+
+       /* Build header part of command packet (excluding the OPCODE). */
+       req->current_outstanding_cmd = handle;
+       req->outstanding_cmds[handle] = sp;
+       sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+       req->cnt -= req_cnt;
+
+       /* Fill-in common area */
+       cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr;
+       cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
+
+       clr_ptr = (uint32_t *)cmd_pkt + 2;
+       memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+
+       /* Set NPORT-ID and LUN number*/
+       cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+       cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
+       cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
+       cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+
+       int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+       host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
+
+       /* Total Data and protection segment(s) */
+       cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
+
+       /* Build IOCB segments and adjust for data protection segments */
+       if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *)
+           req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) !=
+               QLA_SUCCESS)
+               goto queuing_error;
+
+       cmd_pkt->entry_count = (uint8_t)req_cnt;
+       /* Specify response queue number where completion should happen */
+       cmd_pkt->entry_status = (uint8_t) rsp->id;
+       cmd_pkt->timeout = __constant_cpu_to_le16(0);
+       wmb();
+
+       /* Adjust ring index. */
+       req->ring_index++;
+       if (req->ring_index == req->length) {
+               req->ring_index = 0;
+               req->ring_ptr = req->ring;
+       } else
+               req->ring_ptr++;
+
+       /* Set chip new ring index. */
+       WRT_REG_DWORD(req->req_q_in, req->ring_index);
+       RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
+
+       /* Manage unprocessed RIO/ZIO commands in response queue. */
+       if (vha->flags.process_response_queue &&
+           rsp->ring_ptr->signature != RESPONSE_PROCESSED)
+               qla24xx_process_response_queue(vha, rsp);
+
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       return QLA_SUCCESS;
+
+queuing_error:
+       if (status & QDSS_GOT_Q_SPACE) {
+               req->outstanding_cmds[handle] = NULL;
+               req->cnt += req_cnt;
+       }
+       /* Cleanup will be performed by the caller (queuecommand) */
+
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       DEBUG18(qla_printk(KERN_INFO, ha,
+           "CMD sent FAILED SCSI prot_op:%02x\n", scsi_get_prot_op(cmd)));
+       return QLA_FUNCTION_FAILED;
+}
+
+
 static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)
 {
        struct scsi_cmnd *cmd = sp->cmd;
@@ -931,37 +1628,45 @@ qla2x00_start_iocbs(srb_t *sp)
        device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
        struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
 
-       /* Adjust ring index. */
-       req->ring_index++;
-       if (req->ring_index == req->length) {
-               req->ring_index = 0;
-               req->ring_ptr = req->ring;
-       } else
-               req->ring_ptr++;
-
-       /* Set chip new ring index. */
-       if (ha->mqenable) {
-               WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
-               RD_REG_DWORD(&ioreg->hccr);
-       } else if (IS_FWI2_CAPABLE(ha)) {
-               WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
-               RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
+       if (IS_QLA82XX(ha)) {
+               qla82xx_start_iocbs(sp);
        } else {
-               WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp), req->ring_index);
-               RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
+               /* Adjust ring index. */
+               req->ring_index++;
+               if (req->ring_index == req->length) {
+                       req->ring_index = 0;
+                       req->ring_ptr = req->ring;
+               } else
+                       req->ring_ptr++;
+
+               /* Set chip new ring index. */
+               if (ha->mqenable) {
+                       WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
+                       RD_REG_DWORD(&ioreg->hccr);
+               } else if (IS_QLA82XX(ha)) {
+                       qla82xx_start_iocbs(sp);
+               } else if (IS_FWI2_CAPABLE(ha)) {
+                       WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
+                       RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
+               } else {
+                       WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp),
+                               req->ring_index);
+                       RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
+               }
        }
 }
 
 static void
 qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 {
-       struct srb_logio *lio = sp->ctx;
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *lio = ctx->u.iocb_cmd;
 
        logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
        logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
-       if (lio->flags & SRB_LOGIN_COND_PLOGI)
+       if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI)
                logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI);
-       if (lio->flags & SRB_LOGIN_SKIP_PRLI)
+       if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI)
                logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);
        logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
        logio->port_id[0] = sp->fcport->d_id.b.al_pa;
@@ -974,14 +1679,15 @@ static void
 qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
 {
        struct qla_hw_data *ha = sp->fcport->vha->hw;
-       struct srb_logio *lio = sp->ctx;
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *lio = ctx->u.iocb_cmd;
        uint16_t opts;
 
        mbx->entry_type = MBX_IOCB_TYPE;;
        SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
        mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
-       opts = lio->flags & SRB_LOGIN_COND_PLOGI ? BIT_0: 0;
-       opts |= lio->flags & SRB_LOGIN_SKIP_PRLI ? BIT_1: 0;
+       opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0;
+       opts |= lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI ? BIT_1 : 0;
        if (HAS_EXTENDED_IDS(ha)) {
                mbx->mb1 = cpu_to_le16(sp->fcport->loop_id);
                mbx->mb10 = cpu_to_le16(opts);
@@ -1026,9 +1732,97 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
 }
 
 static void
+qla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio)
+{
+       logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
+       logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC);
+       logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+       logio->vp_index = sp->fcport->vp_idx;
+}
+
+static void
+qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx)
+{
+       struct qla_hw_data *ha = sp->fcport->vha->hw;
+
+       mbx->entry_type = MBX_IOCB_TYPE;
+       SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
+       mbx->mb0 = cpu_to_le16(MBC_GET_PORT_DATABASE);
+       if (HAS_EXTENDED_IDS(ha)) {
+               mbx->mb1 = cpu_to_le16(sp->fcport->loop_id);
+               mbx->mb10 = cpu_to_le16(BIT_0);
+       } else {
+               mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | BIT_0);
+       }
+       mbx->mb2 = cpu_to_le16(MSW(ha->async_pd_dma));
+       mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma));
+       mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma)));
+       mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma)));
+       mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx);
+}
+
+static void
+qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
+{
+       uint32_t flags;
+       unsigned int lun;
+       struct fc_port *fcport = sp->fcport;
+       scsi_qla_host_t *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = ctx->u.iocb_cmd;
+       struct req_que *req = vha->req;
+
+       flags = iocb->u.tmf.flags;
+       lun = iocb->u.tmf.lun;
+
+       tsk->entry_type = TSK_MGMT_IOCB_TYPE;
+       tsk->entry_count = 1;
+       tsk->handle = MAKE_HANDLE(req->id, tsk->handle);
+       tsk->nport_handle = cpu_to_le16(fcport->loop_id);
+       tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
+       tsk->control_flags = cpu_to_le32(flags);
+       tsk->port_id[0] = fcport->d_id.b.al_pa;
+       tsk->port_id[1] = fcport->d_id.b.area;
+       tsk->port_id[2] = fcport->d_id.b.domain;
+       tsk->vp_index = fcport->vp_idx;
+
+       if (flags == TCF_LUN_RESET) {
+               int_to_scsilun(lun, &tsk->lun);
+               host_to_fcp_swap((uint8_t *)&tsk->lun,
+                       sizeof(tsk->lun));
+       }
+}
+
+static void
+qla24xx_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
+{
+       uint16_t lun;
+       uint8_t modif;
+       struct fc_port *fcport = sp->fcport;
+       scsi_qla_host_t *vha = fcport->vha;
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = ctx->u.iocb_cmd;
+       struct req_que *req = vha->req;
+
+       lun = iocb->u.marker.lun;
+       modif = iocb->u.marker.modif;
+       mrk->entry_type = MARKER_TYPE;
+       mrk->modifier = modif;
+       if (modif !=  MK_SYNC_ALL) {
+               mrk->nport_handle = cpu_to_le16(fcport->loop_id);
+               mrk->lun[1] = LSB(lun);
+               mrk->lun[2] = MSB(lun);
+               host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
+               mrk->vp_index = vha->vp_idx;
+               mrk->handle = MAKE_HANDLE(req->id, mrk->handle);
+       }
+}
+
+static void
 qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
-       struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job;
+       struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
 
         els_iocb->entry_type = ELS_IOCB_TYPE;
         els_iocb->entry_count = 1;
@@ -1041,8 +1835,10 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
         els_iocb->sof_type = EST_SOFI3;
         els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt);
 
-        els_iocb->opcode =(((struct srb_bsg*)sp->ctx)->ctx.type == SRB_ELS_CMD_RPT) ?
-           bsg_job->request->rqst_data.r_els.els_code : bsg_job->request->rqst_data.h_els.command_code;
+       els_iocb->opcode =
+           (((struct srb_ctx *)sp->ctx)->type == SRB_ELS_CMD_RPT) ?
+           bsg_job->request->rqst_data.r_els.els_code :
+           bsg_job->request->rqst_data.h_els.command_code;
         els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
         els_iocb->port_id[1] = sp->fcport->d_id.b.area;
         els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
@@ -1076,7 +1872,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb)
        int index;
        uint16_t tot_dsds;
         scsi_qla_host_t *vha = sp->fcport->vha;
-       struct fc_bsg_job *bsg_job = ((struct srb_bsg*)sp->ctx)->bsg_job;
+       struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job;
        int loop_iterartion = 0;
        int cont_iocb_prsnt = 0;
        int entry_count = 1;
@@ -1157,12 +1953,12 @@ qla2x00_start_sp(srb_t *sp)
        switch (ctx->type) {
        case SRB_LOGIN_CMD:
                IS_FWI2_CAPABLE(ha) ?
-                   qla24xx_login_iocb(sp, pkt):
+                   qla24xx_login_iocb(sp, pkt) :
                    qla2x00_login_iocb(sp, pkt);
                break;
        case SRB_LOGOUT_CMD:
                IS_FWI2_CAPABLE(ha) ?
-                   qla24xx_logout_iocb(sp, pkt):
+                   qla24xx_logout_iocb(sp, pkt) :
                    qla2x00_logout_iocb(sp, pkt);
                break;
        case SRB_ELS_CMD_RPT:
@@ -1172,6 +1968,17 @@ qla2x00_start_sp(srb_t *sp)
        case SRB_CT_CMD:
                qla24xx_ct_iocb(sp, pkt);
                break;
+       case SRB_ADISC_CMD:
+               IS_FWI2_CAPABLE(ha) ?
+                   qla24xx_adisc_iocb(sp, pkt) :
+                   qla2x00_adisc_iocb(sp, pkt);
+               break;
+       case SRB_TM_CMD:
+               qla24xx_tm_iocb(sp, pkt);
+               break;
+       case SRB_MARKER_CMD:
+               qla24xx_marker_iocb(sp, pkt);
+               break;
        default:
                break;
        }
index db539b0..be3d8be 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_bsg_fc.h>
+#include <scsi/scsi_eh.h>
 
 static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
 static void qla2x00_process_completed_request(struct scsi_qla_host *,
@@ -326,7 +327,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 
        /* Setup to process RIO completion. */
        handle_cnt = 0;
-       if (IS_QLA81XX(ha))
+       if (IS_QLA8XXX_TYPE(ha))
                goto skip_rio;
        switch (mb[0]) {
        case MBA_SCSI_COMPLETION:
@@ -544,7 +545,7 @@ skip_rio:
                if (IS_QLA2100(ha))
                        break;
 
-               if (IS_QLA81XX(ha))
+               if (IS_QLA8XXX_TYPE(ha))
                        DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
                            "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
                else
@@ -845,7 +846,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
                qla2x00_sp_compl(ha, sp);
        } else {
                DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
-                       " handle(%d)\n", vha->host_no, req->id, index));
+                       " handle(0x%x)\n", vha->host_no, req->id, index));
                qla_printk(KERN_WARNING, ha,
                    "Invalid ISP SCSI completion handle\n");
 
@@ -895,36 +896,26 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 {
        const char func[] = "MBX-IOCB";
        const char *type;
-       struct qla_hw_data *ha = vha->hw;
        fc_port_t *fcport;
        srb_t *sp;
-       struct srb_logio *lio;
-       uint16_t data[2];
+       struct srb_iocb *lio;
+       struct srb_ctx *ctx;
+       uint16_t *data;
+       uint16_t status;
 
        sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
        if (!sp)
                return;
 
-       type = NULL;
-       lio = sp->ctx;
-       switch (lio->ctx.type) {
-       case SRB_LOGIN_CMD:
-               type = "login";
-               break;
-       case SRB_LOGOUT_CMD:
-               type = "logout";
-               break;
-       default:
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
-                   lio->ctx.type);
-               return;
-       }
-
-       del_timer(&lio->ctx.timer);
+       ctx = sp->ctx;
+       lio = ctx->u.iocb_cmd;
+       type = ctx->name;
        fcport = sp->fcport;
+       data = lio->u.logio.data;
 
-       data[0] = data[1] = 0;
+       data[0] = MBS_COMMAND_ERROR;
+       data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
+           QLA_LOGIO_LOGIN_RETRIED : 0;
        if (mbx->entry_status) {
                DEBUG2(printk(KERN_WARNING
                    "scsi(%ld:%x): Async-%s error entry - entry-status=%x "
@@ -935,23 +926,28 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
                    le16_to_cpu(mbx->status_flags)));
                DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
 
-               data[0] = MBS_COMMAND_ERROR;
-               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
-                   QLA_LOGIO_LOGIN_RETRIED: 0;
-               goto done_post_logio_done_work;
+               goto logio_done;
        }
 
-       if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
+       status = le16_to_cpu(mbx->status);
+       if (status == 0x30 && ctx->type == SRB_LOGIN_CMD &&
+           le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
+               status = 0;
+       if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
                DEBUG2(printk(KERN_DEBUG
                    "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
                    fcport->vha->host_no, sp->handle, type,
                    le16_to_cpu(mbx->mb1)));
 
                data[0] = MBS_COMMAND_COMPLETE;
-               if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1)
-                       fcport->flags |= FCF_FCP2_DEVICE;
-
-               goto done_post_logio_done_work;
+               if (ctx->type == SRB_LOGIN_CMD) {
+                       fcport->port_type = FCT_TARGET;
+                       if (le16_to_cpu(mbx->mb1) & BIT_0)
+                               fcport->port_type = FCT_INITIATOR;
+                       if (le16_to_cpu(mbx->mb1) & BIT_1)
+                               fcport->flags |= FCF_FCP2_DEVICE;
+               }
+               goto logio_done;
        }
 
        data[0] = le16_to_cpu(mbx->mb0);
@@ -963,25 +959,19 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
                break;
        default:
                data[0] = MBS_COMMAND_ERROR;
-               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
-                   QLA_LOGIO_LOGIN_RETRIED: 0;
                break;
        }
 
        DEBUG2(printk(KERN_WARNING
            "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
            "mb6=%x mb7=%x.\n",
-           fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status),
+           fcport->vha->host_no, sp->handle, type, status,
            le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
            le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
            le16_to_cpu(mbx->mb7)));
 
-done_post_logio_done_work:
-       lio->ctx.type == SRB_LOGIN_CMD ?
-           qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
-           qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
-
-       lio->ctx.free(sp);
+logio_done:
+       lio->done(sp);
 }
 
 static void
@@ -992,7 +982,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
        const char *type;
        struct qla_hw_data *ha = vha->hw;
        srb_t *sp;
-       struct srb_bsg *sp_bsg;
+       struct srb_ctx *sp_bsg;
        struct fc_bsg_job *bsg_job;
        uint16_t comp_status;
        uint32_t fw_status[3];
@@ -1001,11 +991,11 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
        sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
        if (!sp)
                return;
-       sp_bsg = (struct srb_bsg*)sp->ctx;
-       bsg_job = sp_bsg->bsg_job;
+       sp_bsg = sp->ctx;
+       bsg_job = sp_bsg->u.bsg_job;
 
        type = NULL;
-       switch (sp_bsg->ctx.type) {
+       switch (sp_bsg->type) {
        case SRB_ELS_CMD_RPT:
        case SRB_ELS_CMD_HST:
                type = "els";
@@ -1016,7 +1006,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
        default:
                qla_printk(KERN_WARNING, ha,
                    "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
-                   sp_bsg->ctx.type);
+                   sp_bsg->type);
                return;
        }
 
@@ -1070,8 +1060,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
        dma_unmap_sg(&ha->pdev->dev,
            bsg_job->reply_payload.sg_list,
            bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-       if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) ||
-           (sp_bsg->ctx.type == SRB_CT_CMD))
+       if ((sp_bsg->type == SRB_ELS_CMD_HST) ||
+           (sp_bsg->type == SRB_CT_CMD))
                kfree(sp->fcport);
        kfree(sp->ctx);
        mempool_free(sp, ha->srb_mempool);
@@ -1084,37 +1074,26 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 {
        const char func[] = "LOGIO-IOCB";
        const char *type;
-       struct qla_hw_data *ha = vha->hw;
        fc_port_t *fcport;
        srb_t *sp;
-       struct srb_logio *lio;
-       uint16_t data[2];
+       struct srb_iocb *lio;
+       struct srb_ctx *ctx;
+       uint16_t *data;
        uint32_t iop[2];
 
        sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
        if (!sp)
                return;
 
-       type = NULL;
-       lio = sp->ctx;
-       switch (lio->ctx.type) {
-       case SRB_LOGIN_CMD:
-               type = "login";
-               break;
-       case SRB_LOGOUT_CMD:
-               type = "logout";
-               break;
-       default:
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
-                   lio->ctx.type);
-               return;
-       }
-
-       del_timer(&lio->ctx.timer);
+       ctx = sp->ctx;
+       lio = ctx->u.iocb_cmd;
+       type = ctx->name;
        fcport = sp->fcport;
+       data = lio->u.logio.data;
 
-       data[0] = data[1] = 0;
+       data[0] = MBS_COMMAND_ERROR;
+       data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
+               QLA_LOGIO_LOGIN_RETRIED : 0;
        if (logio->entry_status) {
                DEBUG2(printk(KERN_WARNING
                    "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
@@ -1122,10 +1101,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
                    logio->entry_status));
                DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
 
-               data[0] = MBS_COMMAND_ERROR;
-               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
-                   QLA_LOGIO_LOGIN_RETRIED: 0;
-               goto done_post_logio_done_work;
+               goto logio_done;
        }
 
        if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
@@ -1135,8 +1111,8 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
                    le32_to_cpu(logio->io_parameter[0])));
 
                data[0] = MBS_COMMAND_COMPLETE;
-               if (lio->ctx.type == SRB_LOGOUT_CMD)
-                       goto done_post_logio_done_work;
+               if (ctx->type != SRB_LOGIN_CMD)
+                       goto logio_done;
 
                iop[0] = le32_to_cpu(logio->io_parameter[0]);
                if (iop[0] & BIT_4) {
@@ -1151,7 +1127,7 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
                if (logio->io_parameter[9] || logio->io_parameter[10])
                        fcport->supported_classes |= FC_COS_CLASS3;
 
-               goto done_post_logio_done_work;
+               goto logio_done;
        }
 
        iop[0] = le32_to_cpu(logio->io_parameter[0]);
@@ -1172,8 +1148,6 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
                /* Fall through. */
        default:
                data[0] = MBS_COMMAND_ERROR;
-               data[1] = lio->flags & SRB_LOGIN_RETRIED ?
-                   QLA_LOGIO_LOGIN_RETRIED: 0;
                break;
        }
 
@@ -1184,12 +1158,101 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
            le32_to_cpu(logio->io_parameter[0]),
            le32_to_cpu(logio->io_parameter[1])));
 
-done_post_logio_done_work:
-       lio->ctx.type == SRB_LOGIN_CMD ?
-           qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
-           qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
+logio_done:
+       lio->done(sp);
+}
 
-       lio->ctx.free(sp);
+static void
+qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+    struct tsk_mgmt_entry *tsk)
+{
+       const char func[] = "TMF-IOCB";
+       const char *type;
+       fc_port_t *fcport;
+       srb_t *sp;
+       struct srb_iocb *iocb;
+       struct srb_ctx *ctx;
+       struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
+       int error = 1;
+
+       sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
+       if (!sp)
+               return;
+
+       ctx = sp->ctx;
+       iocb = ctx->u.iocb_cmd;
+       type = ctx->name;
+       fcport = sp->fcport;
+
+       if (sts->entry_status) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - entry-status(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->entry_status));
+       } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - completion status(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->comp_status));
+       } else if (!(le16_to_cpu(sts->scsi_status) &
+           SS_RESPONSE_INFO_LEN_VALID)) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - no response info(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->scsi_status));
+       } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - not enough response(%d).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->rsp_data_len));
+       } else if (sts->data[3]) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - response(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->data[3]));
+       } else {
+               error = 0;
+       }
+
+       if (error) {
+               iocb->u.tmf.data = error;
+               DEBUG2(qla2x00_dump_buffer((uint8_t *)sts, sizeof(*sts)));
+       }
+
+       iocb->done(sp);
+}
+
+static void
+qla24xx_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+    struct mrk_entry_24xx *mrk)
+{
+       const char func[] = "MRK-IOCB";
+       const char *type;
+       fc_port_t *fcport;
+       srb_t *sp;
+       struct srb_iocb *iocb;
+       struct srb_ctx *ctx;
+       struct sts_entry_24xx *sts = (struct sts_entry_24xx *)mrk;
+
+       sp = qla2x00_get_sp_from_handle(vha, func, req, mrk);
+       if (!sp)
+               return;
+
+       ctx = sp->ctx;
+       iocb = ctx->u.iocb_cmd;
+       type = ctx->name;
+       fcport = sp->fcport;
+
+       if (sts->entry_status) {
+               iocb->u.marker.data = 1;
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->entry_status));
+               DEBUG2(qla2x00_dump_buffer((uint8_t *)mrk, sizeof(*sts)));
+       }
+
+       iocb->done(sp);
 }
 
 /**
@@ -1256,6 +1319,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
                case MBX_IOCB_TYPE:
                        qla2x00_mbx_iocb_entry(vha, rsp->req,
                            (struct mbx_entry *)pkt);
+                       break;
                default:
                        /* Type Not Supported. */
                        DEBUG4(printk(KERN_WARNING
@@ -1301,6 +1365,78 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
                DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
 }
 
+struct scsi_dif_tuple {
+       __be16 guard;       /* Checksum */
+       __be16 app_tag;         /* APPL identifer */
+       __be32 ref_tag;         /* Target LBA or indirect LBA */
+};
+
+/*
+ * Checks the guard or meta-data for the type of error
+ * detected by the HBA. In case of errors, we set the
+ * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
+ * to indicate to the kernel that the HBA detected error.
+ */
+static inline void
+qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
+{
+       struct scsi_cmnd *cmd = sp->cmd;
+       struct scsi_dif_tuple   *ep =
+                       (struct scsi_dif_tuple *)&sts24->data[20];
+       struct scsi_dif_tuple   *ap =
+                       (struct scsi_dif_tuple *)&sts24->data[12];
+       uint32_t        e_ref_tag, a_ref_tag;
+       uint16_t        e_app_tag, a_app_tag;
+       uint16_t        e_guard, a_guard;
+
+       e_ref_tag = be32_to_cpu(ep->ref_tag);
+       a_ref_tag = be32_to_cpu(ap->ref_tag);
+       e_app_tag = be16_to_cpu(ep->app_tag);
+       a_app_tag = be16_to_cpu(ap->app_tag);
+       e_guard = be16_to_cpu(ep->guard);
+       a_guard = be16_to_cpu(ap->guard);
+
+       DEBUG18(printk(KERN_DEBUG
+           "%s(): iocb(s) %p Returned STATUS\n", __func__, sts24));
+
+       DEBUG18(printk(KERN_ERR "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
+           " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
+           " tag=0x%x, act guard=0x%x, exp guard=0x%x\n",
+           cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
+           a_app_tag, e_app_tag, a_guard, e_guard));
+
+
+       /* check guard */
+       if (e_guard != a_guard) {
+               scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
+                   0x10, 0x1);
+               set_driver_byte(cmd, DRIVER_SENSE);
+               set_host_byte(cmd, DID_ABORT);
+               cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
+               return;
+       }
+
+       /* check appl tag */
+       if (e_app_tag != a_app_tag) {
+               scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
+                   0x10, 0x2);
+               set_driver_byte(cmd, DRIVER_SENSE);
+               set_host_byte(cmd, DID_ABORT);
+               cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
+               return;
+       }
+
+       /* check ref tag */
+       if (e_ref_tag != a_ref_tag) {
+               scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
+                   0x10, 0x3);
+               set_driver_byte(cmd, DRIVER_SENSE);
+               set_host_byte(cmd, DID_ABORT);
+               cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
+               return;
+       }
+}
+
 /**
  * qla2x00_status_entry() - Process a Status IOCB entry.
  * @ha: SCSI driver HA context
@@ -1316,6 +1452,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        struct sts_entry_24xx *sts24;
        uint16_t        comp_status;
        uint16_t        scsi_status;
+       uint16_t        ox_id;
        uint8_t         lscsi_status;
        int32_t         resid;
        uint32_t        sense_len, rsp_info_len, resid_len, fw_resid_len;
@@ -1324,6 +1461,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        uint32_t handle;
        uint16_t que;
        struct req_que *req;
+       int logit = 1;
 
        sts = (sts_entry_t *) pkt;
        sts24 = (struct sts_entry_24xx *) pkt;
@@ -1337,6 +1475,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        handle = (uint32_t) LSW(sts->handle);
        que = MSW(sts->handle);
        req = ha->req_q_map[que];
+
        /* Fast path completion. */
        if (comp_status == CS_COMPLETE && scsi_status == 0) {
                qla2x00_process_completed_request(vha, req, handle);
@@ -1352,9 +1491,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                sp = NULL;
 
        if (sp == NULL) {
-               DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n",
-                   vha->host_no));
-               qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n");
+               qla_printk(KERN_WARNING, ha,
+                   "scsi(%ld): Invalid status handle (0x%x).\n", vha->host_no,
+                   sts->handle);
 
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                qla2xxx_wake_dpc(vha);
@@ -1362,10 +1501,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        }
        cp = sp->cmd;
        if (cp == NULL) {
-               DEBUG2(printk("scsi(%ld): Command already returned back to OS "
-                   "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp));
                qla_printk(KERN_WARNING, ha,
-                   "Command is NULL: already returned to OS (sp=%p)\n", sp);
+                   "scsi(%ld): Command already returned (0x%x/%p).\n",
+                   vha->host_no, sts->handle, sp);
 
                return;
        }
@@ -1374,6 +1512,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 
        fcport = sp->fcport;
 
+       ox_id = 0;
        sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
        if (IS_FWI2_CAPABLE(ha)) {
                if (scsi_status & SS_SENSE_LEN_VALID)
@@ -1387,6 +1526,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                rsp_info = sts24->data;
                sense_data = sts24->data;
                host_to_fcp_swap(sts24->data, sizeof(sts24->data));
+               ox_id = le16_to_cpu(sts24->ox_id);
        } else {
                if (scsi_status & SS_SENSE_LEN_VALID)
                        sense_len = le16_to_cpu(sts->req_sense_length);
@@ -1403,17 +1543,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                if (IS_FWI2_CAPABLE(ha))
                        sense_data += rsp_info_len;
                if (rsp_info_len > 3 && rsp_info[3]) {
-                       DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
-                           "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
-                           "retrying command\n", vha->host_no,
-                           cp->device->channel, cp->device->id,
-                           cp->device->lun, rsp_info_len, rsp_info[0],
-                           rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4],
-                           rsp_info[5], rsp_info[6], rsp_info[7]));
+                       DEBUG2(qla_printk(KERN_INFO, ha,
+                           "scsi(%ld:%d:%d): FCP I/O protocol failure "
+                           "(0x%x/0x%x).\n", vha->host_no, cp->device->id,
+                           cp->device->lun, rsp_info_len, rsp_info[3]));
 
                        cp->result = DID_BUS_BUSY << 16;
-                       qla2x00_sp_compl(ha, sp);
-                       return;
+                       goto out;
                }
        }
 
@@ -1440,12 +1576,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                            ((unsigned)(scsi_bufflen(cp) - resid) <
                             cp->underflow)) {
                                qla_printk(KERN_INFO, ha,
-                                          "scsi(%ld:%d:%d:%d): Mid-layer underflow "
-                                          "detected (%x of %x bytes)...returning "
-                                          "error status.\n", vha->host_no,
-                                          cp->device->channel, cp->device->id,
-                                          cp->device->lun, resid,
-                                          scsi_bufflen(cp));
+                                   "scsi(%ld:%d:%d): Mid-layer underflow "
+                                   "detected (0x%x of 0x%x bytes).\n",
+                                   vha->host_no, cp->device->id,
+                                   cp->device->lun, resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16;
                                break;
@@ -1454,12 +1588,12 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                cp->result = DID_OK << 16 | lscsi_status;
 
                if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-                       DEBUG2(printk(KERN_INFO
-                           "scsi(%ld): QUEUE FULL status detected "
-                           "0x%x-0x%x.\n", vha->host_no, comp_status,
-                           scsi_status));
+                       DEBUG2(qla_printk(KERN_INFO, ha,
+                           "scsi(%ld:%d:%d) QUEUE FULL detected.\n",
+                           vha->host_no, cp->device->id, cp->device->lun));
                        break;
                }
+               logit = 0;
                if (lscsi_status != SS_CHECK_CONDITION)
                        break;
 
@@ -1471,23 +1605,14 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                break;
 
        case CS_DATA_UNDERRUN:
-               DEBUG2(printk(KERN_INFO
-                   "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. "
-                   "resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n",
-                   vha->host_no, cp->device->id, cp->device->lun, comp_status,
-                   scsi_status, resid_len, fw_resid_len, cp->cmnd[0],
-                   cp->underflow));
-
                /* Use F/W calculated residual length. */
                resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
                scsi_set_resid(cp, resid);
                if (scsi_status & SS_RESIDUAL_UNDER) {
                        if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
-                               DEBUG2(printk(
-                                   "scsi(%ld:%d:%d:%d) Dropped frame(s) "
-                                   "detected (%x of %x bytes)...residual "
-                                   "length mismatch...retrying command.\n",
-                                   vha->host_no, cp->device->channel,
+                               DEBUG2(qla_printk(KERN_INFO, ha,
+                                   "scsi(%ld:%d:%d) Dropped frame(s) detected "
+                                   "(0x%x of 0x%x bytes).\n", vha->host_no,
                                    cp->device->id, cp->device->lun, resid,
                                    scsi_bufflen(cp)));
 
@@ -1499,21 +1624,18 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                            ((unsigned)(scsi_bufflen(cp) - resid) <
                            cp->underflow)) {
                                qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
-                                   "detected (%x of %x bytes)...returning "
-                                   "error status.\n", vha->host_no,
-                                   cp->device->channel, cp->device->id,
+                                   "scsi(%ld:%d:%d): Mid-layer underflow "
+                                   "detected (0x%x of 0x%x bytes).\n",
+                                   vha->host_no, cp->device->id,
                                    cp->device->lun, resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16;
                                break;
                        }
                } else if (!lscsi_status) {
-                       DEBUG2(printk(
-                           "scsi(%ld:%d:%d:%d) Dropped frame(s) detected "
-                           "(%x of %x bytes)...firmware reported underrun..."
-                           "retrying command.\n", vha->host_no,
-                           cp->device->channel, cp->device->id,
+                       DEBUG2(qla_printk(KERN_INFO, ha,
+                           "scsi(%ld:%d:%d) Dropped frame(s) detected (0x%x "
+                           "of 0x%x bytes).\n", vha->host_no, cp->device->id,
                            cp->device->lun, resid, scsi_bufflen(cp)));
 
                        cp->result = DID_ERROR << 16;
@@ -1521,6 +1643,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                }
 
                cp->result = DID_OK << 16 | lscsi_status;
+               logit = 0;
 
                /*
                 * Check to see if SCSI Status is non zero. If so report SCSI
@@ -1528,10 +1651,11 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                 */
                if (lscsi_status != 0) {
                        if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-                               DEBUG2(printk(KERN_INFO
-                                   "scsi(%ld): QUEUE FULL status detected "
-                                   "0x%x-0x%x.\n", vha->host_no, comp_status,
-                                   scsi_status));
+                               DEBUG2(qla_printk(KERN_INFO, ha,
+                                   "scsi(%ld:%d:%d) QUEUE FULL detected.\n",
+                                   vha->host_no, cp->device->id,
+                                   cp->device->lun));
+                               logit = 1;
                                break;
                        }
                        if (lscsi_status != SS_CHECK_CONDITION)
@@ -1545,109 +1669,60 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                }
                break;
 
-       case CS_DATA_OVERRUN:
-               DEBUG2(printk(KERN_INFO
-                   "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n",
-                   vha->host_no, cp->device->id, cp->device->lun, comp_status,
-                   scsi_status));
-               DEBUG2(printk(KERN_INFO
-                   "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
-                   cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
-                   cp->cmnd[4], cp->cmnd[5]));
-               DEBUG2(printk(KERN_INFO
-                   "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR "
-                   "status!\n",
-                   cp->serial_number, scsi_bufflen(cp), resid_len));
-
-               cp->result = DID_ERROR << 16;
-               break;
-
        case CS_PORT_LOGGED_OUT:
        case CS_PORT_CONFIG_CHG:
        case CS_PORT_BUSY:
        case CS_INCOMPLETE:
        case CS_PORT_UNAVAILABLE:
-               /*
-                * If the port is in Target Down state, return all IOs for this
-                * Target with DID_NO_CONNECT ELSE Queue the IOs in the
-                * retry_queue.
-                */
-               DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
-                   "pid=%ld, compl status=0x%x, port state=0x%x\n",
-                   vha->host_no, cp->device->id, cp->device->lun,
-                   cp->serial_number, comp_status,
-                   atomic_read(&fcport->state)));
-
+       case CS_TIMEOUT:
                /*
                 * We are going to have the fc class block the rport
                 * while we try to recover so instruct the mid layer
                 * to requeue until the class decides how to handle this.
                 */
                cp->result = DID_TRANSPORT_DISRUPTED << 16;
+
+               if (comp_status == CS_TIMEOUT) {
+                       if (IS_FWI2_CAPABLE(ha))
+                               break;
+                       else if ((le16_to_cpu(sts->status_flags) &
+                           SF_LOGOUT_SENT) == 0)
+                               break;
+               }
+
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                       "scsi(%ld:%d:%d) Port down status: port-state=0x%x\n",
+                       vha->host_no, cp->device->id, cp->device->lun,
+                       atomic_read(&fcport->state)));
+
                if (atomic_read(&fcport->state) == FCS_ONLINE)
                        qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
                break;
 
        case CS_RESET:
-               DEBUG2(printk(KERN_INFO
-                   "scsi(%ld): RESET status detected 0x%x-0x%x.\n",
-                   vha->host_no, comp_status, scsi_status));
-
-               cp->result = DID_RESET << 16;
-               break;
-
        case CS_ABORTED:
-               /*
-                * hv2.19.12 - DID_ABORT does not retry the request if we
-                * aborted this request then abort otherwise it must be a
-                * reset.
-                */
-               DEBUG2(printk(KERN_INFO
-                   "scsi(%ld): ABORT status detected 0x%x-0x%x.\n",
-                   vha->host_no, comp_status, scsi_status));
-
                cp->result = DID_RESET << 16;
                break;
 
-       case CS_TIMEOUT:
-               /*
-                * We are going to have the fc class block the rport
-                * while we try to recover so instruct the mid layer
-                * to requeue until the class decides how to handle this.
-                */
-               cp->result = DID_TRANSPORT_DISRUPTED << 16;
-
-               if (IS_FWI2_CAPABLE(ha)) {
-                       DEBUG2(printk(KERN_INFO
-                           "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
-                           "0x%x-0x%x\n", vha->host_no, cp->device->channel,
-                           cp->device->id, cp->device->lun, comp_status,
-                           scsi_status));
-                       break;
-               }
-               DEBUG2(printk(KERN_INFO
-                   "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
-                   "sflags=%x.\n", vha->host_no, cp->device->channel,
-                   cp->device->id, cp->device->lun, comp_status, scsi_status,
-                   le16_to_cpu(sts->status_flags)));
-
-               /* Check to see if logout occurred. */
-               if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
-                       qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
+       case CS_DIF_ERROR:
+               qla2x00_handle_dif_error(sp, sts24);
                break;
-
        default:
-               DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
-                   "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status));
-               qla_printk(KERN_INFO, ha,
-                   "Unknown status detected 0x%x-0x%x.\n",
-                   comp_status, scsi_status);
-
                cp->result = DID_ERROR << 16;
                break;
        }
 
-       /* Place command on done queue. */
+out:
+       if (logit)
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) "
+                   "oxid=0x%x ser=0x%lx cdb=%02x%02x%02x len=0x%x "
+                   "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no,
+                   cp->device->id, cp->device->lun, comp_status, scsi_status,
+                   cp->result, ox_id, cp->serial_number, cp->cmnd[0],
+                   cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len,
+                   resid_len, fw_resid_len));
+
        if (rsp->status_srb == NULL)
                qla2x00_sp_compl(ha, sp);
 }
@@ -1806,6 +1881,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
        struct rsp_que *rsp)
 {
        struct sts_entry_24xx *pkt;
+       struct qla_hw_data *ha = vha->hw;
 
        if (!vha->flags.online)
                return;
@@ -1846,6 +1922,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
                        qla24xx_logio_entry(vha, rsp->req,
                            (struct logio_entry_24xx *)pkt);
                        break;
+               case TSK_MGMT_IOCB_TYPE:
+                       qla24xx_tm_iocb_entry(vha, rsp->req,
+                           (struct tsk_mgmt_entry *)pkt);
+                       break;
+               case MARKER_TYPE:
+                       qla24xx_marker_iocb_entry(vha, rsp->req,
+                           (struct mrk_entry_24xx *)pkt);
+                       break;
                 case CT_IOCB_TYPE:
                        qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
                        clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
@@ -1866,7 +1950,11 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
        }
 
        /* Adjust ring index */
-       WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
+       if (IS_QLA82XX(ha)) {
+               struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
+               WRT_REG_DWORD(&reg->rsp_q_out[0], rsp->ring_index);
+       } else
+               WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
 }
 
 static void
@@ -2169,6 +2257,11 @@ static struct qla_init_msix_entry msix_entries[3] = {
        { "qla2xxx (multiq)", qla25xx_msix_rsp_q },
 };
 
+static struct qla_init_msix_entry qla82xx_msix_entries[2] = {
+       { "qla2xxx (default)", qla82xx_msix_default },
+       { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
+};
+
 static void
 qla24xx_disable_msix(struct qla_hw_data *ha)
 {
@@ -2195,7 +2288,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
        struct qla_msix_entry *qentry;
 
        entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
-                                       GFP_KERNEL);
+                       GFP_KERNEL);
        if (!entries)
                return -ENOMEM;
 
@@ -2240,8 +2333,15 @@ msix_failed:
        /* Enable MSI-X vectors for the base queue */
        for (i = 0; i < 2; i++) {
                qentry = &ha->msix_entries[i];
-               ret = request_irq(qentry->vector, msix_entries[i].handler,
-                                       0, msix_entries[i].name, rsp);
+               if (IS_QLA82XX(ha)) {
+                       ret = request_irq(qentry->vector,
+                               qla82xx_msix_entries[i].handler,
+                               0, qla82xx_msix_entries[i].name, rsp);
+               } else {
+                       ret = request_irq(qentry->vector,
+                               msix_entries[i].handler,
+                               0, msix_entries[i].name, rsp);
+               }
                if (ret) {
                        qla_printk(KERN_WARNING, ha,
                        "MSI-X: Unable to register handler -- %x/%d.\n",
@@ -2272,7 +2372,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
 
        /* If possible, enable MSI-X. */
        if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
-               !IS_QLA8432(ha) && !IS_QLA8001(ha))
+               !IS_QLA8432(ha) && !IS_QLA8XXX_TYPE(ha))
                goto skip_msi;
 
        if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
@@ -2302,7 +2402,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
                goto clear_risc_ints;
        }
        qla_printk(KERN_WARNING, ha,
-           "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
+           "MSI-X: Falling back-to MSI mode -- %d.\n", ret);
 skip_msix:
 
        if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
@@ -2313,7 +2413,9 @@ skip_msix:
        if (!ret) {
                DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
                ha->flags.msi_enabled = 1;
-       }
+       } else
+               qla_printk(KERN_WARNING, ha,
+                   "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
 skip_msi:
 
        ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
@@ -2331,7 +2433,7 @@ clear_risc_ints:
         * FIXME: Noted that 8014s were being dropped during NK testing.
         * Timing deltas during MSI-X/INTa transitions?
         */
-       if (IS_QLA81XX(ha))
+       if (IS_QLA81XX(ha) || IS_QLA82XX(ha))
                goto fail;
        spin_lock_irq(&ha->hardware_lock);
        if (IS_FWI2_CAPABLE(ha)) {
index 42eb7ff..f3650d0 100644 (file)
@@ -49,6 +49,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        if (ha->pdev->error_state > pci_channel_io_frozen)
                return QLA_FUNCTION_TIMEOUT;
 
+       if (vha->device_flags & DFLG_DEV_FAILED) {
+               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
+                       "%s(%ld): Device in failed state, "
+                       "timeout MBX Exiting.\n",
+                       __func__, base_vha->host_no));
+               return QLA_FUNCTION_TIMEOUT;
+       }
+
        reg = ha->iobase;
        io_lock_on = base_vha->flags.init_done;
 
@@ -85,7 +93,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
        /* Load mailbox registers. */
-       if (IS_FWI2_CAPABLE(ha))
+       if (IS_QLA82XX(ha))
+               optr = (uint16_t __iomem *)&reg->isp82.mailbox_in[0];
+       else if (IS_FWI2_CAPABLE(ha) && !IS_QLA82XX(ha))
                optr = (uint16_t __iomem *)&reg->isp24.mailbox0;
        else
                optr = (uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 0);
@@ -133,7 +143,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
                set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
-               if (IS_FWI2_CAPABLE(ha))
+               if (IS_QLA82XX(ha)) {
+                       if (RD_REG_DWORD(&reg->isp82.hint) &
+                               HINT_MBX_INT_PENDING) {
+                               spin_unlock_irqrestore(&ha->hardware_lock,
+                                       flags);
+                               DEBUG2_3_11(printk(KERN_INFO
+                                   "%s(%ld): Pending Mailbox timeout. "
+                                   "Exiting.\n", __func__, base_vha->host_no));
+                               return QLA_FUNCTION_TIMEOUT;
+                       }
+                       WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
+               } else if (IS_FWI2_CAPABLE(ha))
                        WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
                else
                        WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -147,7 +168,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
                    base_vha->host_no, command));
 
-               if (IS_FWI2_CAPABLE(ha))
+               if (IS_QLA82XX(ha)) {
+                       if (RD_REG_DWORD(&reg->isp82.hint) &
+                               HINT_MBX_INT_PENDING) {
+                               spin_unlock_irqrestore(&ha->hardware_lock,
+                                       flags);
+                               DEBUG2_3_11(printk(KERN_INFO
+                                   "%s(%ld): Pending Mailbox timeout. "
+                                   "Exiting.\n", __func__, base_vha->host_no));
+                               return QLA_FUNCTION_TIMEOUT;
+                       }
+                       WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
+               } else if (IS_FWI2_CAPABLE(ha))
                        WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
                else
                        WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -264,7 +296,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 
                        set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
                        clear_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
-                       if (qla2x00_abort_isp(base_vha)) {
+                       if (ha->isp_ops->abort_isp(base_vha)) {
                                /* Failed. retry later. */
                                set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
                        }
@@ -711,7 +743,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr)
  * Context:
  *     Kernel context.
  */
-static int
+int
 qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer,
     dma_addr_t phys_addr, size_t size, uint32_t tov)
 {
@@ -952,7 +984,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
        mcp->mb[9] = vha->vp_idx;
        mcp->out_mb = MBX_9|MBX_0;
        mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
-       if (IS_QLA81XX(vha->hw))
+       if (IS_QLA8XXX_TYPE(vha->hw))
                mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
@@ -978,7 +1010,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
                DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
                    vha->host_no));
 
-               if (IS_QLA81XX(vha->hw)) {
+               if (IS_QLA8XXX_TYPE(vha->hw)) {
                        vha->fcoe_vlan_id = mcp->mb[9] & 0xfff;
                        vha->fcoe_fcf_idx = mcp->mb[10];
                        vha->fcoe_vn_port_mac[5] = mcp->mb[11] >> 8;
@@ -1076,6 +1108,10 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
        DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
            vha->host_no));
 
+       if (IS_QLA82XX(ha) && ql2xdbwr)
+               qla82xx_wr_32(ha, ha->nxdb_wr_ptr,
+                       (0x04 | (ha->portnum << 5) | (0 << 8) | (0 << 16)));
+
        if (ha->flags.npiv_supported)
                mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
        else
@@ -1408,7 +1444,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
-       if (IS_QLA81XX(vha->hw)) {
+       if (IS_QLA8XXX_TYPE(vha->hw)) {
                /* Logout across all FCFs. */
                mcp->mb[0] = MBC_LIP_FULL_LOGIN;
                mcp->mb[1] = BIT_1;
@@ -2428,12 +2464,22 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 int
 qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag)
 {
+       struct qla_hw_data *ha = fcport->vha->hw;
+
+       if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha))
+               return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
+
        return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag);
 }
 
 int
 qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
 {
+       struct qla_hw_data *ha = fcport->vha->hw;
+
+       if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha))
+               return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
+
        return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag);
 }
 
@@ -2740,6 +2786,48 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint16_t addr,
 }
 
 int
+qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
+       uint16_t *port_speed, uint16_t *mb)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       if (!IS_IIDMA_CAPABLE(vha->hw))
+               return QLA_FUNCTION_FAILED;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       mcp->mb[0] = MBC_PORT_PARAMS;
+       mcp->mb[1] = loop_id;
+       mcp->mb[2] = mcp->mb[3] = 0;
+       mcp->mb[9] = vha->vp_idx;
+       mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_3|MBX_1|MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       /* Return mailbox statuses. */
+       if (mb != NULL) {
+               mb[0] = mcp->mb[0];
+               mb[1] = mcp->mb[1];
+               mb[3] = mcp->mb[3];
+       }
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+                   vha->host_no, rval));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               if (port_speed)
+                       *port_speed = mcp->mb[3];
+       }
+
+       return rval;
+}
+
+int
 qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
     uint16_t port_speed, uint16_t *mb)
 {
@@ -2755,7 +2843,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        mcp->mb[2] = BIT_0;
-       if (IS_QLA81XX(vha->hw))
+       if (IS_QLA8XXX_TYPE(vha->hw))
                mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0);
        else
                mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
@@ -3544,7 +3632,7 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       if (!IS_QLA81XX(vha->hw))
+       if (!IS_QLA8XXX_TYPE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
@@ -3582,7 +3670,7 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       if (!IS_QLA81XX(vha->hw))
+       if (!IS_QLA8XXX_TYPE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
@@ -3643,7 +3731,8 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
 }
 
 int
-qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp)
+qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
+       uint16_t *mresp)
 {
        int rval;
        mbx_cmd_t mc;
@@ -3678,7 +3767,7 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *
 
        mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|
            MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
-       if (IS_QLA81XX(vha->hw))
+       if (IS_QLA8XXX_TYPE(vha->hw))
                mcp->out_mb |= MBX_2;
        mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0;
 
@@ -3690,9 +3779,11 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *
 
        if (rval != QLA_SUCCESS) {
                DEBUG2(printk(KERN_WARNING
-                   "(%ld): failed=%x mb[0]=0x%x "
-                       "mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x mb[19]=0x%x. \n", vha->host_no, rval,
-                       mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[18], mcp->mb[19]));
+                       "(%ld): failed=%x mb[0]=0x%x "
+                       "mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x "
+                       "mb[19]=0x%x.\n",
+                       vha->host_no, rval, mcp->mb[0], mcp->mb[1], mcp->mb[2],
+                       mcp->mb[3], mcp->mb[18], mcp->mb[19]));
        } else {
                DEBUG2(printk(KERN_WARNING
                    "scsi(%ld): done.\n", vha->host_no));
@@ -3706,7 +3797,8 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *
 }
 
 int
-qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mresp)
+qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
+       uint16_t *mresp)
 {
        int rval;
        mbx_cmd_t mc;
@@ -3718,9 +3810,10 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mres
        memset(mcp->mb, 0 , sizeof(mcp->mb));
        mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;
        mcp->mb[1] = mreq->options | BIT_6;     /* BIT_6 specifies 64bit address */
-       if (IS_QLA81XX(ha))
+       if (IS_QLA8XXX_TYPE(ha)) {
                mcp->mb[1] |= BIT_15;
-       mcp->mb[2] = IS_QLA81XX(ha) ? vha->fcoe_fcf_idx : 0;
+               mcp->mb[2] = vha->fcoe_fcf_idx;
+       }
        mcp->mb[16] = LSW(mreq->rcv_dma);
        mcp->mb[17] = MSW(mreq->rcv_dma);
        mcp->mb[6] = LSW(MSD(mreq->rcv_dma));
@@ -3735,13 +3828,13 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mres
 
        mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15|
            MBX_14|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
-       if (IS_QLA81XX(ha))
+       if (IS_QLA8XXX_TYPE(ha))
                mcp->out_mb |= MBX_2;
 
        mcp->in_mb = MBX_0;
-       if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha))
+       if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))
                mcp->in_mb |= MBX_1;
-       if (IS_QLA81XX(ha))
+       if (IS_QLA8XXX_TYPE(ha))
                mcp->in_mb |= MBX_3;
 
        mcp->tov = MBX_TOV_SECONDS;
@@ -3764,8 +3857,7 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, uint16_t *mres
        return rval;
 }
 int
-qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic,
-    uint16_t *cmd_status)
+qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic)
 {
        int rval;
        mbx_cmd_t mc;
@@ -3782,8 +3874,6 @@ qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic,
        mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
        rval = qla2x00_mailbox_command(ha, mcp);
 
-       /* Return mailbox statuses. */
-       *cmd_status = mcp->mb[0];
        if (rval != QLA_SUCCESS)
                DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no,
                        rval));
@@ -3801,7 +3891,7 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
        mbx_cmd_t *mcp = &mc;
 
        if (!IS_FWI2_CAPABLE(vha->hw))
-                return QLA_FUNCTION_FAILED;
+               return QLA_FUNCTION_FAILED;
 
        DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
 
@@ -3836,7 +3926,8 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, vha->host_no));
+       DEBUG11(qla_printk(KERN_INFO, ha,
+               "%s(%ld): entered.\n", __func__, vha->host_no));
 
        mcp->mb[0] = MBC_DATA_RATE;
        mcp->mb[1] = 0;
@@ -3857,3 +3948,122 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
 
        return rval;
 }
+
+int
+qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
+               uint16_t *mb)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
+               return QLA_FUNCTION_FAILED;
+
+       DEBUG11(printk(KERN_INFO
+           "%s(%ld): entered.\n", __func__, ha->host_no));
+
+       mcp->mb[0] = MBC_PORT_PARAMS;
+       mcp->mb[1] = loop_id;
+       if (ha->flags.fcp_prio_enabled)
+               mcp->mb[2] = BIT_1;
+       else
+               mcp->mb[2] = BIT_2;
+       mcp->mb[4] = priority & 0xf;
+       mcp->mb[9] = vha->vp_idx;
+       mcp->out_mb = MBX_9|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_4|MBX_3|MBX_1|MBX_0;
+       mcp->tov = 30;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+       if (mb != NULL) {
+               mb[0] = mcp->mb[0];
+               mb[1] = mcp->mb[1];
+               mb[3] = mcp->mb[3];
+               mb[4] = mcp->mb[4];
+       }
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk(KERN_WARNING
+                   "%s(%ld): failed=%x.\n", __func__,
+                   vha->host_no, rval));
+       } else {
+               DEBUG11(printk(KERN_INFO
+                   "%s(%ld): done.\n", __func__, vha->host_no));
+       }
+
+       return rval;
+}
+
+int
+qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
+{
+       int rval;
+       struct qla_hw_data *ha = vha->hw;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       if (!IS_FWI2_CAPABLE(ha))
+               return QLA_FUNCTION_FAILED;
+
+       DEBUG11(qla_printk(KERN_INFO, ha,
+               "%s(%ld): entered.\n", __func__, vha->host_no));
+
+       memset(mcp, 0, sizeof(mbx_cmd_t));
+       mcp->mb[0] = MBC_TOGGLE_INTR;
+       mcp->mb[1] = 1;
+
+       mcp->out_mb = MBX_1|MBX_0;
+       mcp->in_mb = MBX_0;
+       mcp->tov = 30;
+       mcp->flags = 0;
+
+       rval = qla2x00_mailbox_command(vha, mcp);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
+                       "%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+                       vha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(qla_printk(KERN_INFO, ha,
+                       "%s(%ld): done.\n", __func__, vha->host_no));
+       }
+
+       return rval;
+}
+
+int
+qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
+{
+       int rval;
+       struct qla_hw_data *ha = vha->hw;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       if (!IS_QLA82XX(ha))
+               return QLA_FUNCTION_FAILED;
+
+       DEBUG11(qla_printk(KERN_INFO, ha,
+               "%s(%ld): entered.\n", __func__, vha->host_no));
+
+       memset(mcp, 0, sizeof(mbx_cmd_t));
+       mcp->mb[0] = MBC_TOGGLE_INTR;
+       mcp->mb[1] = 0;
+
+       mcp->out_mb = MBX_1|MBX_0;
+       mcp->in_mb = MBX_0;
+       mcp->tov = 30;
+       mcp->flags = 0;
+
+       rval = qla2x00_mailbox_command(vha, mcp);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
+                       "%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+                       vha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(qla_printk(KERN_INFO, ha,
+                       "%s(%ld): done.\n", __func__, vha->host_no));
+       }
+
+       return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
new file mode 100644 (file)
index 0000000..ff562de
--- /dev/null
@@ -0,0 +1,3636 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2008 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#define MASK(n)                        ((1ULL<<(n))-1)
+#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \
+       ((addr >> 25) & 0x3ff))
+#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | \
+       ((addr >> 25) & 0x3ff))
+#define MS_WIN(addr) (addr & 0x0ffc0000)
+#define QLA82XX_PCI_MN_2M   (0)
+#define QLA82XX_PCI_MS_2M   (0x80000)
+#define QLA82XX_PCI_OCM0_2M (0xc0000)
+#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
+#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+
+/* CRB window related */
+#define CRB_BLK(off)   ((off >> 20) & 0x3f)
+#define CRB_SUBBLK(off)        ((off >> 16) & 0xf)
+#define CRB_WINDOW_2M  (0x130060)
+#define QLA82XX_PCI_CAMQM_2M_END       (0x04800800UL)
+#define CRB_HI(off)    ((qla82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \
+                       ((off) & 0xf0000))
+#define QLA82XX_PCI_CAMQM_2M_BASE      (0x000ff800UL)
+#define CRB_INDIRECT_2M        (0x1e0000UL)
+
+#define MAX_CRB_XFORM 60
+static unsigned long crb_addr_xform[MAX_CRB_XFORM];
+int qla82xx_crb_table_initialized;
+
+#define qla82xx_crb_addr_transform(name) \
+       (crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \
+       QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20)
+
+static void qla82xx_crb_addr_transform_setup(void)
+{
+       qla82xx_crb_addr_transform(XDMA);
+       qla82xx_crb_addr_transform(TIMR);
+       qla82xx_crb_addr_transform(SRE);
+       qla82xx_crb_addr_transform(SQN3);
+       qla82xx_crb_addr_transform(SQN2);
+       qla82xx_crb_addr_transform(SQN1);
+       qla82xx_crb_addr_transform(SQN0);
+       qla82xx_crb_addr_transform(SQS3);
+       qla82xx_crb_addr_transform(SQS2);
+       qla82xx_crb_addr_transform(SQS1);
+       qla82xx_crb_addr_transform(SQS0);
+       qla82xx_crb_addr_transform(RPMX7);
+       qla82xx_crb_addr_transform(RPMX6);
+       qla82xx_crb_addr_transform(RPMX5);
+       qla82xx_crb_addr_transform(RPMX4);
+       qla82xx_crb_addr_transform(RPMX3);
+       qla82xx_crb_addr_transform(RPMX2);
+       qla82xx_crb_addr_transform(RPMX1);
+       qla82xx_crb_addr_transform(RPMX0);
+       qla82xx_crb_addr_transform(ROMUSB);
+       qla82xx_crb_addr_transform(SN);
+       qla82xx_crb_addr_transform(QMN);
+       qla82xx_crb_addr_transform(QMS);
+       qla82xx_crb_addr_transform(PGNI);
+       qla82xx_crb_addr_transform(PGND);
+       qla82xx_crb_addr_transform(PGN3);
+       qla82xx_crb_addr_transform(PGN2);
+       qla82xx_crb_addr_transform(PGN1);
+       qla82xx_crb_addr_transform(PGN0);
+       qla82xx_crb_addr_transform(PGSI);
+       qla82xx_crb_addr_transform(PGSD);
+       qla82xx_crb_addr_transform(PGS3);
+       qla82xx_crb_addr_transform(PGS2);
+       qla82xx_crb_addr_transform(PGS1);
+       qla82xx_crb_addr_transform(PGS0);
+       qla82xx_crb_addr_transform(PS);
+       qla82xx_crb_addr_transform(PH);
+       qla82xx_crb_addr_transform(NIU);
+       qla82xx_crb_addr_transform(I2Q);
+       qla82xx_crb_addr_transform(EG);
+       qla82xx_crb_addr_transform(MN);
+       qla82xx_crb_addr_transform(MS);
+       qla82xx_crb_addr_transform(CAS2);
+       qla82xx_crb_addr_transform(CAS1);
+       qla82xx_crb_addr_transform(CAS0);
+       qla82xx_crb_addr_transform(CAM);
+       qla82xx_crb_addr_transform(C2C1);
+       qla82xx_crb_addr_transform(C2C0);
+       qla82xx_crb_addr_transform(SMB);
+       qla82xx_crb_addr_transform(OCM0);
+       /*
+        * Used only in P3 just define it for P2 also.
+        */
+       qla82xx_crb_addr_transform(I2C0);
+
+       qla82xx_crb_table_initialized = 1;
+}
+
+struct crb_128M_2M_block_map crb_128M_2M_map[64] = {
+       {{{0, 0,         0,         0} } },
+       {{{1, 0x0100000, 0x0102000, 0x120000},
+       {1, 0x0110000, 0x0120000, 0x130000},
+       {1, 0x0120000, 0x0122000, 0x124000},
+       {1, 0x0130000, 0x0132000, 0x126000},
+       {1, 0x0140000, 0x0142000, 0x128000},
+       {1, 0x0150000, 0x0152000, 0x12a000},
+       {1, 0x0160000, 0x0170000, 0x110000},
+       {1, 0x0170000, 0x0172000, 0x12e000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {1, 0x01e0000, 0x01e0800, 0x122000},
+       {0, 0x0000000, 0x0000000, 0x000000} } } ,
+       {{{1, 0x0200000, 0x0210000, 0x180000} } },
+       {{{0, 0,         0,         0} } },
+       {{{1, 0x0400000, 0x0401000, 0x169000} } },
+       {{{1, 0x0500000, 0x0510000, 0x140000} } },
+       {{{1, 0x0600000, 0x0610000, 0x1c0000} } },
+       {{{1, 0x0700000, 0x0704000, 0x1b8000} } },
+       {{{1, 0x0800000, 0x0802000, 0x170000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {1, 0x08f0000, 0x08f2000, 0x172000} } },
+       {{{1, 0x0900000, 0x0902000, 0x174000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {1, 0x09f0000, 0x09f2000, 0x176000} } },
+       {{{0, 0x0a00000, 0x0a02000, 0x178000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {1, 0x0af0000, 0x0af2000, 0x17a000} } },
+       {{{0, 0x0b00000, 0x0b02000, 0x17c000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
+       {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },
+       {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },
+       {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },
+       {{{1, 0x0f00000, 0x0f01000, 0x164000} } },
+       {{{0, 0x1000000, 0x1004000, 0x1a8000} } },
+       {{{1, 0x1100000, 0x1101000, 0x160000} } },
+       {{{1, 0x1200000, 0x1201000, 0x161000} } },
+       {{{1, 0x1300000, 0x1301000, 0x162000} } },
+       {{{1, 0x1400000, 0x1401000, 0x163000} } },
+       {{{1, 0x1500000, 0x1501000, 0x165000} } },
+       {{{1, 0x1600000, 0x1601000, 0x166000} } },
+       {{{0, 0,         0,         0} } },
+       {{{0, 0,         0,         0} } },
+       {{{0, 0,         0,         0} } },
+       {{{0, 0,         0,         0} } },
+       {{{0, 0,         0,         0} } },
+       {{{0, 0,         0,         0} } },
+       {{{1, 0x1d00000, 0x1d10000, 0x190000} } },
+       {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },
+       {{{1, 0x1f00000, 0x1f10000, 0x150000} } },
+       {{{0} } },
+       {{{1, 0x2100000, 0x2102000, 0x120000},
+       {1, 0x2110000, 0x2120000, 0x130000},
+       {1, 0x2120000, 0x2122000, 0x124000},
+       {1, 0x2130000, 0x2132000, 0x126000},
+       {1, 0x2140000, 0x2142000, 0x128000},
+       {1, 0x2150000, 0x2152000, 0x12a000},
+       {1, 0x2160000, 0x2170000, 0x110000},
+       {1, 0x2170000, 0x2172000, 0x12e000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000},
+       {0, 0x0000000, 0x0000000, 0x000000} } },
+       {{{1, 0x2200000, 0x2204000, 0x1b0000} } },
+       {{{0} } },
+       {{{0} } },
+       {{{0} } },
+       {{{0} } },
+       {{{0} } },
+       {{{1, 0x2800000, 0x2804000, 0x1a4000} } },
+       {{{1, 0x2900000, 0x2901000, 0x16b000} } },
+       {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },
+       {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },
+       {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },
+       {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },
+       {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },
+       {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },
+       {{{1, 0x3000000, 0x3000400, 0x1adc00} } },
+       {{{0, 0x3100000, 0x3104000, 0x1a8000} } },
+       {{{1, 0x3200000, 0x3204000, 0x1d4000} } },
+       {{{1, 0x3300000, 0x3304000, 0x1a0000} } },
+       {{{0} } },
+       {{{1, 0x3500000, 0x3500400, 0x1ac000} } },
+       {{{1, 0x3600000, 0x3600400, 0x1ae000} } },
+       {{{1, 0x3700000, 0x3700400, 0x1ae400} } },
+       {{{1, 0x3800000, 0x3804000, 0x1d0000} } },
+       {{{1, 0x3900000, 0x3904000, 0x1b4000} } },
+       {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },
+       {{{0} } },
+       {{{0} } },
+       {{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },
+       {{{1, 0x3e00000, 0x3e01000, 0x167000} } },
+       {{{1, 0x3f00000, 0x3f01000, 0x168000} } }
+};
+
+/*
+ * top 12 bits of crb internal address (hub, agent)
+ */
+unsigned qla82xx_crb_hub_agt[64] = {
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_MN,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_MS,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_SRE,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_NIU,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_QMN,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGND,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_SN,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_EG,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_CAM,
+       0,
+       0,
+       0,
+       0,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_SMB,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1,
+       0,
+       QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC,
+       0,
+};
+
+/* Device states */
+char *qdev_state[] = {
+        "Unknown",
+       "Cold",
+       "Initializing",
+       "Ready",
+       "Need Reset",
+       "Need Quiescent",
+       "Failed",
+       "Quiescent",
+};
+
+/*
+ * In: 'off' is offset from CRB space in 128M pci map
+ * Out: 'off' is 2M pci map addr
+ * side effect: lock crb window
+ */
+static void
+qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off)
+{
+       u32 win_read;
+
+       ha->crb_win = CRB_HI(*off);
+       writel(ha->crb_win,
+               (void *)(CRB_WINDOW_2M + ha->nx_pcibase));
+
+       /* Read back value to make sure write has gone through before trying
+        * to use it.
+        */
+       win_read = RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase));
+       if (win_read != ha->crb_win) {
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "%s: Written crbwin (0x%x) != Read crbwin (0x%x), "
+                   "off=0x%lx\n", __func__, ha->crb_win, win_read, *off));
+       }
+       *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
+}
+
+static inline unsigned long
+qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off)
+{
+       /* See if we are currently pointing to the region we want to use next */
+       if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_DDR_NET)) {
+               /* No need to change window. PCIX and PCIEregs are in both
+                * regs are in both windows.
+                */
+               return off;
+       }
+
+       if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_PCIX_HOST2)) {
+               /* We are in first CRB window */
+               if (ha->curr_window != 0)
+                       WARN_ON(1);
+               return off;
+       }
+
+       if ((off > QLA82XX_CRB_PCIX_HOST2) && (off < QLA82XX_CRB_MAX)) {
+               /* We are in second CRB window */
+               off = off - QLA82XX_CRB_PCIX_HOST2 + QLA82XX_CRB_PCIX_HOST;
+
+               if (ha->curr_window != 1)
+                       return off;
+
+               /* We are in the QM or direct access
+                * register region - do nothing
+                */
+               if ((off >= QLA82XX_PCI_DIRECT_CRB) &&
+                       (off < QLA82XX_PCI_CAMQM_MAX))
+                       return off;
+       }
+       /* strange address given */
+       qla_printk(KERN_WARNING, ha,
+               "%s: Warning: unm_nic_pci_set_crbwindow called with"
+               " an unknown address(%llx)\n", QLA2XXX_DRIVER_NAME, off);
+       return off;
+}
+
+int
+qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data)
+{
+       unsigned long flags = 0;
+       int rv;
+
+       rv = qla82xx_pci_get_crb_addr_2M(ha, &off);
+
+       BUG_ON(rv == -1);
+
+       if (rv == 1) {
+               write_lock_irqsave(&ha->hw_lock, flags);
+               qla82xx_crb_win_lock(ha);
+               qla82xx_pci_set_crbwindow_2M(ha, &off);
+       }
+
+       writel(data, (void __iomem *)off);
+
+       if (rv == 1) {
+               qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
+               write_unlock_irqrestore(&ha->hw_lock, flags);
+       }
+       return 0;
+}
+
+int
+qla82xx_rd_32(struct qla_hw_data *ha, ulong off)
+{
+       unsigned long flags = 0;
+       int rv;
+       u32 data;
+
+       rv = qla82xx_pci_get_crb_addr_2M(ha, &off);
+
+       BUG_ON(rv == -1);
+
+       if (rv == 1) {
+               write_lock_irqsave(&ha->hw_lock, flags);
+               qla82xx_crb_win_lock(ha);
+               qla82xx_pci_set_crbwindow_2M(ha, &off);
+       }
+       data = RD_REG_DWORD((void __iomem *)off);
+
+       if (rv == 1) {
+               qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
+               write_unlock_irqrestore(&ha->hw_lock, flags);
+       }
+       return data;
+}
+
+#define CRB_WIN_LOCK_TIMEOUT 100000000
+int qla82xx_crb_win_lock(struct qla_hw_data *ha)
+{
+       int done = 0, timeout = 0;
+
+       while (!done) {
+               /* acquire semaphore3 from PCI HW block */
+               done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
+               if (done == 1)
+                       break;
+               if (timeout >= CRB_WIN_LOCK_TIMEOUT)
+                       return -1;
+               timeout++;
+       }
+       qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum);
+       return 0;
+}
+
+#define IDC_LOCK_TIMEOUT 100000000
+int qla82xx_idc_lock(struct qla_hw_data *ha)
+{
+       int i;
+       int done = 0, timeout = 0;
+
+       while (!done) {
+               /* acquire semaphore5 from PCI HW block */
+               done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK));
+               if (done == 1)
+                       break;
+               if (timeout >= IDC_LOCK_TIMEOUT)
+                       return -1;
+
+               timeout++;
+
+               /* Yield CPU */
+               if (!in_interrupt())
+                       schedule();
+               else {
+                       for (i = 0; i < 20; i++)
+                               cpu_relax();
+               }
+       }
+
+       return 0;
+}
+
+void qla82xx_idc_unlock(struct qla_hw_data *ha)
+{
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK));
+}
+
+int
+qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off)
+{
+       struct crb_128M_2M_sub_block_map *m;
+
+       if (*off >= QLA82XX_CRB_MAX)
+               return -1;
+
+       if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) {
+               *off = (*off - QLA82XX_PCI_CAMQM) +
+                   QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
+               return 0;
+       }
+
+       if (*off < QLA82XX_PCI_CRBSPACE)
+               return -1;
+
+       *off -= QLA82XX_PCI_CRBSPACE;
+
+       /* Try direct map */
+       m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)];
+
+       if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) {
+               *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase;
+               return 0;
+       }
+       /* Not in direct map, use crb window */
+       return 1;
+}
+
+/*  PCI Windowing for DDR regions.  */
+#define QLA82XX_ADDR_IN_RANGE(addr, low, high) \
+       (((addr) <= (high)) && ((addr) >= (low)))
+/*
+ * check memory access boundary.
+ * used by test agent. support ddr access only for now
+ */
+static unsigned long
+qla82xx_pci_mem_bound_check(struct qla_hw_data *ha,
+       unsigned long long addr, int size)
+{
+       if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+               QLA82XX_ADDR_DDR_NET_MAX) ||
+               !QLA82XX_ADDR_IN_RANGE(addr + size - 1, QLA82XX_ADDR_DDR_NET,
+               QLA82XX_ADDR_DDR_NET_MAX) ||
+               ((size != 1) && (size != 2) && (size != 4) && (size != 8)))
+                       return 0;
+       else
+               return 1;
+}
+
+int qla82xx_pci_set_window_warning_count;
+
+unsigned long
+qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
+{
+       int window;
+       u32 win_read;
+
+       if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+               QLA82XX_ADDR_DDR_NET_MAX)) {
+               /* DDR network side */
+               window = MN_WIN(addr);
+               ha->ddr_mn_window = window;
+               qla82xx_wr_32(ha,
+                       ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window);
+               win_read = qla82xx_rd_32(ha,
+                       ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
+               if ((win_read << 17) != window) {
+                       qla_printk(KERN_WARNING, ha,
+                           "%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n",
+                           __func__, window, win_read);
+               }
+               addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
+       } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0,
+               QLA82XX_ADDR_OCM0_MAX)) {
+               unsigned int temp1;
+               if ((addr & 0x00ff800) == 0xff800) {
+                       qla_printk(KERN_WARNING, ha,
+                           "%s: QM access not handled.\n", __func__);
+                       addr = -1UL;
+               }
+               window = OCM_WIN(addr);
+               ha->ddr_mn_window = window;
+               qla82xx_wr_32(ha,
+                       ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window);
+               win_read = qla82xx_rd_32(ha,
+                       ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
+               temp1 = ((window & 0x1FF) << 7) |
+                   ((window & 0x0FFFE0000) >> 17);
+               if (win_read != temp1) {
+                       qla_printk(KERN_WARNING, ha,
+                           "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x)\n",
+                           __func__, temp1, win_read);
+               }
+               addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;
+
+       } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET,
+               QLA82XX_P3_ADDR_QDR_NET_MAX)) {
+               /* QDR network side */
+               window = MS_WIN(addr);
+               ha->qdr_sn_window = window;
+               qla82xx_wr_32(ha,
+                       ha->ms_win_crb | QLA82XX_PCI_CRBSPACE, window);
+               win_read = qla82xx_rd_32(ha,
+                       ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
+               if (win_read != window) {
+                       qla_printk(KERN_WARNING, ha,
+                           "%s: Written MSwin (0x%x) != Read MSwin (0x%x)\n",
+                           __func__, window, win_read);
+               }
+               addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
+       } else {
+               /*
+                * peg gdb frequently accesses memory that doesn't exist,
+                * this limits the chit chat so debugging isn't slowed down.
+                */
+               if ((qla82xx_pci_set_window_warning_count++ < 8) ||
+                   (qla82xx_pci_set_window_warning_count%64 == 0)) {
+                       qla_printk(KERN_WARNING, ha,
+                           "%s: Warning:%s Unknown address range!\n", __func__,
+                           QLA2XXX_DRIVER_NAME);
+               }
+               addr = -1UL;
+       }
+       return addr;
+}
+
+/* check if address is in the same windows as the previous access */
+static int qla82xx_pci_is_same_window(struct qla_hw_data *ha,
+       unsigned long long addr)
+{
+       int                     window;
+       unsigned long long      qdr_max;
+
+       qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX;
+
+       /* DDR network side */
+       if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
+               QLA82XX_ADDR_DDR_NET_MAX))
+               BUG();
+       else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0,
+               QLA82XX_ADDR_OCM0_MAX))
+               return 1;
+       else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1,
+               QLA82XX_ADDR_OCM1_MAX))
+               return 1;
+       else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, qdr_max)) {
+               /* QDR network side */
+               window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f;
+               if (ha->qdr_sn_window == window)
+                       return 1;
+       }
+       return 0;
+}
+
+static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha,
+       u64 off, void *data, int size)
+{
+       unsigned long   flags;
+       void           *addr = NULL;
+       int             ret = 0;
+       u64             start;
+       uint8_t         *mem_ptr = NULL;
+       unsigned long   mem_base;
+       unsigned long   mem_page;
+
+       write_lock_irqsave(&ha->hw_lock, flags);
+
+       /*
+        * If attempting to access unknown address or straddle hw windows,
+        * do not access.
+        */
+       start = qla82xx_pci_set_window(ha, off);
+       if ((start == -1UL) ||
+               (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
+               write_unlock_irqrestore(&ha->hw_lock, flags);
+               qla_printk(KERN_ERR, ha,
+                       "%s out of bound pci memory access. "
+                       "offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off);
+               return -1;
+       }
+
+       write_unlock_irqrestore(&ha->hw_lock, flags);
+       mem_base = pci_resource_start(ha->pdev, 0);
+       mem_page = start & PAGE_MASK;
+       /* Map two pages whenever user tries to access addresses in two
+       * consecutive pages.
+       */
+       if (mem_page != ((start + size - 1) & PAGE_MASK))
+               mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
+       else
+               mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
+       if (mem_ptr == 0UL) {
+               *(u8  *)data = 0;
+               return -1;
+       }
+       addr = mem_ptr;
+       addr += start & (PAGE_SIZE - 1);
+       write_lock_irqsave(&ha->hw_lock, flags);
+
+       switch (size) {
+       case 1:
+               *(u8  *)data = readb(addr);
+               break;
+       case 2:
+               *(u16 *)data = readw(addr);
+               break;
+       case 4:
+               *(u32 *)data = readl(addr);
+               break;
+       case 8:
+               *(u64 *)data = readq(addr);
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+       write_unlock_irqrestore(&ha->hw_lock, flags);
+
+       if (mem_ptr)
+               iounmap(mem_ptr);
+       return ret;
+}
+
+static int
+qla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
+       u64 off, void *data, int size)
+{
+       unsigned long   flags;
+       void           *addr = NULL;
+       int             ret = 0;
+       u64             start;
+       uint8_t         *mem_ptr = NULL;
+       unsigned long   mem_base;
+       unsigned long   mem_page;
+
+       write_lock_irqsave(&ha->hw_lock, flags);
+
+       /*
+        * If attempting to access unknown address or straddle hw windows,
+        * do not access.
+        */
+       start = qla82xx_pci_set_window(ha, off);
+       if ((start == -1UL) ||
+               (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
+               write_unlock_irqrestore(&ha->hw_lock, flags);
+               qla_printk(KERN_ERR, ha,
+                       "%s out of bound pci memory access. "
+                       "offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off);
+               return -1;
+       }
+
+       write_unlock_irqrestore(&ha->hw_lock, flags);
+       mem_base = pci_resource_start(ha->pdev, 0);
+       mem_page = start & PAGE_MASK;
+       /* Map two pages whenever user tries to access addresses in two
+        * consecutive pages.
+        */
+       if (mem_page != ((start + size - 1) & PAGE_MASK))
+               mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2);
+       else
+               mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
+       if (mem_ptr == 0UL)
+               return -1;
+
+       addr = mem_ptr;
+       addr += start & (PAGE_SIZE - 1);
+       write_lock_irqsave(&ha->hw_lock, flags);
+
+       switch (size) {
+       case 1:
+               writeb(*(u8  *)data, addr);
+               break;
+       case 2:
+               writew(*(u16 *)data, addr);
+               break;
+       case 4:
+               writel(*(u32 *)data, addr);
+               break;
+       case 8:
+               writeq(*(u64 *)data, addr);
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+       write_unlock_irqrestore(&ha->hw_lock, flags);
+       if (mem_ptr)
+               iounmap(mem_ptr);
+       return ret;
+}
+
+int
+qla82xx_wrmem(struct qla_hw_data *ha, u64 off, void *data, int size)
+{
+       int i, j, ret = 0, loop, sz[2], off0;
+       u32 temp;
+       u64 off8, mem_crb, tmpw, word[2] = {0, 0};
+#define MAX_CTL_CHECK   1000
+       /*
+        * If not MN, go check for MS or invalid.
+        */
+       if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) {
+               mem_crb = QLA82XX_CRB_QDR_NET;
+       } else {
+               mem_crb = QLA82XX_CRB_DDR_NET;
+               if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
+                       return qla82xx_pci_mem_write_direct(ha, off,
+                           data, size);
+       }
+
+       off8 = off & 0xfffffff8;
+       off0 = off & 0x7;
+       sz[0] = (size < (8 - off0)) ? size : (8 - off0);
+       sz[1] = size - sz[0];
+       loop = ((off0 + size - 1) >> 3) + 1;
+
+       if ((size != 8) || (off0 != 0))  {
+               for (i = 0; i < loop; i++) {
+                       if (qla82xx_rdmem(ha, off8 + (i << 3), &word[i], 8))
+                               return -1;
+               }
+       }
+
+       switch (size) {
+       case 1:
+               tmpw = *((u8 *)data);
+               break;
+       case 2:
+               tmpw = *((u16 *)data);
+               break;
+       case 4:
+               tmpw = *((u32 *)data);
+               break;
+       case 8:
+       default:
+               tmpw = *((u64 *)data);
+               break;
+       }
+
+       word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+       word[0] |= tmpw << (off0 * 8);
+
+       if (loop == 2) {
+               word[1] &= ~(~0ULL << (sz[1] * 8));
+               word[1] |= tmpw >> (sz[0] * 8);
+       }
+
+       for (i = 0; i < loop; i++) {
+               temp = off8 + (i << 3);
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
+               temp = 0;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
+               temp = word[i] & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
+               temp = (word[i] >> 32) & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
+               temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
+               temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
+
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+                       if ((temp & MIU_TA_CTL_BUSY) == 0)
+                               break;
+               }
+
+               if (j >= MAX_CTL_CHECK) {
+                       qla_printk(KERN_WARNING, ha,
+                               "%s: Fail to write through agent\n",
+                               QLA2XXX_DRIVER_NAME);
+                       ret = -1;
+                       break;
+               }
+       }
+       return ret;
+}
+
+int
+qla82xx_rdmem(struct qla_hw_data *ha, u64 off, void *data, int size)
+{
+       int i, j = 0, k, start, end, loop, sz[2], off0[2];
+       u32 temp;
+       u64 off8, val, mem_crb, word[2] = {0, 0};
+#define MAX_CTL_CHECK   1000
+
+       /*
+        * If not MN, go check for MS or invalid.
+        */
+       if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+               mem_crb = QLA82XX_CRB_QDR_NET;
+       else {
+               mem_crb = QLA82XX_CRB_DDR_NET;
+               if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
+                       return qla82xx_pci_mem_read_direct(ha, off,
+                               data, size);
+       }
+
+       off8 = off & 0xfffffff8;
+       off0[0] = off & 0x7;
+       off0[1] = 0;
+       sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
+       sz[1] = size - sz[0];
+       loop = ((off0[0] + size - 1) >> 3) + 1;
+
+       for (i = 0; i < loop; i++) {
+               temp = off8 + (i << 3);
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
+               temp = 0;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
+               temp = MIU_TA_CTL_ENABLE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+               temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+                       if ((temp & MIU_TA_CTL_BUSY) == 0)
+                               break;
+               }
+
+               if (j >= MAX_CTL_CHECK) {
+                       qla_printk(KERN_INFO, ha,
+                               "%s: Fail to read through agent\n",
+                               QLA2XXX_DRIVER_NAME);
+                       break;
+               }
+
+               start = off0[i] >> 2;
+               end   = (off0[i] + sz[i] - 1) >> 2;
+               for (k = start; k <= end; k++) {
+                       temp = qla82xx_rd_32(ha,
+                           mem_crb + MIU_TEST_AGT_RDDATA(k));
+                       word[i] |= ((u64)temp << (32 * k));
+               }
+       }
+
+       if (j >= MAX_CTL_CHECK)
+               return -1;
+
+       if (sz[0] == 8) {
+               val = word[0];
+       } else {
+               val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
+                       ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
+       }
+
+       switch (size) {
+       case 1:
+               *(u8  *)data = val;
+               break;
+       case 2:
+               *(u16 *)data = val;
+               break;
+       case 4:
+               *(u32 *)data = val;
+               break;
+       case 8:
+               *(u64 *)data = val;
+               break;
+       }
+       return 0;
+}
+
+#define MTU_FUDGE_FACTOR 100
+unsigned long qla82xx_decode_crb_addr(unsigned long addr)
+{
+       int i;
+       unsigned long base_addr, offset, pci_base;
+
+       if (!qla82xx_crb_table_initialized)
+               qla82xx_crb_addr_transform_setup();
+
+       pci_base = ADDR_ERROR;
+       base_addr = addr & 0xfff00000;
+       offset = addr & 0x000fffff;
+
+       for (i = 0; i < MAX_CRB_XFORM; i++) {
+               if (crb_addr_xform[i] == base_addr) {
+                       pci_base = i << 20;
+                       break;
+               }
+       }
+       if (pci_base == ADDR_ERROR)
+               return pci_base;
+       return pci_base + offset;
+}
+
+static long rom_max_timeout = 100;
+static long qla82xx_rom_lock_timeout = 100;
+
+int
+qla82xx_rom_lock(struct qla_hw_data *ha)
+{
+       int done = 0, timeout = 0;
+
+       while (!done) {
+               /* acquire semaphore2 from PCI HW block */
+               done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
+               if (done == 1)
+                       break;
+               if (timeout >= qla82xx_rom_lock_timeout)
+                       return -1;
+               timeout++;
+       }
+       qla82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER);
+       return 0;
+}
+
+int
+qla82xx_wait_rom_busy(struct qla_hw_data *ha)
+{
+       long timeout = 0;
+       long done = 0 ;
+
+       while (done == 0) {
+               done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
+               done &= 4;
+               timeout++;
+               if (timeout >= rom_max_timeout) {
+                       DEBUG(qla_printk(KERN_INFO, ha,
+                               "%s: Timeout reached waiting for rom busy",
+                               QLA2XXX_DRIVER_NAME));
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+int
+qla82xx_wait_rom_done(struct qla_hw_data *ha)
+{
+       long timeout = 0;
+       long done = 0 ;
+
+       while (done == 0) {
+               done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
+               done &= 2;
+               timeout++;
+               if (timeout >= rom_max_timeout) {
+                       DEBUG(qla_printk(KERN_INFO, ha,
+                               "%s: Timeout reached  waiting for rom done",
+                               QLA2XXX_DRIVER_NAME));
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+int
+qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
+{
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb);
+       qla82xx_wait_rom_busy(ha);
+       if (qla82xx_wait_rom_done(ha)) {
+               qla_printk(KERN_WARNING, ha,
+                       "%s: Error waiting for rom done\n",
+                       QLA2XXX_DRIVER_NAME);
+               return -1;
+       }
+       /* Reset abyte_cnt and dummy_byte_cnt */
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+       udelay(10);
+       cond_resched();
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
+       *valp = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
+       return 0;
+}
+
+int
+qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
+{
+       int ret, loops = 0;
+
+       while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
+               udelay(100);
+               schedule();
+               loops++;
+       }
+       if (loops >= 50000) {
+               qla_printk(KERN_INFO, ha,
+                       "%s: qla82xx_rom_lock failed\n",
+                       QLA2XXX_DRIVER_NAME);
+               return -1;
+       }
+       ret = qla82xx_do_rom_fast_read(ha, addr, valp);
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+       return ret;
+}
+
+int
+qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val)
+{
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR);
+       qla82xx_wait_rom_busy(ha);
+       if (qla82xx_wait_rom_done(ha)) {
+               qla_printk(KERN_WARNING, ha,
+                   "Error waiting for rom done\n");
+               return -1;
+       }
+       *val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
+       return 0;
+}
+
+int
+qla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
+{
+       long timeout = 0;
+       uint32_t done = 1 ;
+       uint32_t val;
+       int ret = 0;
+
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
+       while ((done != 0) && (ret == 0)) {
+               ret = qla82xx_read_status_reg(ha, &val);
+               done = val & 1;
+               timeout++;
+               udelay(10);
+               cond_resched();
+               if (timeout >= 50000) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Timeout reached  waiting for write finish");
+                       return -1;
+               }
+       }
+       return ret;
+}
+
+int
+qla82xx_flash_set_write_enable(struct qla_hw_data *ha)
+{
+       uint32_t val;
+       qla82xx_wait_rom_busy(ha);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WREN);
+       qla82xx_wait_rom_busy(ha);
+       if (qla82xx_wait_rom_done(ha))
+               return -1;
+       if (qla82xx_read_status_reg(ha, &val) != 0)
+               return -1;
+       if ((val & 2) != 2)
+               return -1;
+       return 0;
+}
+
+int
+qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
+{
+       if (qla82xx_flash_set_write_enable(ha))
+               return -1;
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0x1);
+       if (qla82xx_wait_rom_done(ha)) {
+               qla_printk(KERN_WARNING, ha,
+                   "Error waiting for rom done\n");
+               return -1;
+       }
+       return qla82xx_flash_wait_write_finish(ha);
+}
+
+int
+qla82xx_write_disable_flash(struct qla_hw_data *ha)
+{
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI);
+       if (qla82xx_wait_rom_done(ha)) {
+               qla_printk(KERN_WARNING, ha,
+                   "Error waiting for rom done\n");
+               return -1;
+       }
+       return 0;
+}
+
+int
+ql82xx_rom_lock_d(struct qla_hw_data *ha)
+{
+       int loops = 0;
+       while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
+               udelay(100);
+               cond_resched();
+               loops++;
+       }
+       if (loops >= 50000) {
+               qla_printk(KERN_WARNING, ha, "ROM lock failed\n");
+               return -1;
+       }
+       return 0;;
+}
+
+int
+qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
+       uint32_t data)
+{
+       int ret = 0;
+
+       ret = ql82xx_rom_lock_d(ha);
+       if (ret < 0) {
+               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               return ret;
+       }
+
+       if (qla82xx_flash_set_write_enable(ha))
+               goto done_write;
+
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, data);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, flashaddr);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_PP);
+       qla82xx_wait_rom_busy(ha);
+       if (qla82xx_wait_rom_done(ha)) {
+               qla_printk(KERN_WARNING, ha,
+                       "Error waiting for rom done\n");
+               ret = -1;
+               goto done_write;
+       }
+
+       ret = qla82xx_flash_wait_write_finish(ha);
+
+done_write:
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+       return ret;
+}
+
+/* This routine does CRB initialize sequence
+ *  to put the ISP into operational state
+ */
+int qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
+{
+       int addr, val;
+       int i ;
+       struct crb_addr_pair *buf;
+       unsigned long off;
+       unsigned offset, n;
+       struct qla_hw_data *ha = vha->hw;
+
+       struct crb_addr_pair {
+               long addr;
+               long data;
+       };
+
+       /* Halt all the indiviual PEGs and other blocks of the ISP */
+       qla82xx_rom_lock(ha);
+       if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
+               /* don't reset CAM block on reset */
+               qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
+       else
+               qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+
+       /* Read the signature value from the flash.
+        * Offset 0: Contain signature (0xcafecafe)
+        * Offset 4: Offset and number of addr/value pairs
+        * that present in CRB initialize sequence
+        */
+       if (qla82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
+           qla82xx_rom_fast_read(ha, 4, &n) != 0) {
+               qla_printk(KERN_WARNING, ha,
+                   "[ERROR] Reading crb_init area: n: %08x\n", n);
+               return -1;
+       }
+
+       /* Offset in flash = lower 16 bits
+        * Number of enteries = upper 16 bits
+        */
+       offset = n & 0xffffU;
+       n = (n >> 16) & 0xffffU;
+
+       /* number of addr/value pair should not exceed 1024 enteries */
+       if (n  >= 1024) {
+               qla_printk(KERN_WARNING, ha,
+                   "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n",
+                   QLA2XXX_DRIVER_NAME, __func__, n);
+               return -1;
+       }
+
+       qla_printk(KERN_INFO, ha,
+           "%s: %d CRB init values found in ROM.\n", QLA2XXX_DRIVER_NAME, n);
+
+       buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL);
+       if (buf == NULL) {
+               qla_printk(KERN_WARNING, ha,
+                   "%s: [ERROR] Unable to malloc memory.\n",
+                   QLA2XXX_DRIVER_NAME);
+               return -1;
+       }
+
+       for (i = 0; i < n; i++) {
+               if (qla82xx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 ||
+                   qla82xx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) != 0) {
+                       kfree(buf);
+                       return -1;
+               }
+
+               buf[i].addr = addr;
+               buf[i].data = val;
+       }
+
+       for (i = 0; i < n; i++) {
+               /* Translate internal CRB initialization
+                * address to PCI bus address
+                */
+               off = qla82xx_decode_crb_addr((unsigned long)buf[i].addr) +
+                   QLA82XX_PCI_CRBSPACE;
+               /* Not all CRB  addr/value pair to be written,
+                * some of them are skipped
+                */
+
+               /* skipping cold reboot MAGIC */
+               if (off == QLA82XX_CAM_RAM(0x1fc))
+                       continue;
+
+               /* do not reset PCI */
+               if (off == (ROMUSB_GLB + 0xbc))
+                       continue;
+
+               /* skip core clock, so that firmware can increase the clock */
+               if (off == (ROMUSB_GLB + 0xc8))
+                       continue;
+
+               /* skip the function enable register */
+               if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION))
+                       continue;
+
+               if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2))
+                       continue;
+
+               if ((off & 0x0ff00000) == QLA82XX_CRB_SMB)
+                       continue;
+
+               if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET)
+                       continue;
+
+               if (off == ADDR_ERROR) {
+                       qla_printk(KERN_WARNING, ha,
+                           "%s: [ERROR] Unknown addr: 0x%08lx\n",
+                           QLA2XXX_DRIVER_NAME, buf[i].addr);
+                       continue;
+               }
+
+               if (off == (QLA82XX_CRB_PEG_NET_1 + 0x18)) {
+                       if (!QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision))
+                               buf[i].data = 0x1020;
+               }
+
+               qla82xx_wr_32(ha, off, buf[i].data);
+
+               /* ISP requires much bigger delay to settle down,
+                * else crb_window returns 0xffffffff
+                */
+               if (off == QLA82XX_ROMUSB_GLB_SW_RESET)
+                       msleep(1000);
+
+               /* ISP requires millisec delay between
+                * successive CRB register updation
+                */
+               msleep(1);
+       }
+
+       kfree(buf);
+
+       /* Resetting the data and instruction cache */
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8);
+
+       /* Clear all protocol processing engines */
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0);
+       qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0);
+       return 0;
+}
+
+int qla82xx_check_for_bad_spd(struct qla_hw_data *ha)
+{
+       u32 val = 0;
+       val = qla82xx_rd_32(ha, BOOT_LOADER_DIMM_STATUS);
+       val &= QLA82XX_BOOT_LOADER_MN_ISSUE;
+       if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) {
+               qla_printk(KERN_INFO, ha,
+                       "Memory DIMM SPD not programmed. "
+                       " Assumed valid.\n");
+               return 1;
+       } else if (val) {
+               qla_printk(KERN_INFO, ha,
+                       "Memory DIMM type incorrect.Info:%08X.\n", val);
+               return 2;
+       }
+       return 0;
+}
+
+int
+qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
+{
+       int  i;
+       long size = 0;
+       long flashaddr = BOOTLD_START, memaddr = BOOTLD_START;
+       u64 data;
+       u32 high, low;
+       size = (IMAGE_START - BOOTLD_START) / 8;
+
+       for (i = 0; i < size; i++) {
+               if ((qla82xx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
+                   (qla82xx_rom_fast_read(ha, flashaddr + 4, (int *)&high))) {
+                       return -1;
+               }
+               data = ((u64)high << 32) | low ;
+               qla82xx_pci_mem_write_2M(ha, memaddr, &data, 8);
+               flashaddr += 8;
+               memaddr += 8;
+
+               if (i % 0x1000 == 0)
+                       msleep(1);
+       }
+       udelay(100);
+       read_lock(&ha->hw_lock);
+       if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
+               qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+               qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
+       } else {
+               qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
+       }
+       read_unlock(&ha->hw_lock);
+       return 0;
+}
+
+int
+qla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
+               u64 off, void *data, int size)
+{
+       int i, j = 0, k, start, end, loop, sz[2], off0[2];
+       int           shift_amount;
+       uint32_t      temp;
+       uint64_t      off8, val, mem_crb, word[2] = {0, 0};
+
+       /*
+        * If not MN, go check for MS or invalid.
+        */
+
+       if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+               mem_crb = QLA82XX_CRB_QDR_NET;
+       else {
+               mem_crb = QLA82XX_CRB_DDR_NET;
+               if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
+                       return qla82xx_pci_mem_read_direct(ha,
+                           off, data, size);
+       }
+
+       if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
+               off8 = off & 0xfffffff0;
+               off0[0] = off & 0xf;
+               sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
+               shift_amount = 4;
+       } else {
+               off8 = off & 0xfffffff8;
+               off0[0] = off & 0x7;
+               sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
+               shift_amount = 4;
+       }
+       loop = ((off0[0] + size - 1) >> shift_amount) + 1;
+       off0[1] = 0;
+       sz[1] = size - sz[0];
+
+       /*
+        * don't lock here - write_wx gets the lock if each time
+        * write_lock_irqsave(&adapter->adapter_lock, flags);
+        * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+        */
+
+       for (i = 0; i < loop; i++) {
+               temp = off8 + (i << shift_amount);
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
+               temp = 0;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
+               temp = MIU_TA_CTL_ENABLE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+               temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+                       if ((temp & MIU_TA_CTL_BUSY) == 0)
+                               break;
+               }
+
+               if (j >= MAX_CTL_CHECK) {
+                       if (printk_ratelimit())
+                               dev_err(&ha->pdev->dev,
+                                   "failed to read through agent\n");
+                       break;
+               }
+
+               start = off0[i] >> 2;
+               end   = (off0[i] + sz[i] - 1) >> 2;
+               for (k = start; k <= end; k++) {
+                       temp = qla82xx_rd_32(ha,
+                                       mem_crb + MIU_TEST_AGT_RDDATA(k));
+                       word[i] |= ((uint64_t)temp << (32 * (k & 1)));
+               }
+       }
+
+       /*
+        * netxen_nic_pci_change_crbwindow_128M(adapter, 1);
+        * write_unlock_irqrestore(&adapter->adapter_lock, flags);
+        */
+
+       if (j >= MAX_CTL_CHECK)
+               return -1;
+
+       if ((off0[0] & 7) == 0) {
+               val = word[0];
+       } else {
+               val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
+                       ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
+       }
+
+       switch (size) {
+       case 1:
+               *(uint8_t  *)data = val;
+               break;
+       case 2:
+               *(uint16_t *)data = val;
+               break;
+       case 4:
+               *(uint32_t *)data = val;
+               break;
+       case 8:
+               *(uint64_t *)data = val;
+               break;
+       }
+       return 0;
+}
+
+int
+qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
+               u64 off, void *data, int size)
+{
+       int i, j, ret = 0, loop, sz[2], off0;
+       int scale, shift_amount, p3p, startword;
+       uint32_t temp;
+       uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
+
+       /*
+        * If not MN, go check for MS or invalid.
+        */
+       if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
+               mem_crb = QLA82XX_CRB_QDR_NET;
+       else {
+               mem_crb = QLA82XX_CRB_DDR_NET;
+               if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
+                       return qla82xx_pci_mem_write_direct(ha,
+                           off, data, size);
+       }
+
+       off0 = off & 0x7;
+       sz[0] = (size < (8 - off0)) ? size : (8 - off0);
+       sz[1] = size - sz[0];
+
+       if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
+               off8 = off & 0xfffffff0;
+               loop = (((off & 0xf) + size - 1) >> 4) + 1;
+               shift_amount = 4;
+               scale = 2;
+               p3p = 1;
+               startword = (off & 0xf)/8;
+       } else {
+               off8 = off & 0xfffffff8;
+               loop = ((off0 + size - 1) >> 3) + 1;
+               shift_amount = 3;
+               scale = 1;
+               p3p = 0;
+               startword = 0;
+       }
+
+       if (p3p || (size != 8) || (off0 != 0)) {
+               for (i = 0; i < loop; i++) {
+                       if (qla82xx_pci_mem_read_2M(ha, off8 +
+                           (i << shift_amount), &word[i * scale], 8))
+                               return -1;
+               }
+       }
+
+       switch (size) {
+       case 1:
+               tmpw = *((uint8_t *)data);
+               break;
+       case 2:
+               tmpw = *((uint16_t *)data);
+               break;
+       case 4:
+               tmpw = *((uint32_t *)data);
+               break;
+       case 8:
+       default:
+               tmpw = *((uint64_t *)data);
+               break;
+       }
+
+       if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
+               if (sz[0] == 8) {
+                       word[startword] = tmpw;
+               } else {
+                       word[startword] &=
+                               ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+                       word[startword] |= tmpw << (off0 * 8);
+               }
+               if (sz[1] != 0) {
+                       word[startword+1] &= ~(~0ULL << (sz[1] * 8));
+                       word[startword+1] |= tmpw >> (sz[0] * 8);
+               }
+       } else {
+               word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
+               word[startword] |= tmpw << (off0 * 8);
+
+               if (loop == 2) {
+                       word[1] &= ~(~0ULL << (sz[1] * 8));
+                       word[1] |= tmpw >> (sz[0] * 8);
+               }
+       }
+
+       /*
+        * don't lock here - write_wx gets the lock if each time
+        * write_lock_irqsave(&adapter->adapter_lock, flags);
+        * netxen_nic_pci_change_crbwindow_128M(adapter, 0);
+        */
+       for (i = 0; i < loop; i++) {
+               temp = off8 + (i << shift_amount);
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
+               temp = 0;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
+               temp = word[i * scale] & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
+               temp = (word[i * scale] >> 32) & 0xffffffff;
+               qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
+               if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
+                       temp = word[i*scale + 1] & 0xffffffff;
+                       qla82xx_wr_32(ha, mem_crb +
+                           MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
+                       temp = (word[i*scale + 1] >> 32) & 0xffffffff;
+                       qla82xx_wr_32(ha, mem_crb +
+                           MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
+               }
+
+               temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+               temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
+               qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
+
+               for (j = 0; j < MAX_CTL_CHECK; j++) {
+                       temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
+                       if ((temp & MIU_TA_CTL_BUSY) == 0)
+                               break;
+               }
+
+               if (j >= MAX_CTL_CHECK) {
+                       if (printk_ratelimit())
+                               dev_err(&ha->pdev->dev,
+                                   "failed to write through agent\n");
+                       ret = -1;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+/* PCI related functions */
+char *
+qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str)
+{
+       int pcie_reg;
+       struct qla_hw_data *ha = vha->hw;
+       char lwstr[6];
+       uint16_t lnk;
+
+       pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+       pci_read_config_word(ha->pdev, pcie_reg + PCI_EXP_LNKSTA, &lnk);
+       ha->link_width = (lnk >> 4) & 0x3f;
+
+       strcpy(str, "PCIe (");
+       strcat(str, "2.5Gb/s ");
+       snprintf(lwstr, sizeof(lwstr), "x%d)", ha->link_width);
+       strcat(str, lwstr);
+       return str;
+}
+
+int qla82xx_pci_region_offset(struct pci_dev *pdev, int region)
+{
+       unsigned long val = 0;
+       u32 control;
+
+       switch (region) {
+       case 0:
+               val = 0;
+               break;
+       case 1:
+               pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control);
+               val = control + QLA82XX_MSIX_TBL_SPACE;
+               break;
+       }
+       return val;
+}
+
+int qla82xx_pci_region_len(struct pci_dev *pdev, int region)
+{
+       unsigned long val = 0;
+       u32 control;
+       switch (region) {
+       case 0:
+               pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control);
+               val = control;
+               break;
+       case 1:
+               val = pci_resource_len(pdev, 0) -
+                   qla82xx_pci_region_offset(pdev, 1);
+               break;
+       }
+       return val;
+}
+
+int
+qla82xx_iospace_config(struct qla_hw_data *ha)
+{
+       uint32_t len = 0;
+
+       if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) {
+               qla_printk(KERN_WARNING, ha,
+                       "Failed to reserve selected regions (%s)\n",
+                       pci_name(ha->pdev));
+               goto iospace_error_exit;
+       }
+
+       /* Use MMIO operations for all accesses. */
+       if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
+               qla_printk(KERN_ERR, ha,
+                       "region #0 not an MMIO resource (%s), aborting\n",
+                       pci_name(ha->pdev));
+               goto iospace_error_exit;
+       }
+
+       len = pci_resource_len(ha->pdev, 0);
+       ha->nx_pcibase =
+           (unsigned long)ioremap(pci_resource_start(ha->pdev, 0), len);
+       if (!ha->nx_pcibase) {
+               qla_printk(KERN_ERR, ha,
+                   "cannot remap pcibase MMIO (%s), aborting\n",
+                   pci_name(ha->pdev));
+               pci_release_regions(ha->pdev);
+               goto iospace_error_exit;
+       }
+
+       /* Mapping of IO base pointer */
+       ha->iobase = (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
+           0xbc000 + (ha->pdev->devfn << 11));
+
+       if (!ql2xdbwr) {
+               ha->nxdb_wr_ptr =
+                   (unsigned long)ioremap((pci_resource_start(ha->pdev, 4) +
+                   (ha->pdev->devfn << 12)), 4);
+               if (!ha->nxdb_wr_ptr) {
+                       qla_printk(KERN_ERR, ha,
+                           "cannot remap MMIO (%s), aborting\n",
+                           pci_name(ha->pdev));
+                       pci_release_regions(ha->pdev);
+                       goto iospace_error_exit;
+               }
+
+               /* Mapping of IO base pointer,
+                * door bell read and write pointer
+                */
+               ha->nxdb_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) +
+                   (ha->pdev->devfn * 8);
+       } else {
+               ha->nxdb_wr_ptr = (ha->pdev->devfn == 6 ?
+                       QLA82XX_CAMRAM_DB1 :
+                       QLA82XX_CAMRAM_DB2);
+       }
+
+       ha->max_req_queues = ha->max_rsp_queues = 1;
+       ha->msix_count = ha->max_rsp_queues + 1;
+       return 0;
+
+iospace_error_exit:
+       return -ENOMEM;
+}
+
+/* GS related functions */
+
+/* Initialization related functions */
+
+/**
+ * qla82xx_pci_config() - Setup ISP82xx PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+*/
+int
+qla82xx_pci_config(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       int ret;
+
+       pci_set_master(ha->pdev);
+       ret = pci_set_mwi(ha->pdev);
+       ha->chip_revision = ha->pdev->revision;
+       return 0;
+}
+
+/**
+ * qla82xx_reset_chip() - Setup ISP82xx PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+void
+qla82xx_reset_chip(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       ha->isp_ops->disable_intrs(ha);
+}
+
+void qla82xx_config_rings(struct scsi_qla_host *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
+       struct init_cb_81xx *icb;
+       struct req_que *req = ha->req_q_map[0];
+       struct rsp_que *rsp = ha->rsp_q_map[0];
+
+       /* Setup ring parameters in initialization control block. */
+       icb = (struct init_cb_81xx *)ha->init_cb;
+       icb->request_q_outpointer = __constant_cpu_to_le16(0);
+       icb->response_q_inpointer = __constant_cpu_to_le16(0);
+       icb->request_q_length = cpu_to_le16(req->length);
+       icb->response_q_length = cpu_to_le16(rsp->length);
+       icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
+       icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
+       icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
+       icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
+
+       icb->version = 1;
+       icb->frame_payload_size = 2112;
+       icb->execution_throttle = 8;
+       icb->exchange_count = 128;
+       icb->login_retry_count = 8;
+
+       WRT_REG_DWORD((unsigned long  __iomem *)&reg->req_q_out[0], 0);
+       WRT_REG_DWORD((unsigned long  __iomem *)&reg->rsp_q_in[0], 0);
+       WRT_REG_DWORD((unsigned long  __iomem *)&reg->rsp_q_out[0], 0);
+}
+
+void qla82xx_reset_adapter(struct scsi_qla_host *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+       vha->flags.online = 0;
+       qla2x00_try_to_stop_firmware(vha);
+       ha->isp_ops->disable_intrs(ha);
+}
+
+int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
+{
+       u64 *ptr64;
+       u32 i, flashaddr, size;
+       __le64 data;
+
+       size = (IMAGE_START - BOOTLD_START) / 8;
+
+       ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START];
+       flashaddr = BOOTLD_START;
+
+       for (i = 0; i < size; i++) {
+               data = cpu_to_le64(ptr64[i]);
+               qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8);
+               flashaddr += 8;
+       }
+
+       size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET];
+       size = (__force u32)cpu_to_le32(size) / 8;
+       ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START];
+       flashaddr = FLASH_ADDR_START;
+
+       for (i = 0; i < size; i++) {
+               data = cpu_to_le64(ptr64[i]);
+
+               if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
+                       return -EIO;
+               flashaddr += 8;
+       }
+
+       /* Write a magic value to CAMRAM register
+        * at a specified offset to indicate
+        * that all data is written and
+        * ready for firmware to initialize.
+        */
+       qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678);
+
+       if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
+               qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
+               qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
+       } else
+               qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
+       return 0;
+}
+
+int qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
+{
+       u32 val = 0;
+       int retries = 60;
+
+       do {
+               read_lock(&ha->hw_lock);
+               val = qla82xx_rd_32(ha, CRB_CMDPEG_STATE);
+               read_unlock(&ha->hw_lock);
+
+               switch (val) {
+               case PHAN_INITIALIZE_COMPLETE:
+               case PHAN_INITIALIZE_ACK:
+                       return QLA_SUCCESS;
+               case PHAN_INITIALIZE_FAILED:
+                       break;
+               default:
+                       break;
+               }
+               qla_printk(KERN_WARNING, ha,
+                       "CRB_CMDPEG_STATE: 0x%x and retries: 0x%x\n",
+                       val, retries);
+
+               msleep(500);
+
+       } while (--retries);
+
+       qla_printk(KERN_INFO, ha,
+           "Cmd Peg initialization failed: 0x%x.\n", val);
+
+       qla82xx_check_for_bad_spd(ha);
+       val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
+       read_lock(&ha->hw_lock);
+       qla82xx_wr_32(ha, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
+       read_unlock(&ha->hw_lock);
+       return QLA_FUNCTION_FAILED;
+}
+
+int qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
+{
+       u32 val = 0;
+       int retries = 60;
+
+       do {
+               read_lock(&ha->hw_lock);
+               val = qla82xx_rd_32(ha, CRB_RCVPEG_STATE);
+               read_unlock(&ha->hw_lock);
+
+               switch (val) {
+               case PHAN_INITIALIZE_COMPLETE:
+               case PHAN_INITIALIZE_ACK:
+                       return QLA_SUCCESS;
+               case PHAN_INITIALIZE_FAILED:
+                       break;
+               default:
+                       break;
+               }
+
+               qla_printk(KERN_WARNING, ha,
+                       "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x\n",
+                       val, retries);
+
+               msleep(500);
+
+       } while (--retries);
+
+       qla_printk(KERN_INFO, ha,
+               "Rcv Peg initialization failed: 0x%x.\n", val);
+       read_lock(&ha->hw_lock);
+       qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED);
+       read_unlock(&ha->hw_lock);
+       return QLA_FUNCTION_FAILED;
+}
+
+/* ISR related functions */
+uint32_t qla82xx_isr_int_target_mask_enable[8] = {
+       ISR_INT_TARGET_MASK, ISR_INT_TARGET_MASK_F1,
+       ISR_INT_TARGET_MASK_F2, ISR_INT_TARGET_MASK_F3,
+       ISR_INT_TARGET_MASK_F4, ISR_INT_TARGET_MASK_F5,
+       ISR_INT_TARGET_MASK_F7, ISR_INT_TARGET_MASK_F7
+};
+
+uint32_t qla82xx_isr_int_target_status[8] = {
+       ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
+       ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
+       ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
+       ISR_INT_TARGET_STATUS_F7, ISR_INT_TARGET_STATUS_F7
+};
+
+static struct qla82xx_legacy_intr_set legacy_intr[] = \
+       QLA82XX_LEGACY_INTR_CONFIG;
+
+/*
+ * qla82xx_mbx_completion() - Process mailbox command completions.
+ * @ha: SCSI driver HA context
+ * @mb0: Mailbox0 register
+ */
+void
+qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
+{
+       uint16_t        cnt;
+       uint16_t __iomem *wptr;
+       struct qla_hw_data *ha = vha->hw;
+       struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
+       wptr = (uint16_t __iomem *)&reg->mailbox_out[1];
+
+       /* Load return mailbox registers. */
+       ha->flags.mbox_int = 1;
+       ha->mailbox_out[0] = mb0;
+
+       for (cnt = 1; cnt < ha->mbx_count; cnt++) {
+               ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
+               wptr++;
+       }
+
+       if (ha->mcp) {
+               DEBUG3_11(printk(KERN_INFO "%s(%ld): "
+                       "Got mailbox completion. cmd=%x.\n",
+                       __func__, vha->host_no, ha->mcp->mb[0]));
+       } else {
+               qla_printk(KERN_INFO, ha,
+                       "%s(%ld): MBX pointer ERROR!\n",
+                       __func__, vha->host_no);
+       }
+}
+
+/*
+ * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+ * @regs:
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+irqreturn_t
+qla82xx_intr_handler(int irq, void *dev_id)
+{
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
+       struct rsp_que *rsp;
+       struct device_reg_82xx __iomem *reg;
+       int status = 0, status1 = 0;
+       unsigned long   flags;
+       unsigned long   iter;
+       uint32_t        stat;
+       uint16_t        mb[4];
+
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
+               printk(KERN_INFO
+                       "%s(): NULL response queue pointer\n", __func__);
+               return IRQ_NONE;
+       }
+       ha = rsp->hw;
+
+       if (!ha->flags.msi_enabled) {
+               status = qla82xx_rd_32(ha, ISR_INT_VECTOR);
+               if (!(status & ha->nx_legacy_intr.int_vec_bit))
+                       return IRQ_NONE;
+
+               status1 = qla82xx_rd_32(ha, ISR_INT_STATE_REG);
+               if (!ISR_IS_LEGACY_INTR_TRIGGERED(status1))
+                       return IRQ_NONE;
+       }
+
+       /* clear the interrupt */
+       qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);
+
+       /* read twice to ensure write is flushed */
+       qla82xx_rd_32(ha, ISR_INT_VECTOR);
+       qla82xx_rd_32(ha, ISR_INT_VECTOR);
+
+       reg = &ha->iobase->isp82;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       vha = pci_get_drvdata(ha->pdev);
+       for (iter = 1; iter--; ) {
+
+               if (RD_REG_DWORD(&reg->host_int)) {
+                       stat = RD_REG_DWORD(&reg->host_status);
+                       if ((stat & HSRX_RISC_INT) == 0)
+                               break;
+
+                       switch (stat & 0xff) {
+                       case 0x1:
+                       case 0x2:
+                       case 0x10:
+                       case 0x11:
+                               qla82xx_mbx_completion(vha, MSW(stat));
+                               status |= MBX_INTERRUPT;
+                               break;
+                       case 0x12:
+                               mb[0] = MSW(stat);
+                               mb[1] = RD_REG_WORD(&reg->mailbox_out[1]);
+                               mb[2] = RD_REG_WORD(&reg->mailbox_out[2]);
+                               mb[3] = RD_REG_WORD(&reg->mailbox_out[3]);
+                               qla2x00_async_event(vha, rsp, mb);
+                               break;
+                       case 0x13:
+                               qla24xx_process_response_queue(vha, rsp);
+                               break;
+                       default:
+                               DEBUG2(printk("scsi(%ld): "
+                                       " Unrecognized interrupt type (%d).\n",
+                                       vha->host_no, stat & 0xff));
+                               break;
+                       }
+               }
+               WRT_REG_DWORD(&reg->host_int, 0);
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       if (!ha->flags.msi_enabled)
+               qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+
+#ifdef QL_DEBUG_LEVEL_17
+       if (!irq && ha->flags.eeh_busy)
+               qla_printk(KERN_WARNING, ha,
+                   "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n",
+                   status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
+#endif
+
+       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+           (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+               set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+               complete(&ha->mbx_intr_comp);
+       }
+       return IRQ_HANDLED;
+}
+
+irqreturn_t
+qla82xx_msix_default(int irq, void *dev_id)
+{
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
+       struct rsp_que *rsp;
+       struct device_reg_82xx __iomem *reg;
+       int status = 0;
+       unsigned long flags;
+       uint32_t stat;
+       uint16_t mb[4];
+
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
+               printk(KERN_INFO
+                       "%s(): NULL response queue pointer\n", __func__);
+               return IRQ_NONE;
+       }
+       ha = rsp->hw;
+
+       reg = &ha->iobase->isp82;
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       vha = pci_get_drvdata(ha->pdev);
+       do {
+               if (RD_REG_DWORD(&reg->host_int)) {
+                       stat = RD_REG_DWORD(&reg->host_status);
+                       if ((stat & HSRX_RISC_INT) == 0)
+                               break;
+
+                       switch (stat & 0xff) {
+                       case 0x1:
+                       case 0x2:
+                       case 0x10:
+                       case 0x11:
+                               qla82xx_mbx_completion(vha, MSW(stat));
+                               status |= MBX_INTERRUPT;
+                               break;
+                       case 0x12:
+                               mb[0] = MSW(stat);
+                               mb[1] = RD_REG_WORD(&reg->mailbox_out[1]);
+                               mb[2] = RD_REG_WORD(&reg->mailbox_out[2]);
+                               mb[3] = RD_REG_WORD(&reg->mailbox_out[3]);
+                               qla2x00_async_event(vha, rsp, mb);
+                               break;
+                       case 0x13:
+                               qla24xx_process_response_queue(vha, rsp);
+                               break;
+                       default:
+                               DEBUG2(printk("scsi(%ld): "
+                                       " Unrecognized interrupt type (%d).\n",
+                                       vha->host_no, stat & 0xff));
+                               break;
+                       }
+               }
+               WRT_REG_DWORD(&reg->host_int, 0);
+       } while (0);
+
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+#ifdef QL_DEBUG_LEVEL_17
+       if (!irq && ha->flags.eeh_busy)
+               qla_printk(KERN_WARNING, ha,
+                       "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n",
+                       status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
+#endif
+
+       if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+               (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+                       set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+                       complete(&ha->mbx_intr_comp);
+       }
+       return IRQ_HANDLED;
+}
+
+irqreturn_t
+qla82xx_msix_rsp_q(int irq, void *dev_id)
+{
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
+       struct rsp_que *rsp;
+       struct device_reg_82xx __iomem *reg;
+
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
+               printk(KERN_INFO
+                       "%s(): NULL response queue pointer\n", __func__);
+               return IRQ_NONE;
+       }
+
+       ha = rsp->hw;
+       reg = &ha->iobase->isp82;
+       spin_lock_irq(&ha->hardware_lock);
+       vha = pci_get_drvdata(ha->pdev);
+       qla24xx_process_response_queue(vha, rsp);
+       WRT_REG_DWORD(&reg->host_int, 0);
+       spin_unlock_irq(&ha->hardware_lock);
+       return IRQ_HANDLED;
+}
+
+void
+qla82xx_poll(int irq, void *dev_id)
+{
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
+       struct rsp_que *rsp;
+       struct device_reg_82xx __iomem *reg;
+       int status = 0;
+       uint32_t stat;
+       uint16_t mb[4];
+       unsigned long flags;
+
+       rsp = (struct rsp_que *) dev_id;
+       if (!rsp) {
+               printk(KERN_INFO
+                       "%s(): NULL response queue pointer\n", __func__);
+               return;
+       }
+       ha = rsp->hw;
+
+       reg = &ha->iobase->isp82;
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       vha = pci_get_drvdata(ha->pdev);
+
+       if (RD_REG_DWORD(&reg->host_int)) {
+               stat = RD_REG_DWORD(&reg->host_status);
+               switch (stat & 0xff) {
+               case 0x1:
+               case 0x2:
+               case 0x10:
+               case 0x11:
+                       qla82xx_mbx_completion(vha, MSW(stat));
+                       status |= MBX_INTERRUPT;
+                       break;
+               case 0x12:
+                       mb[0] = MSW(stat);
+                       mb[1] = RD_REG_WORD(&reg->mailbox_out[1]);
+                       mb[2] = RD_REG_WORD(&reg->mailbox_out[2]);
+                       mb[3] = RD_REG_WORD(&reg->mailbox_out[3]);
+                       qla2x00_async_event(vha, rsp, mb);
+                       break;
+               case 0x13:
+                       qla24xx_process_response_queue(vha, rsp);
+                       break;
+               default:
+                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
+                               "(%d).\n",
+                               vha->host_no, stat & 0xff));
+                       break;
+               }
+       }
+       WRT_REG_DWORD(&reg->host_int, 0);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qla82xx_enable_intrs(struct qla_hw_data *ha)
+{
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+       qla82xx_mbx_intr_enable(vha);
+       spin_lock_irq(&ha->hardware_lock);
+       qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+       spin_unlock_irq(&ha->hardware_lock);
+       ha->interrupts_on = 1;
+}
+
+void
+qla82xx_disable_intrs(struct qla_hw_data *ha)
+{
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+       qla82xx_mbx_intr_disable(vha);
+       spin_lock_irq(&ha->hardware_lock);
+       qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
+       spin_unlock_irq(&ha->hardware_lock);
+       ha->interrupts_on = 0;
+}
+
+void qla82xx_init_flags(struct qla_hw_data *ha)
+{
+       struct qla82xx_legacy_intr_set *nx_legacy_intr;
+
+       /* ISP 8021 initializations */
+       rwlock_init(&ha->hw_lock);
+       ha->qdr_sn_window = -1;
+       ha->ddr_mn_window = -1;
+       ha->curr_window = 255;
+       ha->portnum = PCI_FUNC(ha->pdev->devfn);
+       nx_legacy_intr = &legacy_intr[ha->portnum];
+       ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
+       ha->nx_legacy_intr.tgt_status_reg = nx_legacy_intr->tgt_status_reg;
+       ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
+       ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
+}
+
+static inline void
+qla82xx_set_drv_active(scsi_qla_host_t *vha)
+{
+       uint32_t drv_active;
+       struct qla_hw_data *ha = vha->hw;
+
+       drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+
+       /* If reset value is all FF's, initialize DRV_ACTIVE */
+       if (drv_active == 0xffffffff) {
+               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, 0);
+               drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+       }
+       drv_active |= (1 << (ha->portnum * 4));
+       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
+}
+
+inline void
+qla82xx_clear_drv_active(struct qla_hw_data *ha)
+{
+       uint32_t drv_active;
+
+       drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+       drv_active &= ~(1 << (ha->portnum * 4));
+       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
+}
+
+static inline int
+qla82xx_need_reset(struct qla_hw_data *ha)
+{
+       uint32_t drv_state;
+       int rval;
+
+       drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+       rval = drv_state & (1 << (ha->portnum * 4));
+       return rval;
+}
+
+static inline void
+qla82xx_set_rst_ready(struct qla_hw_data *ha)
+{
+       uint32_t drv_state;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
+       drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+
+       /* If reset value is all FF's, initialize DRV_STATE */
+       if (drv_state == 0xffffffff) {
+               qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0);
+               drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+       }
+       drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
+       qla_printk(KERN_INFO, ha,
+               "%s(%ld):drv_state = 0x%x\n",
+               __func__, vha->host_no, drv_state);
+       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
+}
+
+static inline void
+qla82xx_clear_rst_ready(struct qla_hw_data *ha)
+{
+       uint32_t drv_state;
+
+       drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+       drv_state &= ~(QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
+       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
+}
+
+static inline void
+qla82xx_set_qsnt_ready(struct qla_hw_data *ha)
+{
+       uint32_t qsnt_state;
+
+       qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+       qsnt_state |= (QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
+       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
+}
+
+int qla82xx_load_fw(scsi_qla_host_t *vha)
+{
+       int rst;
+       struct fw_blob *blob;
+       struct qla_hw_data *ha = vha->hw;
+
+       /* Put both the PEG CMD and RCV PEG to default state
+        * of 0 before resetting the hardware
+        */
+       qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
+       qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);
+
+       if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) {
+               qla_printk(KERN_ERR, ha,
+                       "%s: Error during CRB Initialization\n", __func__);
+               return QLA_FUNCTION_FAILED;
+       }
+       udelay(500);
+
+       /* Bring QM and CAMRAM out of reset */
+       rst = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET);
+       rst &= ~((1 << 28) | (1 << 24));
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst);
+
+       /*
+        * FW Load priority:
+        * 1) Operational firmware residing in flash.
+        * 2) Firmware via request-firmware interface (.bin file).
+        */
+       if (ql2xfwloadbin == 2)
+               goto try_blob_fw;
+
+       qla_printk(KERN_INFO, ha,
+               "Attempting to load firmware from flash\n");
+
+       if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) {
+               qla_printk(KERN_ERR, ha,
+                       "Firmware loaded successfully from flash\n");
+               return QLA_SUCCESS;
+       }
+try_blob_fw:
+       qla_printk(KERN_INFO, ha,
+           "Attempting to load firmware from blob\n");
+
+       /* Load firmware blob. */
+       blob = ha->hablob = qla2x00_request_firmware(vha);
+       if (!blob) {
+               qla_printk(KERN_ERR, ha,
+                       "Firmware image not present.\n");
+               goto fw_load_failed;
+       }
+
+       if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
+               qla_printk(KERN_ERR, ha,
+                       "%s: Firmware loaded successfully "
+                       " from binary blob\n", __func__);
+               return QLA_SUCCESS;
+       } else {
+               qla_printk(KERN_ERR, ha,
+                   "Firmware load failed from binary blob\n");
+               blob->fw = NULL;
+               blob = NULL;
+               goto fw_load_failed;
+       }
+       return QLA_SUCCESS;
+
+fw_load_failed:
+       return QLA_FUNCTION_FAILED;
+}
+
+static int
+qla82xx_start_firmware(scsi_qla_host_t *vha)
+{
+       int           pcie_cap;
+       uint16_t      lnk;
+       struct qla_hw_data *ha = vha->hw;
+
+       /* scrub dma mask expansion register */
+       qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
+
+       /* Overwrite stale initialization register values */
+       qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
+       qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
+
+       if (qla82xx_load_fw(vha) != QLA_SUCCESS) {
+               qla_printk(KERN_INFO, ha,
+                       "%s: Error trying to start fw!\n", __func__);
+               return QLA_FUNCTION_FAILED;
+       }
+
+       /* Handshake with the card before we register the devices. */
+       if (qla82xx_check_cmdpeg_state(ha) != QLA_SUCCESS) {
+               qla_printk(KERN_INFO, ha,
+                       "%s: Error during card handshake!\n", __func__);
+               return QLA_FUNCTION_FAILED;
+       }
+
+       /* Negotiated Link width */
+       pcie_cap = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+       pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk);
+       ha->link_width = (lnk >> 4) & 0x3f;
+
+       /* Synchronize with Receive peg */
+       return qla82xx_check_rcvpeg_state(ha);
+}
+
+static inline int
+qla2xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
+       uint16_t tot_dsds)
+{
+       uint32_t *cur_dsd = NULL;
+       scsi_qla_host_t *vha;
+       struct qla_hw_data *ha;
+       struct scsi_cmnd *cmd;
+       struct  scatterlist *cur_seg;
+       uint32_t *dsd_seg;
+       void *next_dsd;
+       uint8_t avail_dsds;
+       uint8_t first_iocb = 1;
+       uint32_t dsd_list_len;
+       struct dsd_dma *dsd_ptr;
+       struct ct6_dsd *ctx;
+
+       cmd = sp->cmd;
+
+       /* Update entry type to indicate Command Type 3 IOCB */
+       *((uint32_t *)(&cmd_pkt->entry_type)) =
+               __constant_cpu_to_le32(COMMAND_TYPE_6);
+
+       /* No data transfer */
+       if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
+               cmd_pkt->byte_count = __constant_cpu_to_le32(0);
+               return 0;
+       }
+
+       vha = sp->fcport->vha;
+       ha = vha->hw;
+
+       /* Set transfer direction */
+       if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+               cmd_pkt->control_flags =
+                   __constant_cpu_to_le16(CF_WRITE_DATA);
+               ha->qla_stats.output_bytes += scsi_bufflen(cmd);
+       } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+               cmd_pkt->control_flags =
+                   __constant_cpu_to_le16(CF_READ_DATA);
+               ha->qla_stats.input_bytes += scsi_bufflen(cmd);
+       }
+
+       cur_seg = scsi_sglist(cmd);
+       ctx = sp->ctx;
+
+       while (tot_dsds) {
+               avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ?
+                   QLA_DSDS_PER_IOCB : tot_dsds;
+               tot_dsds -= avail_dsds;
+               dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE;
+
+               dsd_ptr = list_first_entry(&ha->gbl_dsd_list,
+                   struct dsd_dma, list);
+               next_dsd = dsd_ptr->dsd_addr;
+               list_del(&dsd_ptr->list);
+               ha->gbl_dsd_avail--;
+               list_add_tail(&dsd_ptr->list, &ctx->dsd_list);
+               ctx->dsd_use_cnt++;
+               ha->gbl_dsd_inuse++;
+
+               if (first_iocb) {
+                       first_iocb = 0;
+                       dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address;
+                       *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
+                       *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
+                       *dsd_seg++ = dsd_list_len;
+               } else {
+                       *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma));
+                       *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma));
+                       *cur_dsd++ = dsd_list_len;
+               }
+               cur_dsd = (uint32_t *)next_dsd;
+               while (avail_dsds) {
+                       dma_addr_t      sle_dma;
+
+                       sle_dma = sg_dma_address(cur_seg);
+                       *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+                       *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+                       *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
+                       cur_seg++;
+                       avail_dsds--;
+               }
+       }
+
+       /* Null termination */
+       *cur_dsd++ =  0;
+       *cur_dsd++ = 0;
+       *cur_dsd++ = 0;
+       cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE;
+       return 0;
+}
+
+/*
+ * qla82xx_calc_dsd_lists() - Determine number of DSD list required
+ * for Command Type 6.
+ *
+ * @dsds: number of data segment decriptors needed
+ *
+ * Returns the number of dsd list needed to store @dsds.
+ */
+inline uint16_t
+qla82xx_calc_dsd_lists(uint16_t dsds)
+{
+       uint16_t dsd_lists = 0;
+
+       dsd_lists = (dsds/QLA_DSDS_PER_IOCB);
+       if (dsds % QLA_DSDS_PER_IOCB)
+               dsd_lists++;
+       return dsd_lists;
+}
+
+/*
+ * qla82xx_start_scsi() - Send a SCSI command to the ISP
+ * @sp: command to send to the ISP
+ *
+ * Returns non-zero if a failure occured, else zero.
+ */
+int
+qla82xx_start_scsi(srb_t *sp)
+{
+       int             ret, nseg;
+       unsigned long   flags;
+       struct scsi_cmnd *cmd;
+       uint32_t        *clr_ptr;
+       uint32_t        index;
+       uint32_t        handle;
+       uint16_t        cnt;
+       uint16_t        req_cnt;
+       uint16_t        tot_dsds;
+       struct device_reg_82xx __iomem *reg;
+       uint32_t dbval;
+       uint32_t *fcp_dl;
+       uint8_t additional_cdb_len;
+       struct ct6_dsd *ctx;
+       struct scsi_qla_host *vha = sp->fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       struct req_que *req = NULL;
+       struct rsp_que *rsp = NULL;
+
+       /* Setup device pointers. */
+       ret = 0;
+       reg = &ha->iobase->isp82;
+       cmd = sp->cmd;
+       req = vha->req;
+       rsp = ha->rsp_q_map[0];
+
+       /* So we know we haven't pci_map'ed anything yet */
+       tot_dsds = 0;
+
+       dbval = 0x04 | (ha->portnum << 5);
+
+       /* Send marker if required */
+       if (vha->marker_needed != 0) {
+               if (qla2x00_marker(vha, req,
+                       rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS)
+                       return QLA_FUNCTION_FAILED;
+               vha->marker_needed = 0;
+       }
+
+       /* Acquire ring specific lock */
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+
+       /* Check for room in outstanding command list. */
+       handle = req->current_outstanding_cmd;
+       for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
+               handle++;
+               if (handle == MAX_OUTSTANDING_COMMANDS)
+                       handle = 1;
+               if (!req->outstanding_cmds[handle])
+                       break;
+       }
+       if (index == MAX_OUTSTANDING_COMMANDS)
+               goto queuing_error;
+
+       /* Map the sg table so we have an accurate count of sg entries needed */
+       if (scsi_sg_count(cmd)) {
+               nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+                   scsi_sg_count(cmd), cmd->sc_data_direction);
+               if (unlikely(!nseg))
+                       goto queuing_error;
+       } else
+               nseg = 0;
+
+       tot_dsds = nseg;
+
+       if (tot_dsds > ql2xshiftctondsd) {
+               struct cmd_type_6 *cmd_pkt;
+               uint16_t more_dsd_lists = 0;
+               struct dsd_dma *dsd_ptr;
+               uint16_t i;
+
+               more_dsd_lists = qla82xx_calc_dsd_lists(tot_dsds);
+               if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN)
+                       goto queuing_error;
+
+               if (more_dsd_lists <= ha->gbl_dsd_avail)
+                       goto sufficient_dsds;
+               else
+                       more_dsd_lists -= ha->gbl_dsd_avail;
+
+               for (i = 0; i < more_dsd_lists; i++) {
+                       dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
+                       if (!dsd_ptr)
+                               goto queuing_error;
+
+                       dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool,
+                               GFP_ATOMIC, &dsd_ptr->dsd_list_dma);
+                       if (!dsd_ptr->dsd_addr) {
+                               kfree(dsd_ptr);
+                               goto queuing_error;
+                       }
+                       list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list);
+                       ha->gbl_dsd_avail++;
+               }
+
+sufficient_dsds:
+               req_cnt = 1;
+
+               ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
+               if (!sp->ctx) {
+                       DEBUG(printk(KERN_INFO
+                               "%s(%ld): failed to allocate"
+                               " ctx.\n", __func__, vha->host_no));
+                       goto queuing_error;
+               }
+               memset(ctx, 0, sizeof(struct ct6_dsd));
+               ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool,
+                       GFP_ATOMIC, &ctx->fcp_cmnd_dma);
+               if (!ctx->fcp_cmnd) {
+                       DEBUG2_3(printk("%s(%ld): failed to allocate"
+                               " fcp_cmnd.\n", __func__, vha->host_no));
+                       goto queuing_error_fcp_cmnd;
+               }
+
+               /* Initialize the DSD list and dma handle */
+               INIT_LIST_HEAD(&ctx->dsd_list);
+               ctx->dsd_use_cnt = 0;
+
+               if (cmd->cmd_len > 16) {
+                       additional_cdb_len = cmd->cmd_len - 16;
+                       if ((cmd->cmd_len % 4) != 0) {
+                               /* SCSI command bigger than 16 bytes must be
+                                * multiple of 4
+                                */
+                               goto queuing_error_fcp_cmnd;
+                       }
+                       ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
+               } else {
+                       additional_cdb_len = 0;
+                       ctx->fcp_cmnd_len = 12 + 16 + 4;
+               }
+
+               cmd_pkt = (struct cmd_type_6 *)req->ring_ptr;
+               cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
+
+               /* Zero out remaining portion of packet. */
+               /*    tagged queuing modifier -- default is TSK_SIMPLE (0). */
+               clr_ptr = (uint32_t *)cmd_pkt + 2;
+               memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+               cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
+
+               /* Set NPORT-ID and LUN number*/
+               cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+               cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
+               cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
+               cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+               cmd_pkt->vp_index = sp->fcport->vp_idx;
+
+               /* Build IOCB segments */
+               if (qla2xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds))
+                       goto queuing_error_fcp_cmnd;
+
+               int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+
+               /* build FCP_CMND IU */
+               memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd));
+               int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun);
+               ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len;
+
+               if (cmd->sc_data_direction == DMA_TO_DEVICE)
+                       ctx->fcp_cmnd->additional_cdb_len |= 1;
+               else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+                       ctx->fcp_cmnd->additional_cdb_len |= 2;
+
+               memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len);
+
+               fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 +
+                   additional_cdb_len);
+               *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd));
+
+               cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len);
+               cmd_pkt->fcp_cmnd_dseg_address[0] =
+                   cpu_to_le32(LSD(ctx->fcp_cmnd_dma));
+               cmd_pkt->fcp_cmnd_dseg_address[1] =
+                   cpu_to_le32(MSD(ctx->fcp_cmnd_dma));
+
+               sp->flags |= SRB_FCP_CMND_DMA_VALID;
+               cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
+               /* Set total data segment count. */
+               cmd_pkt->entry_count = (uint8_t)req_cnt;
+               /* Specify response queue number where
+                * completion should happen
+                */
+               cmd_pkt->entry_status = (uint8_t) rsp->id;
+       } else {
+               struct cmd_type_7 *cmd_pkt;
+               req_cnt = qla24xx_calc_iocbs(tot_dsds);
+               if (req->cnt < (req_cnt + 2)) {
+                       cnt = (uint16_t)RD_REG_DWORD_RELAXED(
+                           &reg->req_q_out[0]);
+                       if (req->ring_index < cnt)
+                               req->cnt = cnt - req->ring_index;
+                       else
+                               req->cnt = req->length -
+                                       (req->ring_index - cnt);
+               }
+               if (req->cnt < (req_cnt + 2))
+                       goto queuing_error;
+
+               cmd_pkt = (struct cmd_type_7 *)req->ring_ptr;
+               cmd_pkt->handle = MAKE_HANDLE(req->id, handle);
+
+               /* Zero out remaining portion of packet. */
+               /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/
+               clr_ptr = (uint32_t *)cmd_pkt + 2;
+               memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+               cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
+
+               /* Set NPORT-ID and LUN number*/
+               cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+               cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
+               cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
+               cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+               cmd_pkt->vp_index = sp->fcport->vp_idx;
+
+               int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
+               host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
+                       sizeof(cmd_pkt->lun));
+
+               /* Load SCSI command packet. */
+               memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
+               host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
+
+               cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
+
+               /* Build IOCB segments */
+               qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds);
+
+               /* Set total data segment count. */
+               cmd_pkt->entry_count = (uint8_t)req_cnt;
+               /* Specify response queue number where
+                * completion should happen.
+                */
+               cmd_pkt->entry_status = (uint8_t) rsp->id;
+
+       }
+       /* Build command packet. */
+       req->current_outstanding_cmd = handle;
+       req->outstanding_cmds[handle] = sp;
+       sp->handle = handle;
+       sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+       req->cnt -= req_cnt;
+       wmb();
+
+       /* Adjust ring index. */
+       req->ring_index++;
+       if (req->ring_index == req->length) {
+               req->ring_index = 0;
+               req->ring_ptr = req->ring;
+       } else
+               req->ring_ptr++;
+
+       sp->flags |= SRB_DMA_VALID;
+
+       /* Set chip new ring index. */
+       /* write, read and verify logic */
+       dbval = dbval | (req->id << 8) | (req->ring_index << 16);
+       if (ql2xdbwr)
+               qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
+       else {
+               WRT_REG_DWORD(
+                       (unsigned long __iomem *)ha->nxdb_wr_ptr,
+                       dbval);
+               wmb();
+               while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
+                       WRT_REG_DWORD(
+                               (unsigned long __iomem *)ha->nxdb_wr_ptr,
+                               dbval);
+                       wmb();
+               }
+       }
+
+       /* Manage unprocessed RIO/ZIO commands in response queue. */
+       if (vha->flags.process_response_queue &&
+           rsp->ring_ptr->signature != RESPONSE_PROCESSED)
+               qla24xx_process_response_queue(vha, rsp);
+
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       return QLA_SUCCESS;
+
+queuing_error_fcp_cmnd:
+       dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma);
+queuing_error:
+       if (tot_dsds)
+               scsi_dma_unmap(cmd);
+
+       if (sp->ctx) {
+               mempool_free(sp->ctx, ha->ctx_mempool);
+               sp->ctx = NULL;
+       }
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       return QLA_FUNCTION_FAILED;
+}
+
+uint32_t *
+qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
+       uint32_t length)
+{
+       uint32_t i;
+       uint32_t val;
+       struct qla_hw_data *ha = vha->hw;
+
+       /* Dword reads to flash. */
+       for (i = 0; i < length/4; i++, faddr += 4) {
+               if (qla82xx_rom_fast_read(ha, faddr, &val)) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Do ROM fast read failed\n");
+                       goto done_read;
+               }
+               dwptr[i] = __constant_cpu_to_le32(val);
+       }
+done_read:
+       return dwptr;
+}
+
+int
+qla82xx_unprotect_flash(struct qla_hw_data *ha)
+{
+       int ret;
+       uint32_t val;
+
+       ret = ql82xx_rom_lock_d(ha);
+       if (ret < 0) {
+               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               return ret;
+       }
+
+       ret = qla82xx_read_status_reg(ha, &val);
+       if (ret < 0)
+               goto done_unprotect;
+
+       val &= ~(0x7 << 2);
+       ret = qla82xx_write_status_reg(ha, val);
+       if (ret < 0) {
+               val |= (0x7 << 2);
+               qla82xx_write_status_reg(ha, val);
+       }
+
+       if (qla82xx_write_disable_flash(ha) != 0)
+               qla_printk(KERN_WARNING, ha, "Write disable failed\n");
+
+done_unprotect:
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+       return ret;
+}
+
+int
+qla82xx_protect_flash(struct qla_hw_data *ha)
+{
+       int ret;
+       uint32_t val;
+
+       ret = ql82xx_rom_lock_d(ha);
+       if (ret < 0) {
+               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               return ret;
+       }
+
+       ret = qla82xx_read_status_reg(ha, &val);
+       if (ret < 0)
+               goto done_protect;
+
+       val |= (0x7 << 2);
+       /* LOCK all sectors */
+       ret = qla82xx_write_status_reg(ha, val);
+       if (ret < 0)
+               qla_printk(KERN_WARNING, ha, "Write status register failed\n");
+
+       if (qla82xx_write_disable_flash(ha) != 0)
+               qla_printk(KERN_WARNING, ha, "Write disable failed\n");
+done_protect:
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+       return ret;
+}
+
+int
+qla82xx_erase_sector(struct qla_hw_data *ha, int addr)
+{
+       int ret = 0;
+
+       ret = ql82xx_rom_lock_d(ha);
+       if (ret < 0) {
+               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               return ret;
+       }
+
+       qla82xx_flash_set_write_enable(ha);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
+       qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_SE);
+
+       if (qla82xx_wait_rom_done(ha)) {
+               qla_printk(KERN_WARNING, ha,
+                   "Error waiting for rom done\n");
+               ret = -1;
+               goto done;
+       }
+       ret = qla82xx_flash_wait_write_finish(ha);
+done:
+       qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
+       return ret;
+}
+
+/*
+ * Address and length are byte address
+ */
+uint8_t *
+qla82xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+       uint32_t offset, uint32_t length)
+{
+       scsi_block_requests(vha->host);
+       qla82xx_read_flash_data(vha, (uint32_t *)buf, offset, length);
+       scsi_unblock_requests(vha->host);
+       return buf;
+}
+
+static int
+qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
+       uint32_t faddr, uint32_t dwords)
+{
+       int ret;
+       uint32_t liter;
+       uint32_t sec_mask, rest_addr;
+       dma_addr_t optrom_dma;
+       void *optrom = NULL;
+       int page_mode = 0;
+       struct qla_hw_data *ha = vha->hw;
+
+       ret = -1;
+
+       /* Prepare burst-capable write on supported ISPs. */
+       if (page_mode && !(faddr & 0xfff) &&
+           dwords > OPTROM_BURST_DWORDS) {
+               optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+                   &optrom_dma, GFP_KERNEL);
+               if (!optrom) {
+                       qla_printk(KERN_DEBUG, ha,
+                               "Unable to allocate memory for optrom "
+                               "burst write (%x KB).\n",
+                               OPTROM_BURST_SIZE / 1024);
+               }
+       }
+
+       rest_addr = ha->fdt_block_size - 1;
+       sec_mask = ~rest_addr;
+
+       ret = qla82xx_unprotect_flash(ha);
+       if (ret) {
+               qla_printk(KERN_WARNING, ha,
+                       "Unable to unprotect flash for update.\n");
+               goto write_done;
+       }
+
+       for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) {
+               /* Are we at the beginning of a sector? */
+               if ((faddr & rest_addr) == 0) {
+
+                       ret = qla82xx_erase_sector(ha, faddr);
+                       if (ret) {
+                               DEBUG9(qla_printk(KERN_ERR, ha,
+                                   "Unable to erase sector: "
+                                   "address=%x.\n", faddr));
+                               break;
+                       }
+               }
+
+               /* Go with burst-write. */
+               if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) {
+                       /* Copy data to DMA'ble buffer. */
+                       memcpy(optrom, dwptr, OPTROM_BURST_SIZE);
+
+                       ret = qla2x00_load_ram(vha, optrom_dma,
+                           (ha->flash_data_off | faddr),
+                           OPTROM_BURST_DWORDS);
+                       if (ret != QLA_SUCCESS) {
+                               qla_printk(KERN_WARNING, ha,
+                                   "Unable to burst-write optrom segment "
+                                   "(%x/%x/%llx).\n", ret,
+                                   (ha->flash_data_off | faddr),
+                                   (unsigned long long)optrom_dma);
+                               qla_printk(KERN_WARNING, ha,
+                                   "Reverting to slow-write.\n");
+
+                               dma_free_coherent(&ha->pdev->dev,
+                                   OPTROM_BURST_SIZE, optrom, optrom_dma);
+                               optrom = NULL;
+                       } else {
+                               liter += OPTROM_BURST_DWORDS - 1;
+                               faddr += OPTROM_BURST_DWORDS - 1;
+                               dwptr += OPTROM_BURST_DWORDS - 1;
+                               continue;
+                       }
+               }
+
+               ret = qla82xx_write_flash_dword(ha, faddr,
+                   cpu_to_le32(*dwptr));
+               if (ret) {
+                       DEBUG9(printk(KERN_DEBUG "%s(%ld) Unable to program"
+                           "flash address=%x data=%x.\n", __func__,
+                           ha->host_no, faddr, *dwptr));
+                       break;
+               }
+       }
+
+       ret = qla82xx_protect_flash(ha);
+       if (ret)
+               qla_printk(KERN_WARNING, ha,
+                   "Unable to protect flash after update.\n");
+write_done:
+       if (optrom)
+               dma_free_coherent(&ha->pdev->dev,
+                   OPTROM_BURST_SIZE, optrom, optrom_dma);
+       return ret;
+}
+
+int
+qla82xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+       uint32_t offset, uint32_t length)
+{
+       int rval;
+
+       /* Suspend HBA. */
+       scsi_block_requests(vha->host);
+       rval = qla82xx_write_flash_data(vha, (uint32_t *)buf, offset,
+               length >> 2);
+       scsi_unblock_requests(vha->host);
+
+       /* Convert return ISP82xx to generic */
+       if (rval)
+               rval = QLA_FUNCTION_FAILED;
+       else
+               rval = QLA_SUCCESS;
+       return rval;
+}
+
+void
+qla82xx_start_iocbs(srb_t *sp)
+{
+       struct qla_hw_data *ha = sp->fcport->vha->hw;
+       struct req_que *req = ha->req_q_map[0];
+       struct device_reg_82xx __iomem *reg;
+       uint32_t dbval;
+
+       /* Adjust ring index. */
+       req->ring_index++;
+       if (req->ring_index == req->length) {
+               req->ring_index = 0;
+               req->ring_ptr = req->ring;
+       } else
+               req->ring_ptr++;
+
+       reg = &ha->iobase->isp82;
+       dbval = 0x04 | (ha->portnum << 5);
+
+       dbval = dbval | (req->id << 8) | (req->ring_index << 16);
+       WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
+       wmb();
+       while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
+               WRT_REG_DWORD((unsigned long  __iomem *)ha->nxdb_wr_ptr, dbval);
+               wmb();
+       }
+}
+
+/*
+ * qla82xx_device_bootstrap
+ *    Initialize device, set DEV_READY, start fw
+ *
+ * Note:
+ *      IDC lock must be held upon entry
+ *
+ * Return:
+ *    Success : 0
+ *    Failed  : 1
+ */
+static int
+qla82xx_device_bootstrap(scsi_qla_host_t *vha)
+{
+       int rval, i, timeout;
+       uint32_t old_count, count;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (qla82xx_need_reset(ha))
+               goto dev_initialize;
+
+       old_count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+
+       for (i = 0; i < 10; i++) {
+               timeout = msleep_interruptible(200);
+               if (timeout) {
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                               QLA82XX_DEV_FAILED);
+                       return QLA_FUNCTION_FAILED;
+               }
+
+               count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+               if (count != old_count)
+                       goto dev_ready;
+       }
+
+dev_initialize:
+       /* set to DEV_INITIALIZING */
+       qla_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
+       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING);
+
+       /* Driver that sets device state to initializating sets IDC version */
+       qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION);
+
+       qla82xx_idc_unlock(ha);
+       rval = qla82xx_start_firmware(vha);
+       qla82xx_idc_lock(ha);
+
+       if (rval != QLA_SUCCESS) {
+               qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+               qla82xx_clear_drv_active(ha);
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED);
+               return rval;
+       }
+
+dev_ready:
+       qla_printk(KERN_INFO, ha, "HW State: READY\n");
+       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
+
+       return QLA_SUCCESS;
+}
+
+static void
+qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
+{
+       struct qla_hw_data *ha = vha->hw;
+
+       /* Disable the board */
+       qla_printk(KERN_INFO, ha, "Disabling the board\n");
+
+       /* Set DEV_FAILED flag to disable timer */
+       vha->device_flags |= DFLG_DEV_FAILED;
+       qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
+       qla2x00_mark_all_devices_lost(vha, 0);
+       vha->flags.online = 0;
+       vha->flags.init_done = 0;
+}
+
+/*
+ * qla82xx_need_reset_handler
+ *    Code to start reset sequence
+ *
+ * Note:
+ *      IDC lock must be held upon entry
+ *
+ * Return:
+ *    Success : 0
+ *    Failed  : 1
+ */
+static void
+qla82xx_need_reset_handler(scsi_qla_host_t *vha)
+{
+       uint32_t dev_state, drv_state, drv_active;
+       unsigned long reset_timeout;
+       struct qla_hw_data *ha = vha->hw;
+       struct req_que *req = ha->req_q_map[0];
+
+       if (vha->flags.online) {
+               qla82xx_idc_unlock(ha);
+               qla2x00_abort_isp_cleanup(vha);
+               ha->isp_ops->get_flash_version(vha, req->ring);
+               ha->isp_ops->nvram_config(vha);
+               qla82xx_idc_lock(ha);
+       }
+
+       qla82xx_set_rst_ready(ha);
+
+       /* wait for 10 seconds for reset ack from all functions */
+       reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
+
+       drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+       drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+
+       while (drv_state != drv_active) {
+               if (time_after_eq(jiffies, reset_timeout)) {
+                       qla_printk(KERN_INFO, ha,
+                               "%s: RESET TIMEOUT!\n", QLA2XXX_DRIVER_NAME);
+                       break;
+               }
+               qla82xx_idc_unlock(ha);
+               msleep(1000);
+               qla82xx_idc_lock(ha);
+               drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
+               drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
+       }
+
+       dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+       qla_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state,
+               dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+       /* Force to DEV_COLD unless someone else is starting a reset */
+       if (dev_state != QLA82XX_DEV_INITIALIZING) {
+               qla_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n");
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD);
+       }
+}
+
+static void
+qla82xx_check_fw_alive(scsi_qla_host_t *vha)
+{
+       uint32_t fw_heartbeat_counter, halt_status;
+       struct qla_hw_data *ha = vha->hw;
+
+       fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
+       if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
+               vha->seconds_since_last_heartbeat++;
+               /* FW not alive after 2 seconds */
+               if (vha->seconds_since_last_heartbeat == 2) {
+                       vha->seconds_since_last_heartbeat = 0;
+                       halt_status = qla82xx_rd_32(ha,
+                               QLA82XX_PEG_HALT_STATUS1);
+                       if (halt_status & HALT_STATUS_UNRECOVERABLE) {
+                               set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
+                       } else {
+                               qla_printk(KERN_INFO, ha,
+                                       "scsi(%ld): %s - detect abort needed\n",
+                                       vha->host_no, __func__);
+                               set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+                       }
+                       qla2xxx_wake_dpc(vha);
+               }
+       }
+       vha->fw_heartbeat_counter = fw_heartbeat_counter;
+}
+
+/*
+ * qla82xx_device_state_handler
+ *     Main state handler
+ *
+ * Note:
+ *      IDC lock must be held upon entry
+ *
+ * Return:
+ *    Success : 0
+ *    Failed  : 1
+ */
+int
+qla82xx_device_state_handler(scsi_qla_host_t *vha)
+{
+       uint32_t dev_state;
+       int rval = QLA_SUCCESS;
+       unsigned long dev_init_timeout;
+       struct qla_hw_data *ha = vha->hw;
+
+       qla82xx_idc_lock(ha);
+       if (!vha->flags.init_done)
+               qla82xx_set_drv_active(vha);
+
+       dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+       qla_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state,
+               dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+
+       /* wait for 30 seconds for device to go ready */
+       dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
+
+       while (1) {
+
+               if (time_after_eq(jiffies, dev_init_timeout)) {
+                       DEBUG(qla_printk(KERN_INFO, ha,
+                               "%s: device init failed!\n",
+                               QLA2XXX_DRIVER_NAME));
+                       rval = QLA_FUNCTION_FAILED;
+                       break;
+               }
+               dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+               qla_printk(KERN_INFO, ha,
+                       "2:Device state is 0x%x = %s\n", dev_state,
+                       dev_state < MAX_STATES ?
+                       qdev_state[dev_state] : "Unknown");
+
+               switch (dev_state) {
+               case QLA82XX_DEV_READY:
+                       goto exit;
+               case QLA82XX_DEV_COLD:
+                       rval = qla82xx_device_bootstrap(vha);
+                       goto exit;
+               case QLA82XX_DEV_INITIALIZING:
+                       qla82xx_idc_unlock(ha);
+                       msleep(1000);
+                       qla82xx_idc_lock(ha);
+                       break;
+               case QLA82XX_DEV_NEED_RESET:
+                       if (!ql2xdontresethba)
+                               qla82xx_need_reset_handler(vha);
+                       break;
+               case QLA82XX_DEV_NEED_QUIESCENT:
+                       qla82xx_set_qsnt_ready(ha);
+               case QLA82XX_DEV_QUIESCENT:
+                       qla82xx_idc_unlock(ha);
+                       msleep(1000);
+                       qla82xx_idc_lock(ha);
+                       break;
+               case QLA82XX_DEV_FAILED:
+                       qla82xx_dev_failed_handler(vha);
+                       rval = QLA_FUNCTION_FAILED;
+                       goto exit;
+               default:
+                       qla82xx_idc_unlock(ha);
+                       msleep(1000);
+                       qla82xx_idc_lock(ha);
+               }
+       }
+exit:
+       qla82xx_idc_unlock(ha);
+       return rval;
+}
+
+void qla82xx_watchdog(scsi_qla_host_t *vha)
+{
+       uint32_t dev_state;
+       struct qla_hw_data *ha = vha->hw;
+
+       dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+
+       /* don't poll if reset is going on */
+       if (!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+               test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))) {
+               if (dev_state == QLA82XX_DEV_NEED_RESET) {
+                       qla_printk(KERN_WARNING, ha,
+                               "%s(): Adapter reset needed!\n", __func__);
+                       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+                       qla2xxx_wake_dpc(vha);
+               } else {
+                       qla82xx_check_fw_alive(vha);
+               }
+       }
+}
+
+int qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
+{
+       int rval;
+       rval = qla82xx_device_state_handler(vha);
+       return rval;
+}
+
+/*
+ *  qla82xx_abort_isp
+ *      Resets ISP and aborts all outstanding commands.
+ *
+ * Input:
+ *      ha           = adapter block pointer.
+ *
+ * Returns:
+ *      0 = success
+ */
+int
+qla82xx_abort_isp(scsi_qla_host_t *vha)
+{
+       int rval;
+       struct qla_hw_data *ha = vha->hw;
+       uint32_t dev_state;
+
+       if (vha->device_flags & DFLG_DEV_FAILED) {
+               qla_printk(KERN_WARNING, ha,
+                       "%s(%ld): Device in failed state, "
+                       "Exiting.\n", __func__, vha->host_no);
+               return QLA_SUCCESS;
+       }
+
+       qla82xx_idc_lock(ha);
+       dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+       if (dev_state == QLA82XX_DEV_READY) {
+               qla_printk(KERN_INFO, ha, "HW State: NEED RESET\n");
+               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                       QLA82XX_DEV_NEED_RESET);
+       } else
+               qla_printk(KERN_INFO, ha, "HW State: %s\n",
+                       dev_state < MAX_STATES ?
+                       qdev_state[dev_state] : "Unknown");
+       qla82xx_idc_unlock(ha);
+
+       rval = qla82xx_device_state_handler(vha);
+
+       qla82xx_idc_lock(ha);
+       qla82xx_clear_rst_ready(ha);
+       qla82xx_idc_unlock(ha);
+
+       if (rval == QLA_SUCCESS)
+               qla82xx_restart_isp(vha);
+
+       if (rval) {
+               vha->flags.online = 1;
+               if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+                       if (ha->isp_abort_cnt == 0) {
+                               qla_printk(KERN_WARNING, ha,
+                                   "ISP error recovery failed - "
+                                   "board disabled\n");
+                               /*
+                                * The next call disables the board
+                                * completely.
+                                */
+                               ha->isp_ops->reset_adapter(vha);
+                               vha->flags.online = 0;
+                               clear_bit(ISP_ABORT_RETRY,
+                                   &vha->dpc_flags);
+                               rval = QLA_SUCCESS;
+                       } else { /* schedule another ISP abort */
+                               ha->isp_abort_cnt--;
+                               DEBUG(qla_printk(KERN_INFO, ha,
+                                   "qla%ld: ISP abort - retry remaining %d\n",
+                                   vha->host_no, ha->isp_abort_cnt));
+                               rval = QLA_FUNCTION_FAILED;
+                       }
+               } else {
+                       ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
+                       DEBUG(qla_printk(KERN_INFO, ha,
+                           "(%ld): ISP error recovery - retrying (%d) "
+                           "more times\n", vha->host_no, ha->isp_abort_cnt));
+                       set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
+                       rval = QLA_FUNCTION_FAILED;
+               }
+       }
+       return rval;
+}
+
+/*
+ *  qla82xx_fcoe_ctx_reset
+ *      Perform a quick reset and aborts all outstanding commands.
+ *      This will only perform an FCoE context reset and avoids a full blown
+ *      chip reset.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *      is_reset_path = flag for identifying the reset path.
+ *
+ * Returns:
+ *      0 = success
+ */
+int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *vha)
+{
+       int rval = QLA_FUNCTION_FAILED;
+
+       if (vha->flags.online) {
+               /* Abort all outstanding commands, so as to be requeued later */
+               qla2x00_abort_isp_cleanup(vha);
+       }
+
+       /* Stop currently executing firmware.
+        * This will destroy existing FCoE context at the F/W end.
+        */
+       qla2x00_try_to_stop_firmware(vha);
+
+       /* Restart. Creates a new FCoE context on INIT_FIRMWARE. */
+       rval = qla82xx_restart_isp(vha);
+
+       return rval;
+}
+
+/*
+ * qla2x00_wait_for_fcoe_ctx_reset
+ *    Wait till the FCoE context is reset.
+ *
+ * Note:
+ *    Does context switching here.
+ *    Release SPIN_LOCK (if any) before calling this routine.
+ *
+ * Return:
+ *    Success (fcoe_ctx reset is done) : 0
+ *    Failed  (fcoe_ctx reset not completed within max loop timout ) : 1
+ */
+int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)
+{
+       int status = QLA_FUNCTION_FAILED;
+       unsigned long wait_reset;
+
+       wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ);
+       while ((test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
+           test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
+           && time_before(jiffies, wait_reset)) {
+
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(HZ);
+
+               if (!test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) &&
+                   !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
+                       status = QLA_SUCCESS;
+                       break;
+               }
+       }
+       DEBUG2(printk(KERN_INFO
+           "%s status=%d\n", __func__, status));
+
+       return status;
+}
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
new file mode 100644 (file)
index 0000000..f8f99a5
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2008 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#ifndef __QLA_NX_H
+#define __QLA_NX_H
+
+/*
+ * Following are the states of the Phantom. Phantom will set them and
+ * Host will read to check if the fields are correct.
+*/
+#define PHAN_INITIALIZE_FAILED       0xffff
+#define PHAN_INITIALIZE_COMPLETE      0xff01
+
+/* Host writes the following to notify that it has done the init-handshake */
+#define PHAN_INITIALIZE_ACK          0xf00f
+#define PHAN_PEG_RCV_INITIALIZED      0xff01
+
+/*CRB_RELATED*/
+#define QLA82XX_CRB_BASE       QLA82XX_CAM_RAM(0x200)
+#define QLA82XX_REG(X)         (QLA82XX_CRB_BASE+(X))
+
+#define CRB_CMDPEG_STATE               QLA82XX_REG(0x50)
+#define CRB_RCVPEG_STATE               QLA82XX_REG(0x13c)
+#define BOOT_LOADER_DIMM_STATUS                QLA82XX_REG(0x54)
+#define CRB_DMA_SHIFT                  QLA82XX_REG(0xcc)
+
+#define QLA82XX_HW_H0_CH_HUB_ADR    0x05
+#define QLA82XX_HW_H1_CH_HUB_ADR    0x0E
+#define QLA82XX_HW_H2_CH_HUB_ADR    0x03
+#define QLA82XX_HW_H3_CH_HUB_ADR    0x01
+#define QLA82XX_HW_H4_CH_HUB_ADR    0x06
+#define QLA82XX_HW_H5_CH_HUB_ADR    0x07
+#define QLA82XX_HW_H6_CH_HUB_ADR    0x08
+
+/*  Hub 0 */
+#define QLA82XX_HW_MN_CRB_AGT_ADR   0x15
+#define QLA82XX_HW_MS_CRB_AGT_ADR   0x25
+
+/*  Hub 1 */
+#define QLA82XX_HW_PS_CRB_AGT_ADR      0x73
+#define QLA82XX_HW_QMS_CRB_AGT_ADR     0x00
+#define QLA82XX_HW_RPMX3_CRB_AGT_ADR   0x0b
+#define QLA82XX_HW_SQGS0_CRB_AGT_ADR   0x01
+#define QLA82XX_HW_SQGS1_CRB_AGT_ADR   0x02
+#define QLA82XX_HW_SQGS2_CRB_AGT_ADR   0x03
+#define QLA82XX_HW_SQGS3_CRB_AGT_ADR   0x04
+#define QLA82XX_HW_C2C0_CRB_AGT_ADR    0x58
+#define QLA82XX_HW_C2C1_CRB_AGT_ADR    0x59
+#define QLA82XX_HW_C2C2_CRB_AGT_ADR    0x5a
+#define QLA82XX_HW_RPMX2_CRB_AGT_ADR   0x0a
+#define QLA82XX_HW_RPMX4_CRB_AGT_ADR   0x0c
+#define QLA82XX_HW_RPMX7_CRB_AGT_ADR   0x0f
+#define QLA82XX_HW_RPMX9_CRB_AGT_ADR   0x12
+#define QLA82XX_HW_SMB_CRB_AGT_ADR     0x18
+
+/*  Hub 2 */
+#define QLA82XX_HW_NIU_CRB_AGT_ADR     0x31
+#define QLA82XX_HW_I2C0_CRB_AGT_ADR    0x19
+#define QLA82XX_HW_I2C1_CRB_AGT_ADR    0x29
+
+#define QLA82XX_HW_SN_CRB_AGT_ADR      0x10
+#define QLA82XX_HW_I2Q_CRB_AGT_ADR     0x20
+#define QLA82XX_HW_LPC_CRB_AGT_ADR     0x22
+#define QLA82XX_HW_ROMUSB_CRB_AGT_ADR  0x21
+#define QLA82XX_HW_QM_CRB_AGT_ADR      0x66
+#define QLA82XX_HW_SQG0_CRB_AGT_ADR    0x60
+#define QLA82XX_HW_SQG1_CRB_AGT_ADR    0x61
+#define QLA82XX_HW_SQG2_CRB_AGT_ADR    0x62
+#define QLA82XX_HW_SQG3_CRB_AGT_ADR    0x63
+#define QLA82XX_HW_RPMX1_CRB_AGT_ADR   0x09
+#define QLA82XX_HW_RPMX5_CRB_AGT_ADR   0x0d
+#define QLA82XX_HW_RPMX6_CRB_AGT_ADR   0x0e
+#define QLA82XX_HW_RPMX8_CRB_AGT_ADR   0x11
+
+/*  Hub 3 */
+#define QLA82XX_HW_PH_CRB_AGT_ADR      0x1A
+#define QLA82XX_HW_SRE_CRB_AGT_ADR     0x50
+#define QLA82XX_HW_EG_CRB_AGT_ADR      0x51
+#define QLA82XX_HW_RPMX0_CRB_AGT_ADR   0x08
+
+/*  Hub 4 */
+#define QLA82XX_HW_PEGN0_CRB_AGT_ADR   0x40
+#define QLA82XX_HW_PEGN1_CRB_AGT_ADR   0x41
+#define QLA82XX_HW_PEGN2_CRB_AGT_ADR   0x42
+#define QLA82XX_HW_PEGN3_CRB_AGT_ADR   0x43
+#define QLA82XX_HW_PEGNI_CRB_AGT_ADR   0x44
+#define QLA82XX_HW_PEGND_CRB_AGT_ADR   0x45
+#define QLA82XX_HW_PEGNC_CRB_AGT_ADR   0x46
+#define QLA82XX_HW_PEGR0_CRB_AGT_ADR   0x47
+#define QLA82XX_HW_PEGR1_CRB_AGT_ADR   0x48
+#define QLA82XX_HW_PEGR2_CRB_AGT_ADR   0x49
+#define QLA82XX_HW_PEGR3_CRB_AGT_ADR   0x4a
+#define QLA82XX_HW_PEGN4_CRB_AGT_ADR   0x4b
+
+/*  Hub 5 */
+#define QLA82XX_HW_PEGS0_CRB_AGT_ADR   0x40
+#define QLA82XX_HW_PEGS1_CRB_AGT_ADR   0x41
+#define QLA82XX_HW_PEGS2_CRB_AGT_ADR   0x42
+#define QLA82XX_HW_PEGS3_CRB_AGT_ADR   0x43
+#define QLA82XX_HW_PEGSI_CRB_AGT_ADR   0x44
+#define QLA82XX_HW_PEGSD_CRB_AGT_ADR   0x45
+#define QLA82XX_HW_PEGSC_CRB_AGT_ADR   0x46
+
+/*  Hub 6 */
+#define QLA82XX_HW_CAS0_CRB_AGT_ADR    0x46
+#define QLA82XX_HW_CAS1_CRB_AGT_ADR    0x47
+#define QLA82XX_HW_CAS2_CRB_AGT_ADR    0x48
+#define QLA82XX_HW_CAS3_CRB_AGT_ADR    0x49
+#define QLA82XX_HW_NCM_CRB_AGT_ADR     0x16
+#define QLA82XX_HW_TMR_CRB_AGT_ADR     0x17
+#define QLA82XX_HW_XDMA_CRB_AGT_ADR    0x05
+#define QLA82XX_HW_OCM0_CRB_AGT_ADR    0x06
+#define QLA82XX_HW_OCM1_CRB_AGT_ADR    0x07
+
+/*  This field defines PCI/X adr [25:20] of agents on the CRB */
+/*  */
+#define QLA82XX_HW_PX_MAP_CRB_PH       0
+#define QLA82XX_HW_PX_MAP_CRB_PS       1
+#define QLA82XX_HW_PX_MAP_CRB_MN       2
+#define QLA82XX_HW_PX_MAP_CRB_MS       3
+#define QLA82XX_HW_PX_MAP_CRB_SRE      5
+#define QLA82XX_HW_PX_MAP_CRB_NIU      6
+#define QLA82XX_HW_PX_MAP_CRB_QMN      7
+#define QLA82XX_HW_PX_MAP_CRB_SQN0     8
+#define QLA82XX_HW_PX_MAP_CRB_SQN1     9
+#define QLA82XX_HW_PX_MAP_CRB_SQN2     10
+#define QLA82XX_HW_PX_MAP_CRB_SQN3     11
+#define QLA82XX_HW_PX_MAP_CRB_QMS      12
+#define QLA82XX_HW_PX_MAP_CRB_SQS0     13
+#define QLA82XX_HW_PX_MAP_CRB_SQS1     14
+#define QLA82XX_HW_PX_MAP_CRB_SQS2     15
+#define QLA82XX_HW_PX_MAP_CRB_SQS3     16
+#define QLA82XX_HW_PX_MAP_CRB_PGN0     17
+#define QLA82XX_HW_PX_MAP_CRB_PGN1     18
+#define QLA82XX_HW_PX_MAP_CRB_PGN2     19
+#define QLA82XX_HW_PX_MAP_CRB_PGN3     20
+#define QLA82XX_HW_PX_MAP_CRB_PGN4     QLA82XX_HW_PX_MAP_CRB_SQS2
+#define QLA82XX_HW_PX_MAP_CRB_PGND     21
+#define QLA82XX_HW_PX_MAP_CRB_PGNI     22
+#define QLA82XX_HW_PX_MAP_CRB_PGS0     23
+#define QLA82XX_HW_PX_MAP_CRB_PGS1     24
+#define QLA82XX_HW_PX_MAP_CRB_PGS2     25
+#define QLA82XX_HW_PX_MAP_CRB_PGS3     26
+#define QLA82XX_HW_PX_MAP_CRB_PGSD     27
+#define QLA82XX_HW_PX_MAP_CRB_PGSI     28
+#define QLA82XX_HW_PX_MAP_CRB_SN       29
+#define QLA82XX_HW_PX_MAP_CRB_EG       31
+#define QLA82XX_HW_PX_MAP_CRB_PH2      32
+#define QLA82XX_HW_PX_MAP_CRB_PS2      33
+#define QLA82XX_HW_PX_MAP_CRB_CAM      34
+#define QLA82XX_HW_PX_MAP_CRB_CAS0     35
+#define QLA82XX_HW_PX_MAP_CRB_CAS1     36
+#define QLA82XX_HW_PX_MAP_CRB_CAS2     37
+#define QLA82XX_HW_PX_MAP_CRB_C2C0     38
+#define QLA82XX_HW_PX_MAP_CRB_C2C1     39
+#define QLA82XX_HW_PX_MAP_CRB_TIMR     40
+#define QLA82XX_HW_PX_MAP_CRB_RPMX1    42
+#define QLA82XX_HW_PX_MAP_CRB_RPMX2    43
+#define QLA82XX_HW_PX_MAP_CRB_RPMX3    44
+#define QLA82XX_HW_PX_MAP_CRB_RPMX4    45
+#define QLA82XX_HW_PX_MAP_CRB_RPMX5    46
+#define QLA82XX_HW_PX_MAP_CRB_RPMX6    47
+#define QLA82XX_HW_PX_MAP_CRB_RPMX7    48
+#define QLA82XX_HW_PX_MAP_CRB_XDMA     49
+#define QLA82XX_HW_PX_MAP_CRB_I2Q      50
+#define QLA82XX_HW_PX_MAP_CRB_ROMUSB   51
+#define QLA82XX_HW_PX_MAP_CRB_CAS3     52
+#define QLA82XX_HW_PX_MAP_CRB_RPMX0    53
+#define QLA82XX_HW_PX_MAP_CRB_RPMX8    54
+#define QLA82XX_HW_PX_MAP_CRB_RPMX9    55
+#define QLA82XX_HW_PX_MAP_CRB_OCM0     56
+#define QLA82XX_HW_PX_MAP_CRB_OCM1     57
+#define QLA82XX_HW_PX_MAP_CRB_SMB      58
+#define QLA82XX_HW_PX_MAP_CRB_I2C0     59
+#define QLA82XX_HW_PX_MAP_CRB_I2C1     60
+#define QLA82XX_HW_PX_MAP_CRB_LPC      61
+#define QLA82XX_HW_PX_MAP_CRB_PGNC     62
+#define QLA82XX_HW_PX_MAP_CRB_PGR0     63
+#define QLA82XX_HW_PX_MAP_CRB_PGR1     4
+#define QLA82XX_HW_PX_MAP_CRB_PGR2     30
+#define QLA82XX_HW_PX_MAP_CRB_PGR3     41
+
+/*  This field defines CRB adr [31:20] of the agents */
+/*  */
+
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_MN      ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_MN_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PH      ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PH_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_MS      ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_MS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PS      ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SS      ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMS     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_QMS_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS0     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQGS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS1     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQGS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS2     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQGS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS3     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQGS3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C0     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_C2C0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C1     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_C2C1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX4_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX7_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9    ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX9_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SMB     ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SMB_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_NIU     ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_NIU_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0     ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_I2C0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1     ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_I2C1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SRE     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SRE_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_EG      ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_EG_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMN     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_QM_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQG0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQG1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQG2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SQG3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX5_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX6_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8    ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_RPMX8_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS0     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_CAS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS1     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_CAS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS2     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_CAS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS3     ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_CAS3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGNI_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGND     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGND_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGN0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGN1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGN2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGN3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4           ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGN4_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGNC_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR0     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGR0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR1     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGR1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR2     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGR2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR3     ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGR3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGSI_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSD     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGSD_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGS0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGS1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGS2_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGS3_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSC     ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_PEGSC_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAM     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_NCM_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_TMR_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_XDMA_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_SN      ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_SN_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_I2Q_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB   ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_ROMUSB_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_OCM0_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM1     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_OCM1_CRB_AGT_ADR)
+#define QLA82XX_HW_CRB_HUB_AGT_ADR_LPC     ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \
+       QLA82XX_HW_LPC_CRB_AGT_ADR)
+
+#define ROMUSB_GLB                             (QLA82XX_CRB_ROMUSB + 0x00000)
+#define QLA82XX_ROMUSB_GLB_PEGTUNE_DONE                (ROMUSB_GLB + 0x005c)
+#define QLA82XX_ROMUSB_GLB_STATUS              (ROMUSB_GLB + 0x0004)
+#define QLA82XX_ROMUSB_GLB_SW_RESET            (ROMUSB_GLB + 0x0008)
+#define QLA82XX_ROMUSB_ROM_ADDRESS             (ROMUSB_ROM + 0x0008)
+#define QLA82XX_ROMUSB_ROM_WDATA               (ROMUSB_ROM + 0x000c)
+#define QLA82XX_ROMUSB_ROM_ABYTE_CNT           (ROMUSB_ROM + 0x0010)
+#define QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT      (ROMUSB_ROM + 0x0014)
+#define QLA82XX_ROMUSB_ROM_RDATA               (ROMUSB_ROM + 0x0018)
+
+#define ROMUSB_ROM                             (QLA82XX_CRB_ROMUSB + 0x10000)
+#define QLA82XX_ROMUSB_ROM_INSTR_OPCODE                (ROMUSB_ROM + 0x0004)
+#define QLA82XX_ROMUSB_GLB_CAS_RST             (ROMUSB_GLB + 0x0038)
+
+/* Lock IDs for ROM lock */
+#define ROM_LOCK_DRIVER       0x0d417340
+
+#define QLA82XX_PCI_CRB_WINDOWSIZE 0x00100000   /* all are 1MB windows */
+#define QLA82XX_PCI_CRB_WINDOW(A) \
+       (QLA82XX_PCI_CRBSPACE + (A)*QLA82XX_PCI_CRB_WINDOWSIZE)
+#define QLA82XX_CRB_C2C_0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C0)
+#define QLA82XX_CRB_C2C_1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C1)
+#define QLA82XX_CRB_C2C_2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C2)
+#define QLA82XX_CRB_CAM \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAM)
+#define QLA82XX_CRB_CASPER \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS)
+#define QLA82XX_CRB_CASPER_0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS0)
+#define QLA82XX_CRB_CASPER_1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS1)
+#define QLA82XX_CRB_CASPER_2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS2)
+#define QLA82XX_CRB_DDR_MD \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MS)
+#define QLA82XX_CRB_DDR_NET \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MN)
+#define QLA82XX_CRB_EPG \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_EG)
+#define QLA82XX_CRB_I2Q \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2Q)
+#define QLA82XX_CRB_NIU \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_NIU)
+
+#define QLA82XX_CRB_PCIX_HOST \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH)
+#define QLA82XX_CRB_PCIX_HOST2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH2)
+#define QLA82XX_CRB_PCIX_MD \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS)
+#define QLA82XX_CRB_PCIE \
+       QLA82XX_CRB_PCIX_MD
+
+/* window 1 pcie slot */
+#define QLA82XX_CRB_PCIE2       \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS2)
+#define QLA82XX_CRB_PEG_MD_0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS0)
+#define QLA82XX_CRB_PEG_MD_1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS1)
+#define QLA82XX_CRB_PEG_MD_2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS2)
+#define QLA82XX_CRB_PEG_MD_3 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3)
+#define QLA82XX_CRB_PEG_MD_3 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3)
+#define QLA82XX_CRB_PEG_MD_D \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSD)
+#define QLA82XX_CRB_PEG_MD_I \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSI)
+#define QLA82XX_CRB_PEG_NET_0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN0)
+#define QLA82XX_CRB_PEG_NET_1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN1)
+#define QLA82XX_CRB_PEG_NET_2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN2)
+#define QLA82XX_CRB_PEG_NET_3 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN3)
+#define QLA82XX_CRB_PEG_NET_4 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN4)
+#define QLA82XX_CRB_PEG_NET_D \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGND)
+#define QLA82XX_CRB_PEG_NET_I \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGNI)
+#define QLA82XX_CRB_PQM_MD \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMS)
+#define QLA82XX_CRB_PQM_NET \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMN)
+#define QLA82XX_CRB_QDR_MD \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SS)
+#define QLA82XX_CRB_QDR_NET \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SN)
+#define QLA82XX_CRB_ROMUSB \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_ROMUSB)
+#define QLA82XX_CRB_RPMX_0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX0)
+#define QLA82XX_CRB_RPMX_1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX1)
+#define QLA82XX_CRB_RPMX_2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX2)
+#define QLA82XX_CRB_RPMX_3 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX3)
+#define QLA82XX_CRB_RPMX_4 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX4)
+#define QLA82XX_CRB_RPMX_5 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX5)
+#define QLA82XX_CRB_RPMX_6 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX6)
+#define QLA82XX_CRB_RPMX_7 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX7)
+#define QLA82XX_CRB_SQM_MD_0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS0)
+#define QLA82XX_CRB_SQM_MD_1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS1)
+#define QLA82XX_CRB_SQM_MD_2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS2)
+#define QLA82XX_CRB_SQM_MD_3 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS3)
+#define QLA82XX_CRB_SQM_NET_0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN0)
+#define QLA82XX_CRB_SQM_NET_1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN1)
+#define QLA82XX_CRB_SQM_NET_2 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN2)
+#define QLA82XX_CRB_SQM_NET_3 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN3)
+#define QLA82XX_CRB_SRE \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SRE)
+#define QLA82XX_CRB_TIMER \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_TIMR)
+#define QLA82XX_CRB_XDMA \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_XDMA)
+#define QLA82XX_CRB_I2C0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C0)
+#define QLA82XX_CRB_I2C1 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C1)
+#define QLA82XX_CRB_OCM0 \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_OCM0)
+#define QLA82XX_CRB_SMB \
+       QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SMB)
+#define QLA82XX_CRB_MAX \
+       QLA82XX_PCI_CRB_WINDOW(64)
+
+/*
+ * ====================== BASE ADDRESSES ON-CHIP ======================
+ * Base addresses of major components on-chip.
+ * ====================== BASE ADDRESSES ON-CHIP ======================
+ */
+#define QLA82XX_ADDR_DDR_NET           (0x0000000000000000ULL)
+#define QLA82XX_ADDR_DDR_NET_MAX       (0x000000000fffffffULL)
+
+/* Imbus address bit used to indicate a host address. This bit is
+ * eliminated by the pcie bar and bar select before presentation
+ * over pcie. */
+/* host memory via IMBUS */
+#define QLA82XX_P2_ADDR_PCIE           (0x0000000800000000ULL)
+#define QLA82XX_P3_ADDR_PCIE           (0x0000008000000000ULL)
+#define QLA82XX_ADDR_PCIE_MAX          (0x0000000FFFFFFFFFULL)
+#define QLA82XX_ADDR_OCM0              (0x0000000200000000ULL)
+#define QLA82XX_ADDR_OCM0_MAX          (0x00000002000fffffULL)
+#define QLA82XX_ADDR_OCM1              (0x0000000200400000ULL)
+#define QLA82XX_ADDR_OCM1_MAX          (0x00000002004fffffULL)
+#define QLA82XX_ADDR_QDR_NET           (0x0000000300000000ULL)
+
+#define QLA82XX_P2_ADDR_QDR_NET_MAX    (0x00000003001fffffULL)
+#define QLA82XX_P3_ADDR_QDR_NET_MAX    (0x0000000303ffffffULL)
+
+#define QLA82XX_PCI_CRBSPACE           (unsigned long)0x06000000
+#define QLA82XX_PCI_DIRECT_CRB         (unsigned long)0x04400000
+#define QLA82XX_PCI_CAMQM              (unsigned long)0x04800000
+#define QLA82XX_PCI_CAMQM_MAX          (unsigned long)0x04ffffff
+#define QLA82XX_PCI_DDR_NET            (unsigned long)0x00000000
+#define QLA82XX_PCI_QDR_NET            (unsigned long)0x04000000
+#define QLA82XX_PCI_QDR_NET_MAX                (unsigned long)0x043fffff
+
+/*
+ *   Register offsets for MN
+ */
+#define MIU_CONTROL                    (0x000)
+#define MIU_TAG                                (0x004)
+#define MIU_TEST_AGT_CTRL              (0x090)
+#define MIU_TEST_AGT_ADDR_LO           (0x094)
+#define MIU_TEST_AGT_ADDR_HI           (0x098)
+#define MIU_TEST_AGT_WRDATA_LO         (0x0a0)
+#define MIU_TEST_AGT_WRDATA_HI         (0x0a4)
+#define MIU_TEST_AGT_WRDATA(i)         (0x0a0+(4*(i)))
+#define MIU_TEST_AGT_RDDATA_LO         (0x0a8)
+#define MIU_TEST_AGT_RDDATA_HI         (0x0ac)
+#define MIU_TEST_AGT_RDDATA(i)         (0x0a8+(4*(i)))
+#define MIU_TEST_AGT_ADDR_MASK         0xfffffff8
+#define MIU_TEST_AGT_UPPER_ADDR(off)   (0)
+
+/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
+#define MIU_TA_CTL_START       1
+#define MIU_TA_CTL_ENABLE      2
+#define MIU_TA_CTL_WRITE       4
+#define MIU_TA_CTL_BUSY                8
+
+/*CAM RAM */
+# define QLA82XX_CAM_RAM_BASE          (QLA82XX_CRB_CAM + 0x02000)
+# define QLA82XX_CAM_RAM(reg)          (QLA82XX_CAM_RAM_BASE + (reg))
+
+#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED 0x80000000
+#define QLA82XX_BOOT_LOADER_MN_ISSUE   0xff00ffff
+#define QLA82XX_PORT_MODE_ADDR         (QLA82XX_CAM_RAM(0x24))
+#define QLA82XX_PEG_HALT_STATUS1       (QLA82XX_CAM_RAM(0xa8))
+#define QLA82XX_PEG_HALT_STATUS2       (QLA82XX_CAM_RAM(0xac))
+#define QLA82XX_PEG_ALIVE_COUNTER      (QLA82XX_CAM_RAM(0xb0))
+
+#define QLA82XX_CAMRAM_DB1             (QLA82XX_CAM_RAM(0x1b8))
+#define QLA82XX_CAMRAM_DB2             (QLA82XX_CAM_RAM(0x1bc))
+
+#define HALT_STATUS_UNRECOVERABLE      0x80000000
+#define HALT_STATUS_RECOVERABLE                0x40000000
+
+/* Driver Coexistence Defines */
+#define QLA82XX_CRB_DRV_ACTIVE      (QLA82XX_CAM_RAM(0x138))
+#define QLA82XX_CRB_DEV_STATE       (QLA82XX_CAM_RAM(0x140))
+#define QLA82XX_CRB_DEV_PART_INFO    (QLA82XX_CAM_RAM(0x14c))
+#define QLA82XX_CRB_DRV_IDC_VERSION  (QLA82XX_CAM_RAM(0x174))
+#define QLA82XX_CRB_DRV_STATE       (QLA82XX_CAM_RAM(0x144))
+#define QLA82XX_CRB_DRV_SCRATCH      (QLA82XX_CAM_RAM(0x148))
+#define QLA82XX_CRB_DEV_PART_INFO    (QLA82XX_CAM_RAM(0x14c))
+
+/* Every driver should use these Device State */
+#define QLA82XX_DEV_COLD               1
+#define QLA82XX_DEV_INITIALIZING       2
+#define QLA82XX_DEV_READY              3
+#define QLA82XX_DEV_NEED_RESET         4
+#define QLA82XX_DEV_NEED_QUIESCENT     5
+#define QLA82XX_DEV_FAILED             6
+#define QLA82XX_DEV_QUIESCENT          7
+#define        MAX_STATES                      8 /* Increment if new state added */
+
+#define QLA82XX_IDC_VERSION                    1
+#define QLA82XX_ROM_DEV_INIT_TIMEOUT           30
+#define QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT      10
+
+#define QLA82XX_ROM_LOCK_ID            (QLA82XX_CAM_RAM(0x100))
+#define QLA82XX_CRB_WIN_LOCK_ID                (QLA82XX_CAM_RAM(0x124))
+#define QLA82XX_FW_VERSION_MAJOR       (QLA82XX_CAM_RAM(0x150))
+#define QLA82XX_FW_VERSION_MINOR       (QLA82XX_CAM_RAM(0x154))
+#define QLA82XX_FW_VERSION_SUB         (QLA82XX_CAM_RAM(0x158))
+#define QLA82XX_PCIE_REG(reg)          (QLA82XX_CRB_PCIE + (reg))
+
+#define PCIE_CHICKEN3                  (0x120c8)
+#define PCIE_SETUP_FUNCTION            (0x12040)
+#define PCIE_SETUP_FUNCTION2           (0x12048)
+
+#define QLA82XX_PCIX_PS_REG(reg)       (QLA82XX_CRB_PCIX_MD + (reg))
+#define QLA82XX_PCIX_PS2_REG(reg)      (QLA82XX_CRB_PCIE2 + (reg))
+
+#define PCIE_SEM2_LOCK      (0x1c010)  /* Flash lock   */
+#define PCIE_SEM2_UNLOCK     (0x1c014) /* Flash unlock */
+#define PCIE_SEM5_LOCK      (0x1c028)  /* Coexistence lock   */
+#define PCIE_SEM5_UNLOCK     (0x1c02c) /* Coexistence unlock */
+#define PCIE_SEM7_LOCK      (0x1c038)  /* crb win lock */
+#define PCIE_SEM7_UNLOCK     (0x1c03c) /* crbwin unlock*/
+
+/* Different drive state */
+#define QLA82XX_DRVST_NOT_RDY          0
+#define        QLA82XX_DRVST_RST_RDY           1
+#define QLA82XX_DRVST_QSNT_RDY         2
+
+/*
+ * The PCI VendorID and DeviceID for our board.
+ */
+#define PCI_DEVICE_ID_QLOGIC_ISP8021           0x8021
+
+#define QLA82XX_MSIX_TBL_SPACE                 8192
+#define QLA82XX_PCI_REG_MSIX_TBL               0x44
+#define QLA82XX_PCI_MSIX_CONTROL               0x40
+
+struct crb_128M_2M_sub_block_map {
+       unsigned valid;
+       unsigned start_128M;
+       unsigned end_128M;
+       unsigned start_2M;
+};
+
+struct crb_128M_2M_block_map {
+       struct crb_128M_2M_sub_block_map sub_block[16];
+};
+
+struct crb_addr_pair {
+       long addr;
+       long data;
+};
+
+#define ADDR_ERROR ((unsigned long) 0xffffffff)
+#define MAX_CTL_CHECK  1000
+
+/***************************************************************************
+ *             PCI related defines.
+ **************************************************************************/
+
+/*
+ * Interrupt related defines.
+ */
+#define PCIX_TARGET_STATUS     (0x10118)
+#define PCIX_TARGET_STATUS_F1  (0x10160)
+#define PCIX_TARGET_STATUS_F2  (0x10164)
+#define PCIX_TARGET_STATUS_F3  (0x10168)
+#define PCIX_TARGET_STATUS_F4  (0x10360)
+#define PCIX_TARGET_STATUS_F5  (0x10364)
+#define PCIX_TARGET_STATUS_F6  (0x10368)
+#define PCIX_TARGET_STATUS_F7  (0x1036c)
+
+#define PCIX_TARGET_MASK       (0x10128)
+#define PCIX_TARGET_MASK_F1    (0x10170)
+#define PCIX_TARGET_MASK_F2    (0x10174)
+#define PCIX_TARGET_MASK_F3    (0x10178)
+#define PCIX_TARGET_MASK_F4    (0x10370)
+#define PCIX_TARGET_MASK_F5    (0x10374)
+#define PCIX_TARGET_MASK_F6    (0x10378)
+#define PCIX_TARGET_MASK_F7    (0x1037c)
+
+/*
+ * Message Signaled Interrupts
+ */
+#define PCIX_MSI_F0            (0x13000)
+#define PCIX_MSI_F1            (0x13004)
+#define PCIX_MSI_F2            (0x13008)
+#define PCIX_MSI_F3            (0x1300c)
+#define PCIX_MSI_F4            (0x13010)
+#define PCIX_MSI_F5            (0x13014)
+#define PCIX_MSI_F6            (0x13018)
+#define PCIX_MSI_F7            (0x1301c)
+#define PCIX_MSI_F(FUNC)       (0x13000 + ((FUNC) * 4))
+#define PCIX_INT_VECTOR                (0x10100)
+#define PCIX_INT_MASK          (0x10104)
+
+/*
+ * Interrupt state machine and other bits.
+ */
+#define PCIE_MISCCFG_RC                (0x1206c)
+
+#define ISR_INT_TARGET_STATUS \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS))
+#define ISR_INT_TARGET_STATUS_F1 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F1))
+#define ISR_INT_TARGET_STATUS_F2 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F2))
+#define ISR_INT_TARGET_STATUS_F3 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F3))
+#define ISR_INT_TARGET_STATUS_F4 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F4))
+#define ISR_INT_TARGET_STATUS_F5 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F5))
+#define ISR_INT_TARGET_STATUS_F6 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F6))
+#define ISR_INT_TARGET_STATUS_F7 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F7))
+
+#define ISR_INT_TARGET_MASK \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK))
+#define ISR_INT_TARGET_MASK_F1 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F1))
+#define ISR_INT_TARGET_MASK_F2 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F2))
+#define ISR_INT_TARGET_MASK_F3 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F3))
+#define ISR_INT_TARGET_MASK_F4 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F4))
+#define ISR_INT_TARGET_MASK_F5 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F5))
+#define ISR_INT_TARGET_MASK_F6 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F6))
+#define ISR_INT_TARGET_MASK_F7 \
+       (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F7))
+
+#define ISR_INT_VECTOR \
+       (QLA82XX_PCIX_PS_REG(PCIX_INT_VECTOR))
+#define ISR_INT_MASK \
+       (QLA82XX_PCIX_PS_REG(PCIX_INT_MASK))
+#define ISR_INT_STATE_REG \
+       (QLA82XX_PCIX_PS_REG(PCIE_MISCCFG_RC))
+
+#define        ISR_MSI_INT_TRIGGER(FUNC) \
+       (QLA82XX_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
+
+#define        ISR_IS_LEGACY_INTR_IDLE(VAL)            (((VAL) & 0x300) == 0)
+#define        ISR_IS_LEGACY_INTR_TRIGGERED(VAL)       (((VAL) & 0x300) == 0x200)
+
+/*
+ * PCI Interrupt Vector Values.
+ */
+#define        PCIX_INT_VECTOR_BIT_F0  0x0080
+#define        PCIX_INT_VECTOR_BIT_F1  0x0100
+#define        PCIX_INT_VECTOR_BIT_F2  0x0200
+#define        PCIX_INT_VECTOR_BIT_F3  0x0400
+#define        PCIX_INT_VECTOR_BIT_F4  0x0800
+#define        PCIX_INT_VECTOR_BIT_F5  0x1000
+#define        PCIX_INT_VECTOR_BIT_F6  0x2000
+#define        PCIX_INT_VECTOR_BIT_F7  0x4000
+
+struct qla82xx_legacy_intr_set {
+       uint32_t        int_vec_bit;
+       uint32_t        tgt_status_reg;
+       uint32_t        tgt_mask_reg;
+       uint32_t        pci_int_reg;
+};
+
+#define QLA82XX_LEGACY_INTR_CONFIG                                     \
+{                                                                      \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F0,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS,          \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK,            \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(0) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F1,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F1,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F1,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(1) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F2,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F2,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F2,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(2) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F3,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F3,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F3,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(3) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F4,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F4,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F4,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(4) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F5,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F5,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F5,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(5) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F6,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F6,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F6,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(6) },       \
+                                                                       \
+       {                                                               \
+               .int_vec_bit    =       PCIX_INT_VECTOR_BIT_F7,         \
+               .tgt_status_reg =       ISR_INT_TARGET_STATUS_F7,       \
+               .tgt_mask_reg   =       ISR_INT_TARGET_MASK_F7,         \
+               .pci_int_reg    =       ISR_MSI_INT_TRIGGER(7) },       \
+}
+
+#define        BOOTLD_START            0x10000
+#define        IMAGE_START             0x100000
+#define FLASH_ADDR_START       0x43000
+
+/* Magic number to let user know flash is programmed */
+#define QLA82XX_BDINFO_MAGIC   0x12345678
+#define FW_SIZE_OFFSET         (0x3e840c)
+
+#define QLA82XX_IS_REVISION_P3PLUS(_rev_)      ((_rev_) >= 0x50)
+#define MIU_TEST_AGT_WRDATA_UPPER_LO           (0x0b0)
+#define        MIU_TEST_AGT_WRDATA_UPPER_HI            (0x0b4)
+
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+       return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+       writel(((u32) (val)), (addr));
+       writel(((u32) (val >> 32)), (addr + 4));
+}
+#endif
+
+/* Request and response queue size */
+#define REQUEST_ENTRY_CNT_82XX         128     /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_82XX                128     /* Number of response entries.*/
+
+/*
+ * ISP 8021 I/O Register Set structure definitions.
+ */
+struct device_reg_82xx {
+       uint32_t req_q_out[64];         /* Request Queue out-Pointer (64 * 4) */
+       uint32_t rsp_q_in[64];          /* Response Queue In-Pointer. */
+       uint32_t rsp_q_out[64];         /* Response Queue Out-Pointer. */
+
+       uint16_t mailbox_in[32];        /* Mail box In registers */
+       uint16_t unused_1[32];
+       uint32_t hint;                  /* Host interrupt register */
+#define        HINT_MBX_INT_PENDING    BIT_0
+       uint16_t unused_2[62];
+       uint16_t mailbox_out[32];       /* Mail box Out registers */
+       uint32_t unused_3[48];
+
+       uint32_t host_status;           /* host status */
+#define HSRX_RISC_INT          BIT_15  /* RISC to Host interrupt. */
+#define HSRX_RISC_PAUSED       BIT_8   /* RISC Paused. */
+       uint32_t host_int;              /* Interrupt status. */
+#define ISRX_NX_RISC_INT       BIT_0   /* RISC interrupt. */
+};
+
+struct fcp_cmnd {
+       struct scsi_lun lun;
+       uint8_t crn;
+       uint8_t task_attribute;
+       uint8_t task_managment;
+       uint8_t additional_cdb_len;
+       uint8_t cdb[260]; /* 256 for CDB len and 4 for FCP_DL */
+};
+
+struct dsd_dma {
+       struct list_head list;
+       dma_addr_t dsd_list_dma;
+       void *dsd_addr;
+};
+
+#define QLA_DSDS_PER_IOCB      37
+#define QLA_DSD_SIZE           12
+struct ct6_dsd {
+       uint16_t fcp_cmnd_len;
+       dma_addr_t fcp_cmnd_dma;
+       struct fcp_cmnd *fcp_cmnd;
+       int dsd_use_cnt;
+       struct list_head dsd_list;
+};
+
+#define MBC_TOGGLE_INTR                        0x10
+
+/* Flash  offset */
+#define FLT_REG_BOOTLOAD_82XX  0x72
+#define FLT_REG_BOOT_CODE_82XX 0x78
+#define FLT_REG_FW_82XX                0x74
+#define FLT_REG_GOLD_FW_82XX   0x75
+#define FLT_REG_VPD_82XX       0x81
+
+#define        FA_VPD_SIZE_82XX        0x400
+
+#define FA_FLASH_LAYOUT_ADDR_82        0xFC400
+
+/******************************************************************************
+*
+*    Definitions specific to M25P flash
+*
+*******************************************************************************
+*   Instructions
+*/
+#define M25P_INSTR_WREN                0x06
+#define M25P_INSTR_WRDI                0x04
+#define M25P_INSTR_RDID                0x9f
+#define M25P_INSTR_RDSR                0x05
+#define M25P_INSTR_WRSR                0x01
+#define M25P_INSTR_READ                0x03
+#define M25P_INSTR_FAST_READ   0x0b
+#define M25P_INSTR_PP          0x02
+#define M25P_INSTR_SE          0xd8
+#define M25P_INSTR_BE          0xc7
+#define M25P_INSTR_DP          0xb9
+#define M25P_INSTR_RES         0xab
+
+#endif
index 48c37e3..be1a8fc 100644 (file)
  */
 char qla2x00_version_str[40];
 
+static int apidev_major;
+
 /*
  * SRB allocation cache
  */
 static struct kmem_cache *srb_cachep;
 
+/*
+ * CT6 CTX allocation cache
+ */
+static struct kmem_cache *ctx_cachep;
+
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
@@ -65,13 +72,19 @@ MODULE_PARM_DESC(ql2xextended_error_logging,
                "Option to enable extended error logging, "
                "Default is 0 - no logging. 1 - log errors.");
 
+int ql2xshiftctondsd = 6;
+module_param(ql2xshiftctondsd, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xshiftctondsd,
+               "Set to control shifting of command type processing "
+               "based on total number of SG elements.");
+
 static void qla2x00_free_device(scsi_qla_host_t *);
 
 int ql2xfdmienable=1;
 module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xfdmienable,
-               "Enables FDMI registratons "
-               "Default is 0 - no FDMI. 1 - perfom FDMI.");
+               "Enables FDMI registrations. "
+               "0 - no FDMI. Default is 1 - perform FDMI.");
 
 #define MAX_Q_DEPTH    32
 static int ql2xmaxqdepth = MAX_Q_DEPTH;
@@ -79,6 +92,19 @@ module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xmaxqdepth,
                "Maximum queue depth to report for target devices.");
 
+/* Do not change the value of this after module load */
+int ql2xenabledif = 1;
+module_param(ql2xenabledif, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xenabledif,
+               " Enable T10-CRC-DIF "
+               " Default is 0 - No DIF Support. 1 - Enable it");
+
+int ql2xenablehba_err_chk;
+module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xenablehba_err_chk,
+               " Enable T10-CRC-DIF Error isolation by HBA"
+               " Default is 0 - Error isolation disabled, 1 - Enable it");
+
 int ql2xiidmaenable=1;
 module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xiidmaenable,
@@ -114,6 +140,32 @@ MODULE_PARM_DESC(ql2xetsenable,
                "Enables firmware ETS burst."
                "Default is 0 - skip ETS enablement.");
 
+int ql2xdbwr;
+module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xdbwr,
+       "Option to specify scheme for request queue posting\n"
+       " 0 -- Regular doorbell.\n"
+       " 1 -- CAMRAM doorbell (faster).\n");
+
+int ql2xdontresethba;
+module_param(ql2xdontresethba, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xdontresethba,
+       "Option to specify reset behaviour\n"
+       " 0 (Default) -- Reset on failure.\n"
+       " 1 -- Do not reset on failure.\n");
+
+int ql2xtargetreset = 1;
+module_param(ql2xtargetreset, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xtargetreset,
+                "Enable target reset."
+                "Default is 1 - use hw defaults.");
+
+
+int ql2xasynctmfenable;
+module_param(ql2xasynctmfenable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xasynctmfenable,
+               "Enables issue of TM IOCBs asynchronously via IOCB mechanism"
+               "Default is 0 - Issue TM IOCBs via mailbox mechanism.");
 /*
  * SCSI host template entry points
  */
@@ -183,6 +235,10 @@ qla2x00_start_timer(scsi_qla_host_t *vha, void *func, unsigned long interval)
 static inline void
 qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval)
 {
+       /* Currently used for 82XX only. */
+       if (vha->device_flags & DFLG_DEV_FAILED)
+               return;
+
        mod_timer(&vha->timer, jiffies + interval * HZ);
 }
 
@@ -500,6 +556,14 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
        if (fcport->drport)
                goto qc24_target_busy;
 
+       if (!vha->flags.difdix_supported &&
+               scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
+                       DEBUG2(qla_printk(KERN_ERR, ha,
+                           "DIF Cap Not Reg, fail DIF capable cmd's:%x\n",
+                           cmd->cmnd[0]));
+                       cmd->result = DID_NO_CONNECT << 16;
+                       goto qc24_fail_command;
+       }
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
                    atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
@@ -618,6 +682,50 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha)
        return (return_status);
 }
 
+/*
+ * qla2x00_wait_for_reset_ready
+ *    Wait till the HBA is online after going through
+ *    <= MAX_RETRIES_OF_ISP_ABORT  or
+ *    finally HBA is disabled ie marked offline or flash
+ *    operations are in progress.
+ *
+ * Input:
+ *     ha - pointer to host adapter structure
+ *
+ * Note:
+ *    Does context switching-Release SPIN_LOCK
+ *    (if any) before calling this routine.
+ *
+ * Return:
+ *    Success (Adapter is online/no flash ops) : 0
+ *    Failed  (Adapter is offline/disabled/flash ops in progress) : 1
+ */
+int
+qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha)
+{
+       int             return_status;
+       unsigned long   wait_online;
+       struct qla_hw_data *ha = vha->hw;
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+
+       wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
+       while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) ||
+           test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) ||
+           test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) ||
+           ha->optrom_state != QLA_SWAITING ||
+           ha->dpc_active) && time_before(jiffies, wait_online))
+               msleep(1000);
+
+       if (base_vha->flags.online &&  ha->optrom_state == QLA_SWAITING)
+               return_status = QLA_SUCCESS;
+       else
+               return_status = QLA_FUNCTION_FAILED;
+
+       DEBUG2(printk("%s return_status=%d\n", __func__, return_status));
+
+       return return_status;
+}
+
 int
 qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha)
 {
@@ -739,7 +847,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 
                if (sp == NULL)
                        continue;
-               if (sp->ctx)
+               if ((sp->ctx) && !(sp->flags & SRB_FCP_CMND_DMA_VALID) &&
+                   !IS_PROT_IO(sp))
                        continue;
                if (sp->cmd != cmd)
                        continue;
@@ -805,7 +914,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
                sp = req->outstanding_cmds[cnt];
                if (!sp)
                        continue;
-               if (sp->ctx)
+               if ((sp->ctx) && !IS_PROT_IO(sp))
                        continue;
                if (vha->vp_idx != sp->fcport->vha->vp_idx)
                        continue;
@@ -834,6 +943,24 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
        return status;
 }
 
+void qla82xx_wait_for_pending_commands(scsi_qla_host_t *vha)
+{
+       int cnt;
+       srb_t *sp;
+       struct req_que *req = vha->req;
+
+       DEBUG2(qla_printk(KERN_INFO, vha->hw,
+               "Waiting for pending commands\n"));
+       for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+               sp = req->outstanding_cmds[cnt];
+               if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
+                       sp, WAIT_HOST) == QLA_SUCCESS) {
+                       DEBUG2(qla_printk(KERN_INFO, vha->hw,
+                               "Done wait for pending commands\n"));
+               }
+       }
+}
+
 static char *reset_errors[] = {
        "HBA not online",
        "HBA not ready",
@@ -1004,7 +1131,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
        qla_printk(KERN_INFO, ha,
            "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", vha->host_no, id, lun);
 
-       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS)
+       if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS)
                goto eh_host_reset_lock;
 
        /*
@@ -1020,11 +1147,19 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
                if (qla2x00_vp_abort_isp(vha))
                        goto eh_host_reset_lock;
        } else {
+               if (IS_QLA82XX(vha->hw)) {
+                       if (!qla82xx_fcoe_ctx_reset(vha)) {
+                               /* Ctx reset success */
+                               ret = SUCCESS;
+                               goto eh_host_reset_lock;
+                       }
+                       /* fall thru if ctx reset failed */
+               }
                if (ha->wq)
                        flush_workqueue(ha->wq);
 
                set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-               if (qla2x00_abort_isp(base_vha)) {
+               if (ha->isp_ops->abort_isp(base_vha)) {
                        clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
                        /* failed. schedule dpc to try */
                        set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
@@ -1064,7 +1199,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
        struct fc_port *fcport;
        struct qla_hw_data *ha = vha->hw;
 
-       if (ha->flags.enable_target_reset) {
+       if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) {
                list_for_each_entry(fcport, &vha->vp_fcports, list) {
                        if (fcport->port_type != FCT_TARGET)
                                continue;
@@ -1078,7 +1213,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
                }
        }
 
-       if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) {
+       if (ha->flags.enable_lip_full_login && !IS_QLA8XXX_TYPE(ha)) {
                ret = qla2x00_full_login_lip(vha);
                if (ret != QLA_SUCCESS) {
                        DEBUG2_3(printk("%s(%ld): failed: "
@@ -1125,23 +1260,28 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
                        sp = req->outstanding_cmds[cnt];
                        if (sp) {
                                req->outstanding_cmds[cnt] = NULL;
-                               if (!sp->ctx) {
+                               if (!sp->ctx ||
+                                       (sp->flags & SRB_FCP_CMND_DMA_VALID) ||
+                                       IS_PROT_IO(sp)) {
                                        sp->cmd->result = res;
                                        qla2x00_sp_compl(ha, sp);
                                } else {
                                        ctx = sp->ctx;
-                                       if (ctx->type == SRB_LOGIN_CMD || ctx->type == SRB_LOGOUT_CMD) {
-                                               del_timer_sync(&ctx->timer);
-                                               ctx->free(sp);
+                                       if (ctx->type == SRB_LOGIN_CMD ||
+                                           ctx->type == SRB_LOGOUT_CMD) {
+                                               ctx->u.iocb_cmd->free(sp);
                                        } else {
-                                               struct srb_bsg* sp_bsg = (struct srb_bsg*)sp->ctx;
-                                               if (sp_bsg->bsg_job->request->msgcode == FC_BSG_HST_CT)
+                                               struct fc_bsg_job *bsg_job =
+                                                   ctx->u.bsg_job;
+                                               if (bsg_job->request->msgcode
+                                                   == FC_BSG_HST_CT)
                                                        kfree(sp->fcport);
-                                               sp_bsg->bsg_job->req->errors = 0;
-                                               sp_bsg->bsg_job->reply->result = res;
-                                               sp_bsg->bsg_job->job_done(sp_bsg->bsg_job);
+                                               bsg_job->req->errors = 0;
+                                               bsg_job->reply->result = res;
+                                               bsg_job->job_done(bsg_job);
                                                kfree(sp->ctx);
-                                               mempool_free(sp, ha->srb_mempool);
+                                               mempool_free(sp,
+                                                       ha->srb_mempool);
                                        }
                                }
                        }
@@ -1379,6 +1519,7 @@ static struct isp_operations qla2100_isp_ops = {
        .write_optrom           = qla2x00_write_optrom_data,
        .get_flash_version      = qla2x00_get_flash_version,
        .start_scsi             = qla2x00_start_scsi,
+       .abort_isp              = qla2x00_abort_isp,
 };
 
 static struct isp_operations qla2300_isp_ops = {
@@ -1414,6 +1555,7 @@ static struct isp_operations qla2300_isp_ops = {
        .write_optrom           = qla2x00_write_optrom_data,
        .get_flash_version      = qla2x00_get_flash_version,
        .start_scsi             = qla2x00_start_scsi,
+       .abort_isp              = qla2x00_abort_isp,
 };
 
 static struct isp_operations qla24xx_isp_ops = {
@@ -1449,6 +1591,7 @@ static struct isp_operations qla24xx_isp_ops = {
        .write_optrom           = qla24xx_write_optrom_data,
        .get_flash_version      = qla24xx_get_flash_version,
        .start_scsi             = qla24xx_start_scsi,
+       .abort_isp              = qla2x00_abort_isp,
 };
 
 static struct isp_operations qla25xx_isp_ops = {
@@ -1483,7 +1626,8 @@ static struct isp_operations qla25xx_isp_ops = {
        .read_optrom            = qla25xx_read_optrom_data,
        .write_optrom           = qla24xx_write_optrom_data,
        .get_flash_version      = qla24xx_get_flash_version,
-       .start_scsi             = qla24xx_start_scsi,
+       .start_scsi             = qla24xx_dif_start_scsi,
+       .abort_isp              = qla2x00_abort_isp,
 };
 
 static struct isp_operations qla81xx_isp_ops = {
@@ -1519,6 +1663,43 @@ static struct isp_operations qla81xx_isp_ops = {
        .write_optrom           = qla24xx_write_optrom_data,
        .get_flash_version      = qla24xx_get_flash_version,
        .start_scsi             = qla24xx_start_scsi,
+       .abort_isp              = qla2x00_abort_isp,
+};
+
+static struct isp_operations qla82xx_isp_ops = {
+       .pci_config             = qla82xx_pci_config,
+       .reset_chip             = qla82xx_reset_chip,
+       .chip_diag              = qla24xx_chip_diag,
+       .config_rings           = qla82xx_config_rings,
+       .reset_adapter          = qla24xx_reset_adapter,
+       .nvram_config           = qla81xx_nvram_config,
+       .update_fw_options      = qla24xx_update_fw_options,
+       .load_risc              = qla82xx_load_risc,
+       .pci_info_str           = qla82xx_pci_info_str,
+       .fw_version_str         = qla24xx_fw_version_str,
+       .intr_handler           = qla82xx_intr_handler,
+       .enable_intrs           = qla82xx_enable_intrs,
+       .disable_intrs          = qla82xx_disable_intrs,
+       .abort_command          = qla24xx_abort_command,
+       .target_reset           = qla24xx_abort_target,
+       .lun_reset              = qla24xx_lun_reset,
+       .fabric_login           = qla24xx_login_fabric,
+       .fabric_logout          = qla24xx_fabric_logout,
+       .calc_req_entries       = NULL,
+       .build_iocbs            = NULL,
+       .prep_ms_iocb           = qla24xx_prep_ms_iocb,
+       .prep_ms_fdmi_iocb      = qla24xx_prep_ms_fdmi_iocb,
+       .read_nvram             = qla24xx_read_nvram_data,
+       .write_nvram            = qla24xx_write_nvram_data,
+       .fw_dump                = qla24xx_fw_dump,
+       .beacon_on              = qla24xx_beacon_on,
+       .beacon_off             = qla24xx_beacon_off,
+       .beacon_blink           = qla24xx_beacon_blink,
+       .read_optrom            = qla82xx_read_optrom_data,
+       .write_optrom           = qla82xx_write_optrom_data,
+       .get_flash_version      = qla24xx_get_flash_version,
+       .start_scsi             = qla82xx_start_scsi,
+       .abort_isp              = qla82xx_abort_isp,
 };
 
 static inline void
@@ -1607,10 +1788,22 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->device_type |= DT_IIDMA;
                ha->fw_srisc_address = RISC_START_ADDRESS_2400;
                break;
+       case PCI_DEVICE_ID_QLOGIC_ISP8021:
+               ha->device_type |= DT_ISP8021;
+               ha->device_type |= DT_ZIO_SUPPORTED;
+               ha->device_type |= DT_FWI2;
+               ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+               /* Initialize 82XX ISP flags */
+               qla82xx_init_flags(ha);
+               break;
        }
 
-       /* Get adapter physical port no from interrupt pin register. */
-       pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+       if (IS_QLA82XX(ha))
+               ha->port_no = !(ha->portnum & 1);
+       else
+               /* Get adapter physical port no from interrupt pin register. */
+               pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
+
        if (ha->port_no & 1)
                ha->flags.port0 = 1;
        else
@@ -1624,6 +1817,9 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
        uint16_t msix;
        int cpus;
 
+       if (IS_QLA82XX(ha))
+               return qla82xx_iospace_config(ha);
+
        if (pci_request_selected_regions(ha->pdev, ha->bars,
            QLA2XXX_DRIVER_NAME)) {
                qla_printk(KERN_WARNING, ha,
@@ -1767,7 +1963,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 ||
-           pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) {
+           pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 ||
+           pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021) {
                bars = pci_select_bars(pdev, IORESOURCE_MEM);
                mem_only = 1;
        }
@@ -1897,6 +2094,19 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
                ha->nvram_conf_off = ~0;
                ha->nvram_data_off = ~0;
+       } else if (IS_QLA82XX(ha)) {
+               ha->mbx_count = MAILBOX_REGISTER_COUNT;
+               req_length = REQUEST_ENTRY_CNT_82XX;
+               rsp_length = RESPONSE_ENTRY_CNT_82XX;
+               ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
+               ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
+               ha->gid_list_info_size = 8;
+               ha->optrom_size = OPTROM_SIZE_82XX;
+               ha->isp_ops = &qla82xx_isp_ops;
+               ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+               ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
+               ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
+               ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
        }
 
        mutex_init(&ha->vport_lock);
@@ -1969,6 +2179,7 @@ que_init:
                " pointers\n");
                goto probe_init_failed;
        }
+
        ha->rsp_q_map[0] = rsp;
        ha->req_q_map[0] = req;
        rsp->req = req;
@@ -1987,6 +2198,12 @@ que_init:
                rsp->rsp_q_out =  &ha->mqiobase->isp25mq.rsp_q_out;
        }
 
+       if (IS_QLA82XX(ha)) {
+               req->req_q_out = &ha->iobase->isp82.req_q_out[0];
+               rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0];
+               rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0];
+       }
+
        if (qla2x00_initialize_adapter(base_vha)) {
                qla_printk(KERN_WARNING, ha,
                    "Failed to initialize adapter\n");
@@ -1995,6 +2212,14 @@ que_init:
                    "Adapter flags %x.\n",
                    base_vha->host_no, base_vha->device_flags));
 
+               if (IS_QLA82XX(ha)) {
+                       qla82xx_idc_lock(ha);
+                       qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                               QLA82XX_DEV_FAILED);
+                       qla82xx_idc_unlock(ha);
+                       qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+               }
+
                ret = -ENODEV;
                goto probe_failed;
        }
@@ -2033,6 +2258,24 @@ skip_dpc:
        DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
            base_vha->host_no, ha));
 
+       if (IS_QLA25XX(ha) && ql2xenabledif) {
+               if (ha->fw_attributes & BIT_4) {
+                       base_vha->flags.difdix_supported = 1;
+                       DEBUG18(qla_printk(KERN_INFO, ha,
+                           "Registering for DIF/DIX type 1 and 3"
+                           " protection.\n"));
+                       scsi_host_set_prot(host,
+                           SHOST_DIF_TYPE1_PROTECTION
+                           | SHOST_DIF_TYPE3_PROTECTION
+                           | SHOST_DIX_TYPE1_PROTECTION
+                           | SHOST_DIX_TYPE3_PROTECTION);
+                       scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC);
+               } else
+                       base_vha->flags.difdix_supported = 0;
+       }
+
+       ha->isp_ops->enable_intrs(ha);
+
        ret = scsi_add_host(host, &pdev->dev);
        if (ret)
                goto probe_failed;
@@ -2040,8 +2283,6 @@ skip_dpc:
        base_vha->flags.init_done = 1;
        base_vha->flags.online = 1;
 
-       ha->isp_ops->enable_intrs(ha);
-
        scsi_scan_host(host);
 
        qla2x00_alloc_sysfs_attr(base_vha);
@@ -2083,9 +2324,17 @@ probe_failed:
        scsi_host_put(base_vha->host);
 
 probe_hw_failed:
-       if (ha->iobase)
-               iounmap(ha->iobase);
-
+       if (IS_QLA82XX(ha)) {
+               qla82xx_idc_lock(ha);
+               qla82xx_clear_drv_active(ha);
+               qla82xx_idc_unlock(ha);
+               iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+               if (!ql2xdbwr)
+                       iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+       } else {
+               if (ha->iobase)
+                       iounmap(ha->iobase);
+       }
        pci_release_selected_regions(ha->pdev, ha->bars);
        kfree(ha);
        ha = NULL;
@@ -2152,11 +2401,17 @@ qla2x00_remove_one(struct pci_dev *pdev)
 
        scsi_host_put(base_vha->host);
 
-       if (ha->iobase)
-               iounmap(ha->iobase);
+       if (IS_QLA82XX(ha)) {
+               iounmap((device_reg_t __iomem *)ha->nx_pcibase);
+               if (!ql2xdbwr)
+                       iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
+       } else {
+               if (ha->iobase)
+                       iounmap(ha->iobase);
 
-       if (ha->mqiobase)
-               iounmap(ha->mqiobase);
+               if (ha->mqiobase)
+                       iounmap(ha->mqiobase);
+       }
 
        pci_release_selected_regions(ha->pdev, ha->bars);
        kfree(ha);
@@ -2205,8 +2460,10 @@ qla2x00_free_device(scsi_qla_host_t *vha)
        vha->flags.online = 0;
 
        /* turn-off interrupts on the card */
-       if (ha->interrupts_on)
+       if (ha->interrupts_on) {
+               vha->flags.init_done = 0;
                ha->isp_ops->disable_intrs(ha);
+       }
 
        qla2x00_free_irqs(vha);
 
@@ -2351,10 +2608,25 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
        if (!ha->srb_mempool)
                goto fail_free_gid_list;
 
+       if (IS_QLA82XX(ha)) {
+               /* Allocate cache for CT6 Ctx. */
+               if (!ctx_cachep) {
+                       ctx_cachep = kmem_cache_create("qla2xxx_ctx",
+                               sizeof(struct ct6_dsd), 0,
+                               SLAB_HWCACHE_ALIGN, NULL);
+                       if (!ctx_cachep)
+                               goto fail_free_gid_list;
+               }
+               ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ,
+                       ctx_cachep);
+               if (!ha->ctx_mempool)
+                       goto fail_free_srb_mempool;
+       }
+
        /* Get memory for cached NVRAM */
        ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
        if (!ha->nvram)
-               goto fail_free_srb_mempool;
+               goto fail_free_ctx_mempool;
 
        snprintf(name, sizeof(name), "%s_%d", QLA2XXX_DRIVER_NAME,
                ha->pdev->device);
@@ -2363,6 +2635,24 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
        if (!ha->s_dma_pool)
                goto fail_free_nvram;
 
+       if (IS_QLA82XX(ha) || ql2xenabledif) {
+               ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+                       DSD_LIST_DMA_POOL_SIZE, 8, 0);
+               if (!ha->dl_dma_pool) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Memory Allocation failed - dl_dma_pool\n");
+                       goto fail_s_dma_pool;
+               }
+
+               ha->fcp_cmnd_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+                       FCP_CMND_DMA_POOL_SIZE, 8, 0);
+               if (!ha->fcp_cmnd_dma_pool) {
+                       qla_printk(KERN_WARNING, ha,
+                           "Memory Allocation failed - fcp_cmnd_dma_pool\n");
+                       goto fail_dl_dma_pool;
+               }
+       }
+
        /* Allocate memory for SNS commands */
        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
        /* Get consistent memory allocated for SNS commands */
@@ -2429,16 +2719,28 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                ha->npiv_info = NULL;
 
        /* Get consistent memory allocated for EX-INIT-CB. */
-       if (IS_QLA81XX(ha)) {
+       if (IS_QLA8XXX_TYPE(ha)) {
                ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
                    &ha->ex_init_cb_dma);
                if (!ha->ex_init_cb)
                        goto fail_ex_init_cb;
        }
 
+       INIT_LIST_HEAD(&ha->gbl_dsd_list);
+
+       /* Get consistent memory allocated for Async Port-Database. */
+       if (!IS_FWI2_CAPABLE(ha)) {
+               ha->async_pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+                       &ha->async_pd_dma);
+               if (!ha->async_pd)
+                       goto fail_async_pd;
+       }
+
        INIT_LIST_HEAD(&ha->vp_list);
        return 1;
 
+fail_async_pd:
+       dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
 fail_ex_init_cb:
        kfree(ha->npiv_info);
 fail_npiv_info:
@@ -2465,11 +2767,24 @@ fail_free_ms_iocb:
        ha->ms_iocb = NULL;
        ha->ms_iocb_dma = 0;
 fail_dma_pool:
+       if (IS_QLA82XX(ha) || ql2xenabledif) {
+               dma_pool_destroy(ha->fcp_cmnd_dma_pool);
+               ha->fcp_cmnd_dma_pool = NULL;
+       }
+fail_dl_dma_pool:
+       if (IS_QLA82XX(ha) || ql2xenabledif) {
+               dma_pool_destroy(ha->dl_dma_pool);
+               ha->dl_dma_pool = NULL;
+       }
+fail_s_dma_pool:
        dma_pool_destroy(ha->s_dma_pool);
        ha->s_dma_pool = NULL;
 fail_free_nvram:
        kfree(ha->nvram);
        ha->nvram = NULL;
+fail_free_ctx_mempool:
+       mempool_destroy(ha->ctx_mempool);
+       ha->ctx_mempool = NULL;
 fail_free_srb_mempool:
        mempool_destroy(ha->srb_mempool);
        ha->srb_mempool = NULL;
@@ -2538,7 +2853,11 @@ qla2x00_mem_free(struct qla_hw_data *ha)
                dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
 
        if (ha->ex_init_cb)
-               dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
+               dma_pool_free(ha->s_dma_pool,
+                       ha->ex_init_cb, ha->ex_init_cb_dma);
+
+       if (ha->async_pd)
+               dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
 
        if (ha->s_dma_pool)
                dma_pool_destroy(ha->s_dma_pool);
@@ -2547,14 +2866,39 @@ qla2x00_mem_free(struct qla_hw_data *ha)
                dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
                ha->gid_list_dma);
 
+       if (IS_QLA82XX(ha)) {
+               if (!list_empty(&ha->gbl_dsd_list)) {
+                       struct dsd_dma *dsd_ptr, *tdsd_ptr;
+
+                       /* clean up allocated prev pool */
+                       list_for_each_entry_safe(dsd_ptr,
+                               tdsd_ptr, &ha->gbl_dsd_list, list) {
+                               dma_pool_free(ha->dl_dma_pool,
+                               dsd_ptr->dsd_addr, dsd_ptr->dsd_list_dma);
+                               list_del(&dsd_ptr->list);
+                               kfree(dsd_ptr);
+                       }
+               }
+       }
+
+       if (ha->dl_dma_pool)
+               dma_pool_destroy(ha->dl_dma_pool);
+
+       if (ha->fcp_cmnd_dma_pool)
+               dma_pool_destroy(ha->fcp_cmnd_dma_pool);
+
+       if (ha->ctx_mempool)
+               mempool_destroy(ha->ctx_mempool);
+
        if (ha->init_cb)
                dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
-               ha->init_cb, ha->init_cb_dma);
+                       ha->init_cb, ha->init_cb_dma);
        vfree(ha->optrom_buffer);
        kfree(ha->nvram);
        kfree(ha->npiv_info);
 
        ha->srb_mempool = NULL;
+       ha->ctx_mempool = NULL;
        ha->eft = NULL;
        ha->eft_dma = 0;
        ha->sns_cmd = NULL;
@@ -2567,8 +2911,12 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        ha->init_cb_dma = 0;
        ha->ex_init_cb = NULL;
        ha->ex_init_cb_dma = 0;
+       ha->async_pd = NULL;
+       ha->async_pd_dma = 0;
 
        ha->s_dma_pool = NULL;
+       ha->dl_dma_pool = NULL;
+       ha->fcp_cmnd_dma_pool = NULL;
 
        ha->gid_list = NULL;
        ha->gid_list_dma = 0;
@@ -2691,6 +3039,8 @@ qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN);
 qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE);
 qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT);
 qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE);
+qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC);
+qla2x00_post_async_work(adisc_done, QLA_EVT_ASYNC_ADISC_DONE);
 
 int
 qla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code)
@@ -2760,6 +3110,14 @@ qla2x00_do_work(struct scsi_qla_host *vha)
                        qla2x00_async_logout_done(vha, e->u.logio.fcport,
                            e->u.logio.data);
                        break;
+               case QLA_EVT_ASYNC_ADISC:
+                       qla2x00_async_adisc(vha, e->u.logio.fcport,
+                           e->u.logio.data);
+                       break;
+               case QLA_EVT_ASYNC_ADISC_DONE:
+                       qla2x00_async_adisc_done(vha, e->u.logio.fcport,
+                           e->u.logio.data);
+                       break;
                case QLA_EVT_UEVENT:
                        qla2x00_uevent_emit(vha, e->u.uevent.code);
                        break;
@@ -2785,9 +3143,8 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
         * If the port is not ONLINE then try to login
         * to it if we haven't run out of retries.
         */
-               if (atomic_read(&fcport->state) !=
-                       FCS_ONLINE && fcport->login_retry) {
-
+               if (atomic_read(&fcport->state) != FCS_ONLINE &&
+                   fcport->login_retry && !(fcport->flags & FCF_ASYNC_SENT)) {
                        fcport->login_retry--;
                        if (fcport->flags & FCF_FABRIC_DEVICE) {
                                if (fcport->flags & FCF_FCP2_DEVICE)
@@ -2798,6 +3155,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
                                                        fcport->d_id.b.al_pa);
 
                                if (IS_ALOGIO_CAPABLE(ha)) {
+                                       fcport->flags |= FCF_ASYNC_SENT;
                                        data[0] = 0;
                                        data[1] = QLA_LOGIO_LOGIN_RETRIED;
                                        status = qla2x00_post_async_login_work(
@@ -2896,6 +3254,45 @@ qla2x00_do_dpc(void *data)
 
                qla2x00_do_work(base_vha);
 
+               if (IS_QLA82XX(ha)) {
+                       if (test_and_clear_bit(ISP_UNRECOVERABLE,
+                               &base_vha->dpc_flags)) {
+                               qla82xx_idc_lock(ha);
+                               qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+                                       QLA82XX_DEV_FAILED);
+                               qla82xx_idc_unlock(ha);
+                               qla_printk(KERN_INFO, ha,
+                                       "HW State: FAILED\n");
+                               qla82xx_device_state_handler(base_vha);
+                               continue;
+                       }
+
+                       if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED,
+                               &base_vha->dpc_flags)) {
+
+                               DEBUG(printk(KERN_INFO
+                                       "scsi(%ld): dpc: sched "
+                                       "qla82xx_fcoe_ctx_reset ha = %p\n",
+                                       base_vha->host_no, ha));
+                               if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
+                                       &base_vha->dpc_flags))) {
+                                       if (qla82xx_fcoe_ctx_reset(base_vha)) {
+                                               /* FCoE-ctx reset failed.
+                                                * Escalate to chip-reset
+                                                */
+                                               set_bit(ISP_ABORT_NEEDED,
+                                                       &base_vha->dpc_flags);
+                                       }
+                                       clear_bit(ABORT_ISP_ACTIVE,
+                                               &base_vha->dpc_flags);
+                               }
+
+                               DEBUG(printk("scsi(%ld): dpc:"
+                                       " qla82xx_fcoe_ctx_reset end\n",
+                                       base_vha->host_no));
+                       }
+               }
+
                if (test_and_clear_bit(ISP_ABORT_NEEDED,
                                                &base_vha->dpc_flags)) {
 
@@ -2905,7 +3302,7 @@ qla2x00_do_dpc(void *data)
                        if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
                            &base_vha->dpc_flags))) {
 
-                               if (qla2x00_abort_isp(base_vha)) {
+                               if (ha->isp_ops->abort_isp(base_vha)) {
                                        /* failed. retry later */
                                        set_bit(ISP_ABORT_NEEDED,
                                            &base_vha->dpc_flags);
@@ -3038,11 +3435,31 @@ static void
 qla2x00_sp_free_dma(srb_t *sp)
 {
        struct scsi_cmnd *cmd = sp->cmd;
+       struct qla_hw_data *ha = sp->fcport->vha->hw;
 
        if (sp->flags & SRB_DMA_VALID) {
                scsi_dma_unmap(cmd);
                sp->flags &= ~SRB_DMA_VALID;
        }
+
+       if (sp->flags & SRB_CRC_PROT_DMA_VALID) {
+               dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd),
+                   scsi_prot_sg_count(cmd), cmd->sc_data_direction);
+               sp->flags &= ~SRB_CRC_PROT_DMA_VALID;
+       }
+
+       if (sp->flags & SRB_CRC_CTX_DSD_VALID) {
+               /* List assured to be having elements */
+               qla2x00_clean_dsd_pool(ha, sp);
+               sp->flags &= ~SRB_CRC_CTX_DSD_VALID;
+       }
+
+       if (sp->flags & SRB_CRC_CTX_DMA_VALID) {
+               dma_pool_free(ha->dl_dma_pool, sp->ctx,
+                   ((struct crc_context *)sp->ctx)->crc_ctx_dma);
+               sp->flags &= ~SRB_CRC_CTX_DMA_VALID;
+       }
+
        CMD_SP(cmd) = NULL;
 }
 
@@ -3053,8 +3470,18 @@ qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
 
        qla2x00_sp_free_dma(sp);
 
-       mempool_free(sp, ha->srb_mempool);
+       if (sp->flags & SRB_FCP_CMND_DMA_VALID) {
+               struct ct6_dsd *ctx = sp->ctx;
+               dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd,
+                       ctx->fcp_cmnd_dma);
+               list_splice(&ctx->dsd_list, &ha->gbl_dsd_list);
+               ha->gbl_dsd_inuse -= ctx->dsd_use_cnt;
+               ha->gbl_dsd_avail += ctx->dsd_use_cnt;
+               mempool_free(sp->ctx, ha->ctx_mempool);
+               sp->ctx = NULL;
+       }
 
+       mempool_free(sp, ha->srb_mempool);
        cmd->scsi_done(cmd);
 }
 
@@ -3079,6 +3506,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req;
 
+       if (IS_QLA82XX(ha))
+               qla82xx_watchdog(vha);
+
        /* Hardware read to raise pending EEH errors during mailbox waits. */
        if (!pci_channel_offline(ha->pdev))
                pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
@@ -3143,7 +3573,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
                                        sp = req->outstanding_cmds[index];
                                        if (!sp)
                                                continue;
-                                       if (sp->ctx)
+                                       if (sp->ctx && !IS_PROT_IO(sp))
                                                continue;
                                        sfcp = sp->fcport;
                                        if (!(sfcp->flags & FCF_FCP2_DEVICE))
@@ -3193,6 +3623,8 @@ qla2x00_timer(scsi_qla_host_t *vha)
            start_dpc ||
            test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) ||
            test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags) ||
+           test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) ||
+           test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
            test_bit(VP_DPC_NEEDED, &vha->dpc_flags) ||
            test_bit(RELOGIN_NEEDED, &vha->dpc_flags)))
                qla2xxx_wake_dpc(vha);
@@ -3202,7 +3634,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
 
 /* Firmware interface routines. */
 
-#define FW_BLOBS       7
+#define FW_BLOBS       8
 #define FW_ISP21XX     0
 #define FW_ISP22XX     1
 #define FW_ISP2300     2
@@ -3210,6 +3642,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
 #define FW_ISP24XX     4
 #define FW_ISP25XX     5
 #define FW_ISP81XX     6
+#define FW_ISP82XX     7
 
 #define FW_FILE_ISP21XX        "ql2100_fw.bin"
 #define FW_FILE_ISP22XX        "ql2200_fw.bin"
@@ -3218,6 +3651,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
 #define FW_FILE_ISP24XX        "ql2400_fw.bin"
 #define FW_FILE_ISP25XX        "ql2500_fw.bin"
 #define FW_FILE_ISP81XX        "ql8100_fw.bin"
+#define FW_FILE_ISP82XX        "ql8200_fw.bin"
 
 static DEFINE_MUTEX(qla_fw_lock);
 
@@ -3229,6 +3663,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
        { .name = FW_FILE_ISP24XX, },
        { .name = FW_FILE_ISP25XX, },
        { .name = FW_FILE_ISP81XX, },
+       { .name = FW_FILE_ISP82XX, },
 };
 
 struct fw_blob *
@@ -3252,6 +3687,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
                blob = &qla_fw_blobs[FW_ISP25XX];
        } else if (IS_QLA81XX(ha)) {
                blob = &qla_fw_blobs[FW_ISP81XX];
+       } else if (IS_QLA82XX(ha)) {
+               blob = &qla_fw_blobs[FW_ISP82XX];
        }
 
        mutex_lock(&qla_fw_lock);
@@ -3392,11 +3829,10 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
                msleep(1000);
 
        set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
-       if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS)
+       if (ha->isp_ops->abort_isp(base_vha) == QLA_SUCCESS)
                ret =  PCI_ERS_RESULT_RECOVERED;
        clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 
-       pci_cleanup_aer_uncorrect_error_status(pdev);
 
        DEBUG17(qla_printk(KERN_WARNING, ha,
            "slot_reset-return:ret=%x\n", ret));
@@ -3420,6 +3856,8 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
                    "from slot/link_reset");
        }
 
+       pci_cleanup_aer_uncorrect_error_status(pdev);
+
        ha->flags.eeh_busy = 0;
 }
 
@@ -3445,6 +3883,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
        { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) },
+       { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },
        { 0 },
 };
 MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -3460,6 +3899,10 @@ static struct pci_driver qla2xxx_pci_driver = {
        .err_handler    = &qla2xxx_err_handler,
 };
 
+static struct file_operations apidev_fops = {
+       .owner = THIS_MODULE,
+};
+
 /**
  * qla2x00_module_init - Module initialization.
  **/
@@ -3488,6 +3931,13 @@ qla2x00_module_init(void)
                kmem_cache_destroy(srb_cachep);
                return -ENODEV;
        }
+
+       apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops);
+       if (apidev_major < 0) {
+               printk(KERN_WARNING "qla2xxx: Unable to register char device "
+                   "%s\n", QLA2XXX_APIDEV);
+       }
+
        qla2xxx_transport_vport_template =
            fc_attach_transport(&qla2xxx_transport_vport_functions);
        if (!qla2xxx_transport_vport_template) {
@@ -3513,9 +3963,12 @@ qla2x00_module_init(void)
 static void __exit
 qla2x00_module_exit(void)
 {
+       unregister_chrdev(apidev_major, QLA2XXX_APIDEV);
        pci_unregister_driver(&qla2xxx_pci_driver);
        qla2x00_release_firmware();
        kmem_cache_destroy(srb_cachep);
+       if (ctx_cachep)
+               kmem_cache_destroy(ctx_cachep);
        fc_release_transport(qla2xxx_transport_template);
        fc_release_transport(qla2xxx_transport_vport_template);
 }
index 8b3de4e..de92504 100644 (file)
@@ -423,9 +423,6 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
 /* Flash Manipulation Routines                                               */
 /*****************************************************************************/
 
-#define OPTROM_BURST_SIZE      0x1000
-#define OPTROM_BURST_DWORDS    (OPTROM_BURST_SIZE / 4)
-
 static inline uint32_t
 flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr)
 {
@@ -565,6 +562,10 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
                *start = FA_FLASH_LAYOUT_ADDR;
        else if (IS_QLA81XX(ha))
                *start = FA_FLASH_LAYOUT_ADDR_81;
+       else if (IS_QLA82XX(ha)) {
+               *start = FA_FLASH_LAYOUT_ADDR_82;
+               goto end;
+       }
        /* Begin with first PCI expansion ROM header. */
        buf = (uint8_t *)req->ring;
        dcode = (uint32_t *)req->ring;
@@ -648,6 +649,12 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
        const uint32_t def_npiv_conf1[] =
                { FA_NPIV_CONF1_ADDR_24, FA_NPIV_CONF1_ADDR,
                        FA_NPIV_CONF1_ADDR_81 };
+       const uint32_t fcp_prio_cfg0[] =
+               { FA_FCP_PRIO0_ADDR, FA_FCP_PRIO0_ADDR_25,
+                       0 };
+       const uint32_t fcp_prio_cfg1[] =
+               { FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25,
+                       0 };
        uint32_t def;
        uint16_t *wptr;
        uint16_t cnt, chksum;
@@ -703,10 +710,14 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
                        break;
                case FLT_REG_VPD_0:
                        ha->flt_region_vpd_nvram = start;
+                       if (IS_QLA82XX(ha))
+                               break;
                        if (ha->flags.port0)
                                ha->flt_region_vpd = start;
                        break;
                case FLT_REG_VPD_1:
+                       if (IS_QLA82XX(ha))
+                               break;
                        if (!ha->flags.port0)
                                ha->flt_region_vpd = start;
                        break;
@@ -732,6 +743,29 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
                case FLT_REG_GOLD_FW:
                        ha->flt_region_gold_fw = start;
                        break;
+               case FLT_REG_FCP_PRIO_0:
+                       if (ha->flags.port0)
+                               ha->flt_region_fcp_prio = start;
+                       break;
+               case FLT_REG_FCP_PRIO_1:
+                       if (!ha->flags.port0)
+                               ha->flt_region_fcp_prio = start;
+                       break;
+               case FLT_REG_BOOT_CODE_82XX:
+                       ha->flt_region_boot = start;
+                       break;
+               case FLT_REG_FW_82XX:
+                       ha->flt_region_fw = start;
+                       break;
+               case FLT_REG_GOLD_FW_82XX:
+                       ha->flt_region_gold_fw = start;
+                       break;
+               case FLT_REG_BOOTLOAD_82XX:
+                       ha->flt_region_bootload = start;
+                       break;
+               case FLT_REG_VPD_82XX:
+                       ha->flt_region_vpd = start;
+                       break;
                }
        }
        goto done;
@@ -750,12 +784,14 @@ no_flash_data:
        ha->flt_region_boot = def_boot[def];
        ha->flt_region_vpd_nvram = def_vpd_nvram[def];
        ha->flt_region_vpd = ha->flags.port0 ?
-           def_vpd0[def]: def_vpd1[def];
+           def_vpd0[def] : def_vpd1[def];
        ha->flt_region_nvram = ha->flags.port0 ?
-           def_nvram0[def]: def_nvram1[def];
+           def_nvram0[def] : def_nvram1[def];
        ha->flt_region_fdt = def_fdt[def];
        ha->flt_region_npiv_conf = ha->flags.port0 ?
-           def_npiv_conf0[def]: def_npiv_conf1[def];
+           def_npiv_conf0[def] : def_npiv_conf1[def];
+       ha->flt_region_fcp_prio = ha->flags.port0 ?
+           fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
 done:
        DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
            "vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x "
@@ -775,7 +811,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
        uint16_t *wptr;
        struct qla_fdt_layout *fdt;
        uint8_t man_id, flash_id;
-       uint16_t mid, fid;
+       uint16_t mid = 0, fid = 0;
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
 
@@ -816,6 +852,10 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
        goto done;
 no_flash_data:
        loc = locations[0];
+       if (IS_QLA82XX(ha)) {
+               ha->fdt_block_size = FLASH_BLK_SIZE_64K;
+               goto done;
+       }
        qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
        mid = man_id;
        fid = flash_id;
@@ -853,6 +893,31 @@ done:
            ha->fdt_block_size));
 }
 
+static void
+qla2xxx_get_idc_param(scsi_qla_host_t *vha)
+{
+#define QLA82XX_IDC_PARAM_ADDR       0x003e885c
+       uint32_t *wptr;
+       struct qla_hw_data *ha = vha->hw;
+       struct req_que *req = ha->req_q_map[0];
+
+       if (!IS_QLA82XX(ha))
+               return;
+
+       wptr = (uint32_t *)req->ring;
+       ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring,
+               QLA82XX_IDC_PARAM_ADDR , 8);
+
+       if (*wptr == __constant_cpu_to_le32(0xffffffff)) {
+               ha->nx_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
+               ha->nx_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
+       } else {
+               ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
+               ha->nx_reset_timeout = le32_to_cpu(*wptr);
+       }
+       return;
+}
+
 int
 qla2xxx_get_flash_info(scsi_qla_host_t *vha)
 {
@@ -860,7 +925,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
        uint32_t flt_addr;
        struct qla_hw_data *ha = vha->hw;
 
-       if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha))
+       if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA8XXX_TYPE(ha))
                return QLA_SUCCESS;
 
        ret = qla2xxx_find_flt_start(vha, &flt_addr);
@@ -869,6 +934,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
 
        qla2xxx_get_flt_info(vha, flt_addr);
        qla2xxx_get_fdt_info(vha);
+       qla2xxx_get_idc_param(vha);
 
        return QLA_SUCCESS;
 }
@@ -885,7 +951,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
        struct qla_npiv_entry *entry;
        struct qla_hw_data *ha = vha->hw;
 
-       if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha))
+       if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA8XXX_TYPE(ha))
                return;
 
        ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
@@ -1178,6 +1244,9 @@ qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
        uint32_t *dwptr;
        struct qla_hw_data *ha = vha->hw;
 
+       if (IS_QLA82XX(ha))
+               return  buf;
+
        /* Dword reads to flash. */
        dwptr = (uint32_t *)buf;
        for (i = 0; i < bytes >> 2; i++, naddr++)
@@ -1233,6 +1302,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
 
        ret = QLA_SUCCESS;
 
+       if (IS_QLA82XX(ha))
+               return ret;
+
        /* Enable flash write. */
        WRT_REG_DWORD(&reg->ctrl_status,
            RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
@@ -1344,6 +1416,9 @@ qla2x00_beacon_blink(struct scsi_qla_host *vha)
        struct qla_hw_data *ha = vha->hw;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
+       if (IS_QLA82XX(ha))
+               return;
+
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
        /* Save the Original GPIOE. */
@@ -1525,6 +1600,9 @@ qla24xx_beacon_on(struct scsi_qla_host *vha)
        struct qla_hw_data *ha = vha->hw;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
+       if (IS_QLA82XX(ha))
+               return QLA_SUCCESS;
+
        if (ha->beacon_blink_led == 0) {
                /* Enable firmware for update */
                ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL;
@@ -1567,6 +1645,9 @@ qla24xx_beacon_off(struct scsi_qla_host *vha)
        struct qla_hw_data *ha = vha->hw;
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
+       if (IS_QLA82XX(ha))
+               return QLA_SUCCESS;
+
        ha->beacon_blink_led = 0;
        ha->beacon_color_state = QLA_LED_ALL_ON;
 
@@ -2576,6 +2657,9 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
        int i;
        struct qla_hw_data *ha = vha->hw;
 
+       if (IS_QLA82XX(ha))
+               return ret;
+
        if (!mbuf)
                return QLA_FUNCTION_FAILED;
 
@@ -2722,3 +2806,50 @@ qla2xxx_get_vpd_field(scsi_qla_host_t *vha, char *key, char *str, size_t size)
 
        return 0;
 }
+
+int
+qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
+{
+       int len, max_len;
+       uint32_t fcp_prio_addr;
+       struct qla_hw_data *ha = vha->hw;
+
+       if (!ha->fcp_prio_cfg) {
+               ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
+               if (!ha->fcp_prio_cfg) {
+                       qla_printk(KERN_WARNING, ha,
+                       "Unable to allocate memory for fcp priority data "
+                                       "(%x).\n", FCP_PRIO_CFG_SIZE);
+                       return QLA_FUNCTION_FAILED;
+               }
+       }
+       memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE);
+
+       fcp_prio_addr = ha->flt_region_fcp_prio;
+
+       /* first read the fcp priority data header from flash */
+       ha->isp_ops->read_optrom(vha, (uint8_t *)ha->fcp_prio_cfg,
+                       fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE);
+
+       if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 0))
+               goto fail;
+
+       /* read remaining FCP CMD config data from flash */
+       fcp_prio_addr += (FCP_PRIO_CFG_HDR_SIZE >> 2);
+       len = ha->fcp_prio_cfg->num_entries * FCP_PRIO_CFG_ENTRY_SIZE;
+       max_len = FCP_PRIO_CFG_SIZE - FCP_PRIO_CFG_HDR_SIZE;
+
+       ha->isp_ops->read_optrom(vha, (uint8_t *)&ha->fcp_prio_cfg->entry[0],
+                       fcp_prio_addr << 2, (len < max_len ? len : max_len));
+
+       /* revalidate the entire FCP priority config data, including entries */
+       if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 1))
+               goto fail;
+
+       ha->flags.fcp_prio_enabled = 1;
+       return QLA_SUCCESS;
+fail:
+       vfree(ha->fcp_prio_cfg);
+       ha->fcp_prio_cfg = NULL;
+       return QLA_FUNCTION_FAILED;
+}
index 81b5f29..4288026 100644 (file)
  */
 #define MAC_ADDR_LEN                   6       /* in bytes */
 #define IP_ADDR_LEN                    4       /* in bytes */
+#define IPv6_ADDR_LEN                  16      /* IPv6 address size */
 #define DRIVER_NAME                    "qla4xxx"
 
 #define MAX_LINKED_CMDS_PER_LUN                3
 
 #define MAX_RESET_HA_RETRIES           2
 
+#define CMD_SP(Cmnd)                   ((Cmnd)->SCp.ptr)
+
 /*
  * SCSI Request Block structure         (srb)  that is placed
  * on cmd->SCp location of every I/O    [We have 22 bytes available]
@@ -169,7 +172,7 @@ struct srb {
 
        struct scsi_cmnd *cmd;  /* (4) SCSI command block */
        dma_addr_t dma_handle;  /* (4) for unmap of single transfers */
-       atomic_t ref_count;     /* reference count for this srb */
+       struct kref srb_ref;    /* reference count for this srb */
        uint32_t fw_ddb_index;
        uint8_t err_id;         /* error id */
 #define SRB_ERR_PORT      1    /* Request failed because "port down" */
@@ -220,7 +223,7 @@ struct ddb_entry {
 
        uint16_t os_target_id;  /* Target ID */
        uint16_t fw_ddb_index;  /* DDB firmware index */
-       uint8_t reserved[2];
+       uint16_t options;
        uint32_t fw_ddb_device_state; /* F/W Device State  -- see ql4_fw.h */
 
        uint32_t CmdSn;
@@ -245,10 +248,18 @@ struct ddb_entry {
 
        uint16_t port;
        uint32_t tpgt;
-       uint8_t ip_addr[ISCSI_IPADDR_SIZE];
+       uint8_t ip_addr[IP_ADDR_LEN];
        uint8_t iscsi_name[ISCSI_NAME_SIZE];    /* 72 x48 */
        uint8_t iscsi_alias[0x20];
        uint8_t isid[6];
+       uint16_t iscsi_max_burst_len;
+       uint16_t iscsi_max_outsnd_r2t;
+       uint16_t iscsi_first_burst_len;
+       uint16_t iscsi_max_rcv_data_seg_len;
+       uint16_t iscsi_max_snd_data_seg_len;
+
+       struct in6_addr remote_ipv6_addr;
+       struct in6_addr link_local_ipv6_addr;
 };
 
 /*
@@ -301,6 +312,7 @@ struct scsi_qla_host {
 #define DPC_ISNS_RESTART               7 /* 0x00000080 */
 #define DPC_AEN                                9 /* 0x00000200 */
 #define DPC_GET_DHCP_IP_ADDR           15 /* 0x00008000 */
+#define DPC_LINK_CHANGED               18 /* 0x00040000 */
 
        struct Scsi_Host *host; /* pointer to host data */
        uint32_t tot_ddbs;
@@ -320,8 +332,7 @@ struct scsi_qla_host {
 #define MIN_IOBASE_LEN         0x100
 
        uint16_t req_q_count;
-       uint8_t marker_needed;
-       uint8_t rsvd1;
+       uint8_t rsvd1[2];
 
        unsigned long host_no;
 
@@ -441,8 +452,35 @@ struct scsi_qla_host {
 
        /* Saved srb for status continuation entry processing */
        struct srb *status_srb;
+
+       /* IPv6 support info from InitFW */
+       uint8_t acb_version;
+       uint8_t ipv4_addr_state;
+       uint16_t ipv4_options;
+
+       uint32_t resvd2;
+       uint32_t ipv6_options;
+       uint32_t ipv6_addl_options;
+       uint8_t ipv6_link_local_state;
+       uint8_t ipv6_addr0_state;
+       uint8_t ipv6_addr1_state;
+       uint8_t ipv6_default_router_state;
+       struct in6_addr ipv6_link_local_addr;
+       struct in6_addr ipv6_addr0;
+       struct in6_addr ipv6_addr1;
+       struct in6_addr ipv6_default_router_addr;
 };
 
+static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
+{
+       return ((ha->ipv4_options & IPOPT_IPv4_PROTOCOL_ENABLE) != 0);
+}
+
+static inline int is_ipv6_enabled(struct scsi_qla_host *ha)
+{
+       return ((ha->ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) != 0);
+}
+
 static inline int is_qla4010(struct scsi_qla_host *ha)
 {
        return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010;
index 9cd7a60..855226e 100644 (file)
@@ -215,6 +215,7 @@ union external_hw_config_reg {
 /*  Mailbox command definitions */
 #define MBOX_CMD_ABOUT_FW                      0x0009
 #define MBOX_CMD_PING                          0x000B
+#define MBOX_CMD_ABORT_TASK                    0x0015
 #define MBOX_CMD_LUN_RESET                     0x0016
 #define MBOX_CMD_TARGET_WARM_RESET             0x0017
 #define MBOX_CMD_GET_MANAGEMENT_DATA           0x001E
@@ -258,13 +259,15 @@ union external_hw_config_reg {
 /* Mailbox 1 */
 #define FW_STATE_READY                         0x0000
 #define FW_STATE_CONFIG_WAIT                   0x0001
-#define FW_STATE_WAIT_LOGIN                    0x0002
+#define FW_STATE_WAIT_AUTOCONNECT              0x0002
 #define FW_STATE_ERROR                         0x0004
-#define FW_STATE_DHCP_IN_PROGRESS              0x0008
+#define FW_STATE_CONFIGURING_IP                        0x0008
 
 /* Mailbox 3 */
 #define FW_ADDSTATE_OPTICAL_MEDIA              0x0001
-#define FW_ADDSTATE_DHCP_ENABLED               0x0002
+#define FW_ADDSTATE_DHCPv4_ENABLED             0x0002
+#define FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED      0x0004
+#define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED       0x0008
 #define FW_ADDSTATE_LINK_UP                    0x0010
 #define FW_ADDSTATE_ISNS_SVC_ENABLED           0x0020
 #define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS   0x006B
@@ -320,6 +323,8 @@ union external_hw_config_reg {
 /* Host Adapter Initialization Control Block (from host) */
 struct addr_ctrl_blk {
        uint8_t version;        /* 00 */
+#define  IFCB_VER_MIN                  0x01
+#define  IFCB_VER_MAX                  0x02
        uint8_t control;        /* 01 */
 
        uint16_t fw_options;    /* 02-03 */
@@ -351,11 +356,16 @@ struct addr_ctrl_blk {
        uint16_t iscsi_opts;    /* 30-31 */
        uint16_t ipv4_tcp_opts; /* 32-33 */
        uint16_t ipv4_ip_opts;  /* 34-35 */
+#define  IPOPT_IPv4_PROTOCOL_ENABLE    0x8000
 
        uint16_t iscsi_max_pdu_size;    /* 36-37 */
        uint8_t ipv4_tos;       /* 38 */
        uint8_t ipv4_ttl;       /* 39 */
        uint8_t acb_version;    /* 3A */
+#define ACB_NOT_SUPPORTED              0x00
+#define ACB_SUPPORTED                  0x02 /* Capable of ACB Version 2
+                                               Features */
+
        uint8_t res2;   /* 3B */
        uint16_t def_timeout;   /* 3C-3D */
        uint16_t iscsi_fburst_len;      /* 3E-3F */
@@ -397,16 +407,35 @@ struct addr_ctrl_blk {
        uint32_t cookie;        /* 200-203 */
        uint16_t ipv6_port;     /* 204-205 */
        uint16_t ipv6_opts;     /* 206-207 */
+#define IPV6_OPT_IPV6_PROTOCOL_ENABLE  0x8000
+
        uint16_t ipv6_addtl_opts;       /* 208-209 */
+#define IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE     0x0002 /* Pri ACB
+                                                                 Only */
+#define IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR         0x0001
+
        uint16_t ipv6_tcp_opts; /* 20A-20B */
        uint8_t ipv6_tcp_wsf;   /* 20C */
        uint16_t ipv6_flow_lbl; /* 20D-20F */
-       uint8_t ipv6_gw_addr[16];       /* 210-21F */
+       uint8_t ipv6_dflt_rtr_addr[16]; /* 210-21F */
        uint16_t ipv6_vlan_tag; /* 220-221 */
        uint8_t ipv6_lnk_lcl_addr_state;/* 222 */
        uint8_t ipv6_addr0_state;       /* 223 */
        uint8_t ipv6_addr1_state;       /* 224 */
-       uint8_t ipv6_gw_state;  /* 225 */
+#define IP_ADDRSTATE_UNCONFIGURED      0
+#define IP_ADDRSTATE_INVALID           1
+#define IP_ADDRSTATE_ACQUIRING         2
+#define IP_ADDRSTATE_TENTATIVE         3
+#define IP_ADDRSTATE_DEPRICATED                4
+#define IP_ADDRSTATE_PREFERRED         5
+#define IP_ADDRSTATE_DISABLING         6
+
+       uint8_t ipv6_dflt_rtr_state;    /* 225 */
+#define IPV6_RTRSTATE_UNKNOWN                   0
+#define IPV6_RTRSTATE_MANUAL                    1
+#define IPV6_RTRSTATE_ADVERTISED                3
+#define IPV6_RTRSTATE_STALE                     4
+
        uint8_t ipv6_traffic_class;     /* 226 */
        uint8_t ipv6_hop_limit; /* 227 */
        uint8_t ipv6_if_id[8];  /* 228-22F */
@@ -424,7 +453,7 @@ struct addr_ctrl_blk {
 
 struct init_fw_ctrl_blk {
        struct addr_ctrl_blk pri;
-       struct addr_ctrl_blk sec;
+/*     struct addr_ctrl_blk sec;*/
 };
 
 /*************************************************************************/
@@ -433,6 +462,9 @@ struct dev_db_entry {
        uint16_t options;       /* 00-01 */
 #define DDB_OPT_DISC_SESSION  0x10
 #define DDB_OPT_TARGET       0x02 /* device is a target */
+#define DDB_OPT_IPV6_DEVICE    0x100
+#define DDB_OPT_IPV6_NULL_LINK_LOCAL           0x800 /* post connection */
+#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL     0x800 /* pre connection */
 
        uint16_t exec_throttle; /* 02-03 */
        uint16_t exec_count;    /* 04-05 */
@@ -468,7 +500,7 @@ struct dev_db_entry {
                                         * pointer to a string so we
                                         * don't have to reserve soooo
                                         * much RAM */
-       uint8_t ipv6_addr[0x10];/* 1A0-1AF */
+       uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */
        uint8_t res5[0x10];     /* 1B0-1BF */
        uint16_t ddb_link;      /* 1C0-1C1 */
        uint16_t chap_tbl_idx;  /* 1C2-1C3 */
index 96ebfb0..c4636f6 100644 (file)
@@ -25,6 +25,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
 int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
 int qla4xxx_relogin_device(struct scsi_qla_host * ha,
                           struct ddb_entry * ddb_entry);
+int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb);
 int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
                      int lun);
 int qla4xxx_reset_target(struct scsi_qla_host * ha,
@@ -65,13 +66,14 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
 int qla4xxx_init_rings(struct scsi_qla_host * ha);
 struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
                                        uint32_t index);
-void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
+void qla4xxx_srb_compl(struct kref *ref);
 int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
-int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
-                               uint32_t fw_ddb_index, uint32_t state);
+int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
+               uint32_t state, uint32_t conn_error);
 void qla4xxx_dump_buffer(void *b, uint32_t size);
 int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
        struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod);
+int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err);
 
 extern int ql4xextended_error_logging;
 extern int ql4xdiscoverywait;
index 92329a4..5510df8 100644 (file)
@@ -189,6 +189,78 @@ static int qla4xxx_init_local_data(struct scsi_qla_host *ha)
        return qla4xxx_get_firmware_status(ha);
 }
 
+static uint8_t
+qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha)
+{
+       uint8_t ipv4_wait = 0;
+       uint8_t ipv6_wait = 0;
+       int8_t ip_address[IPv6_ADDR_LEN] = {0} ;
+
+       /* If both IPv4 & IPv6 are enabled, possibly only one
+        * IP address may be acquired, so check to see if we
+        * need to wait for another */
+       if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) {
+               if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) &&
+                   ((ha->addl_fw_state &
+                                   FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) {
+                       ipv4_wait = 1;
+               }
+               if (((ha->ipv6_addl_options &
+                           IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) &&
+                   ((ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING) ||
+                    (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING) ||
+                    (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING))) {
+
+                       ipv6_wait = 1;
+
+                       if ((ha->ipv6_link_local_state ==
+                                                    IP_ADDRSTATE_PREFERRED) ||
+                           (ha->ipv6_addr0_state == IP_ADDRSTATE_PREFERRED) ||
+                           (ha->ipv6_addr1_state == IP_ADDRSTATE_PREFERRED)) {
+                               DEBUG2(printk(KERN_INFO "scsi%ld: %s: "
+                                             "Preferred IP configured."
+                                             " Don't wait!\n", ha->host_no,
+                                             __func__));
+                               ipv6_wait = 0;
+                       }
+                       if (memcmp(&ha->ipv6_default_router_addr, ip_address,
+                               IPv6_ADDR_LEN) == 0) {
+                               DEBUG2(printk(KERN_INFO "scsi%ld: %s: "
+                                             "No Router configured. "
+                                             "Don't wait!\n", ha->host_no,
+                                             __func__));
+                               ipv6_wait = 0;
+                       }
+                       if ((ha->ipv6_default_router_state ==
+                                               IPV6_RTRSTATE_MANUAL) &&
+                           (ha->ipv6_link_local_state ==
+                                               IP_ADDRSTATE_TENTATIVE) &&
+                           (memcmp(&ha->ipv6_link_local_addr,
+                                   &ha->ipv6_default_router_addr, 4) == 0)) {
+                               DEBUG2(printk("scsi%ld: %s: LinkLocal Router & "
+                                       "IP configured. Don't wait!\n",
+                                       ha->host_no, __func__));
+                               ipv6_wait = 0;
+                       }
+               }
+               if (ipv4_wait || ipv6_wait) {
+                       DEBUG2(printk("scsi%ld: %s: Wait for additional "
+                                     "IP(s) \"", ha->host_no, __func__));
+                       if (ipv4_wait)
+                               DEBUG2(printk("IPv4 "));
+                       if (ha->ipv6_link_local_state == IP_ADDRSTATE_ACQUIRING)
+                               DEBUG2(printk("IPv6LinkLocal "));
+                       if (ha->ipv6_addr0_state == IP_ADDRSTATE_ACQUIRING)
+                               DEBUG2(printk("IPv6Addr0 "));
+                       if (ha->ipv6_addr1_state == IP_ADDRSTATE_ACQUIRING)
+                               DEBUG2(printk("IPv6Addr1 "));
+                       DEBUG2(printk("\"\n"));
+               }
+       }
+
+       return ipv4_wait|ipv6_wait;
+}
+
 static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
 {
        uint32_t timeout_count;
@@ -226,38 +298,80 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
                        continue;
                }
 
+               if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) {
+                       DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:"
+                                     "AUTOCONNECT in progress\n",
+                                     ha->host_no, __func__));
+               }
+
+               if (ha->firmware_state & FW_STATE_CONFIGURING_IP) {
+                       DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:"
+                                     " CONFIGURING IP\n",
+                                     ha->host_no, __func__));
+                       /*
+                        * Check for link state after 15 secs and if link is
+                        * still DOWN then, cable is unplugged. Ignore "DHCP
+                        * in Progress/CONFIGURING IP" bit to check if firmware
+                        * is in ready state or not after 15 secs.
+                        * This is applicable for both 2.x & 3.x firmware
+                        */
+                       if (timeout_count <= (ADAPTER_INIT_TOV - 15)) {
+                               if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) {
+                                       DEBUG2(printk(KERN_INFO "scsi%ld: %s:"
+                                                 " LINK UP (Cable plugged)\n",
+                                                 ha->host_no, __func__));
+                               } else if (ha->firmware_state &
+                                         (FW_STATE_CONFIGURING_IP |
+                                                            FW_STATE_READY)) {
+                                       DEBUG2(printk(KERN_INFO "scsi%ld: %s: "
+                                               "LINK DOWN (Cable unplugged)\n",
+                                               ha->host_no, __func__));
+                                       ha->firmware_state = FW_STATE_READY;
+                               }
+                       }
+               }
+
                if (ha->firmware_state == FW_STATE_READY) {
-                       DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n"));
-                       /* The firmware is ready to process SCSI commands. */
-                       DEBUG2(dev_info(&ha->pdev->dev,
-                                         "scsi%ld: %s: MEDIA TYPE - %s\n",
-                                         ha->host_no,
-                                         __func__, (ha->addl_fw_state &
-                                                    FW_ADDSTATE_OPTICAL_MEDIA)
-                                         != 0 ? "OPTICAL" : "COPPER"));
-                       DEBUG2(dev_info(&ha->pdev->dev,
-                                         "scsi%ld: %s: DHCP STATE Enabled "
-                                         "%s\n",
-                                         ha->host_no, __func__,
-                                         (ha->addl_fw_state &
-                                          FW_ADDSTATE_DHCP_ENABLED) != 0 ?
-                                         "YES" : "NO"));
-                       DEBUG2(dev_info(&ha->pdev->dev,
-                                         "scsi%ld: %s: LINK %s\n",
-                                         ha->host_no, __func__,
-                                         (ha->addl_fw_state &
-                                          FW_ADDSTATE_LINK_UP) != 0 ?
-                                         "UP" : "DOWN"));
-                       DEBUG2(dev_info(&ha->pdev->dev,
-                                         "scsi%ld: %s: iSNS Service "
-                                         "Started %s\n",
-                                         ha->host_no, __func__,
-                                         (ha->addl_fw_state &
-                                          FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ?
-                                         "YES" : "NO"));
-
-                       ready = 1;
-                       break;
+                       /* If DHCP IP Addr is available, retrieve it now. */
+                       if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR,
+                                                               &ha->dpc_flags))
+                               qla4xxx_get_dhcp_ip_address(ha);
+
+                       if (!qla4xxx_wait_for_ip_config(ha) ||
+                                                       timeout_count == 1) {
+                               DEBUG2(dev_info(&ha->pdev->dev,
+                                               "Firmware Ready..\n"));
+                               /* The firmware is ready to process SCSI
+                                  commands. */
+                               DEBUG2(dev_info(&ha->pdev->dev,
+                                       "scsi%ld: %s: MEDIA TYPE"
+                                       " - %s\n", ha->host_no,
+                                       __func__, (ha->addl_fw_state &
+                                       FW_ADDSTATE_OPTICAL_MEDIA)
+                                       != 0 ? "OPTICAL" : "COPPER"));
+                               DEBUG2(dev_info(&ha->pdev->dev,
+                                       "scsi%ld: %s: DHCPv4 STATE"
+                                       " Enabled %s\n", ha->host_no,
+                                        __func__, (ha->addl_fw_state &
+                                        FW_ADDSTATE_DHCPv4_ENABLED) != 0 ?
+                                       "YES" : "NO"));
+                               DEBUG2(dev_info(&ha->pdev->dev,
+                                       "scsi%ld: %s: LINK %s\n",
+                                       ha->host_no, __func__,
+                                       (ha->addl_fw_state &
+                                        FW_ADDSTATE_LINK_UP) != 0 ?
+                                       "UP" : "DOWN"));
+                               DEBUG2(dev_info(&ha->pdev->dev,
+                                       "scsi%ld: %s: iSNS Service "
+                                       "Started %s\n",
+                                       ha->host_no, __func__,
+                                       (ha->addl_fw_state &
+                                        FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ?
+                                       "YES" : "NO"));
+
+                               ready = 1;
+                               break;
+                       }
                }
                DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - "
                              "seconds expired= %d\n", ha->host_no, __func__,
@@ -272,15 +386,19 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
                msleep(1000);
        }                       /* end of for */
 
-       if (timeout_count == 0)
+       if (timeout_count <= 0)
                DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",
                              ha->host_no, __func__));
 
-       if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)  {
-               DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to"
-                             " grab an IP address from DHCP server\n",
-                             ha->host_no, __func__));
+       if (ha->firmware_state & FW_STATE_CONFIGURING_IP) {
+               DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting "
+                             "it's waiting to configure an IP address\n",
+                              ha->host_no, __func__));
                ready = 1;
+       } else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) {
+               DEBUG2(printk("scsi%ld: %s: FW initialized, but "
+                             "auto-discovery still in process\n",
+                              ha->host_no, __func__));
        }
 
        return ready;
@@ -387,6 +505,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
        struct dev_db_entry *fw_ddb_entry = NULL;
        dma_addr_t fw_ddb_entry_dma;
        int status = QLA_ERROR;
+       uint32_t conn_err;
 
        if (ddb_entry == NULL) {
                DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
@@ -407,7 +526,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
 
        if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
                                    fw_ddb_entry_dma, NULL, NULL,
-                                   &ddb_entry->fw_ddb_device_state, NULL,
+                                   &ddb_entry->fw_ddb_device_state, &conn_err,
                                    &ddb_entry->tcp_source_port_num,
                                    &ddb_entry->connection_id) ==
            QLA_ERROR) {
@@ -419,6 +538,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
        }
 
        status = QLA_SUCCESS;
+       ddb_entry->options = le16_to_cpu(fw_ddb_entry->options);
        ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid);
        ddb_entry->task_mgmt_timeout =
                le16_to_cpu(fw_ddb_entry->def_timeout);
@@ -442,11 +562,44 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
        memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
               min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
 
-       DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
-                     ha->host_no, __func__, fw_ddb_index,
-                     ddb_entry->fw_ddb_device_state, status));
-
- exit_update_ddb:
+       ddb_entry->iscsi_max_burst_len = fw_ddb_entry->iscsi_max_burst_len;
+       ddb_entry->iscsi_max_outsnd_r2t = fw_ddb_entry->iscsi_max_outsnd_r2t;
+       ddb_entry->iscsi_first_burst_len = fw_ddb_entry->iscsi_first_burst_len;
+       ddb_entry->iscsi_max_rcv_data_seg_len =
+                               fw_ddb_entry->iscsi_max_rcv_data_seg_len;
+       ddb_entry->iscsi_max_snd_data_seg_len =
+                               fw_ddb_entry->iscsi_max_snd_data_seg_len;
+
+       if (ddb_entry->options & DDB_OPT_IPV6_DEVICE) {
+               memcpy(&ddb_entry->remote_ipv6_addr,
+                       fw_ddb_entry->ip_addr,
+                       min(sizeof(ddb_entry->remote_ipv6_addr),
+                       sizeof(fw_ddb_entry->ip_addr)));
+               memcpy(&ddb_entry->link_local_ipv6_addr,
+                       fw_ddb_entry->link_local_ipv6_addr,
+                       min(sizeof(ddb_entry->link_local_ipv6_addr),
+                       sizeof(fw_ddb_entry->link_local_ipv6_addr)));
+
+               DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
+                                       "State %04x ConnErr %08x IP %pI6 "
+                                       ":%04d \"%s\"\n",
+                                       __func__, fw_ddb_index,
+                                       ddb_entry->os_target_id,
+                                       ddb_entry->fw_ddb_device_state,
+                                       conn_err, fw_ddb_entry->ip_addr,
+                                       le16_to_cpu(fw_ddb_entry->port),
+                                       fw_ddb_entry->iscsi_name));
+       } else
+               DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
+                                       "State %04x ConnErr %08x IP %pI4 "
+                                       ":%04d \"%s\"\n",
+                                       __func__, fw_ddb_index,
+                                       ddb_entry->os_target_id,
+                                       ddb_entry->fw_ddb_device_state,
+                                       conn_err, fw_ddb_entry->ip_addr,
+                                       le16_to_cpu(fw_ddb_entry->port),
+                                       fw_ddb_entry->iscsi_name));
+exit_update_ddb:
        if (fw_ddb_entry)
                dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
                                  fw_ddb_entry, fw_ddb_entry_dma);
@@ -492,6 +645,40 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
 }
 
 /**
+ * qla4_is_relogin_allowed - Are we allowed to login?
+ * @ha: Pointer to host adapter structure.
+ * @conn_err: Last connection error associated with the ddb
+ *
+ * This routine tests the given connection error to determine if
+ * we are allowed to login.
+ **/
+int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err)
+{
+       uint32_t err_code, login_rsp_sts_class;
+       int relogin = 1;
+
+       err_code = ((conn_err & 0x00ff0000) >> 16);
+       login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8);
+       if (err_code == 0x1c || err_code == 0x06) {
+               DEBUG2(dev_info(&ha->pdev->dev,
+                               ": conn_err=0x%08x, send target completed"
+                               " or access denied failure\n", conn_err));
+               relogin = 0;
+       }
+       if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) {
+               /* Login Response PDU returned an error.
+                  Login Response Status in Error Code Detail
+                  indicates login should not be retried.*/
+               DEBUG2(dev_info(&ha->pdev->dev,
+                               ": conn_err=0x%08x, do not retry relogin\n",
+                               conn_err));
+               relogin = 0;
+       }
+
+       return relogin;
+}
+
+/**
  * qla4xxx_configure_ddbs - builds driver ddb list
  * @ha: Pointer to host adapter structure.
  *
@@ -505,18 +692,30 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
        uint32_t fw_ddb_index = 0;
        uint32_t next_fw_ddb_index = 0;
        uint32_t ddb_state;
-       uint32_t conn_err, err_code;
+       uint32_t conn_err;
        struct ddb_entry *ddb_entry;
+       struct dev_db_entry *fw_ddb_entry = NULL;
+       dma_addr_t fw_ddb_entry_dma;
+       uint32_t ipv6_device;
        uint32_t new_tgt;
 
+       fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+                       &fw_ddb_entry_dma, GFP_KERNEL);
+       if (fw_ddb_entry == NULL) {
+               DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n",
+                               __func__));
+               return QLA_ERROR;
+       }
+
        dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
        for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
             fw_ddb_index = next_fw_ddb_index) {
                /* First, let's see if a device exists here */
-               if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL,
-                                           &next_fw_ddb_index, &ddb_state,
-                                           &conn_err, NULL, NULL) ==
-                   QLA_ERROR) {
+               if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
+                                           0, NULL, &next_fw_ddb_index,
+                                           &ddb_state, &conn_err,
+                                           NULL, NULL) ==
+                                           QLA_ERROR) {
                        DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
                                      "fw_ddb_index %d failed", ha->host_no,
                                      __func__, fw_ddb_index));
@@ -533,18 +732,19 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
                        /* Try and login to device */
                        DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n",
                                      ha->host_no, __func__, fw_ddb_index));
-                       err_code = ((conn_err & 0x00ff0000) >> 16);
-                       if (err_code == 0x1c || err_code == 0x06) {
-                               DEBUG2(printk("scsi%ld: %s send target "
-                                             "completed "
-                                             "or access denied failure\n",
-                                             ha->host_no, __func__));
-                       } else {
+                       ipv6_device = le16_to_cpu(fw_ddb_entry->options) &
+                                       DDB_OPT_IPV6_DEVICE;
+                       if (qla4_is_relogin_allowed(ha, conn_err) &&
+                                       ((!ipv6_device &&
+                                         *((uint32_t *)fw_ddb_entry->ip_addr))
+                                        || ipv6_device)) {
                                qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
                                if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index,
-                                       NULL, 0, NULL, &next_fw_ddb_index,
-                                       &ddb_state, &conn_err, NULL, NULL)
-                                       == QLA_ERROR) {
+                                                       NULL, 0, NULL,
+                                                       &next_fw_ddb_index,
+                                                       &ddb_state, &conn_err,
+                                                       NULL, NULL)
+                                               == QLA_ERROR) {
                                        DEBUG2(printk("scsi%ld: %s:"
                                                "get_ddb_entry %d failed\n",
                                                ha->host_no,
@@ -599,7 +799,6 @@ next_one:
 struct qla4_relog_scan {
        int halt_wait;
        uint32_t conn_err;
-       uint32_t err_code;
        uint32_t fw_ddb_index;
        uint32_t next_fw_ddb_index;
        uint32_t fw_ddb_device_state;
@@ -609,18 +808,7 @@ static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs)
 {
        struct ddb_entry *ddb_entry;
 
-       /*
-        * Don't want to do a relogin if connection
-        * error is 0x1c.
-        */
-       rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16);
-       if (rs->err_code == 0x1c || rs->err_code == 0x06) {
-               DEBUG2(printk(
-                              "scsi%ld: %s send target"
-                              " completed or "
-                              "access denied failure\n",
-                              ha->host_no, __func__));
-       } else {
+       if (qla4_is_relogin_allowed(ha, rs->conn_err)) {
                /* We either have a device that is in
                 * the process of relogging in or a
                 * device that is waiting to be
@@ -908,7 +1096,7 @@ static void qla4x00_pci_config(struct scsi_qla_host *ha)
 static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
 {
        int status = QLA_ERROR;
-       uint32_t max_wait_time;
+       unsigned long max_wait_time;
        unsigned long flags;
        uint32_t mbox_status;
 
@@ -940,7 +1128,10 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        /* Wait for firmware to come UP. */
-       max_wait_time = FIRMWARE_UP_TOV * 4;
+       DEBUG2(printk(KERN_INFO "scsi%ld: %s: Wait up to %d seconds for "
+                     "boot firmware to complete...\n",
+                     ha->host_no, __func__, FIRMWARE_UP_TOV));
+       max_wait_time = jiffies + (FIRMWARE_UP_TOV * HZ);
        do {
                uint32_t ctrl_status;
 
@@ -954,16 +1145,15 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
                if (mbox_status == MBOX_STS_COMMAND_COMPLETE)
                        break;
 
-               DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to "
-                             "complete... ctrl_sts=0x%x, remaining=%d\n",
-                             ha->host_no, __func__, ctrl_status,
-                             max_wait_time));
+               DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot "
+                             "firmware to complete... ctrl_sts=0x%x\n",
+                             ha->host_no, __func__, ctrl_status));
 
-               msleep(250);
-       } while ((max_wait_time--));
+               msleep_interruptible(250);
+       } while (!time_after_eq(jiffies, max_wait_time));
 
        if (mbox_status == MBOX_STS_COMMAND_COMPLETE) {
-               DEBUG(printk("scsi%ld: %s: Firmware has started\n",
+               DEBUG(printk(KERN_INFO "scsi%ld: %s: Firmware has started\n",
                             ha->host_no, __func__));
 
                spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1141,6 +1331,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
        int status = QLA_ERROR;
        int8_t ip_address[IP_ADDR_LEN] = {0} ;
 
+       clear_bit(AF_ONLINE, &ha->flags);
        ha->eeprom_cmd_data = 0;
 
        qla4x00_pci_config(ha);
@@ -1166,7 +1357,7 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
         * the ddb_list and wait for DHCP lease acquired aen to come in
         * followed by 0x8014 aen" to trigger the tgt discovery process.
         */
-       if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)
+       if (ha->firmware_state & FW_STATE_CONFIGURING_IP)
                goto exit_init_online;
 
        /* Skip device discovery if ip and subnet is zero */
@@ -1270,8 +1461,8 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
  *
  * This routine processes a Decive Database Changed AEN Event.
  **/
-int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
-                               uint32_t fw_ddb_index, uint32_t state)
+int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
+               uint32_t state, uint32_t conn_err)
 {
        struct ddb_entry * ddb_entry;
        uint32_t old_fw_ddb_device_state;
@@ -1318,19 +1509,24 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
                 * the device came back.
                 */
        } else {
-               /* Device went away, try to relogin. */
-               /* Mark device missing */
-               if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+               /* Device went away, mark device missing */
+               if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) {
+                       DEBUG2(dev_info(&ha->pdev->dev, "%s mark missing "
+                                       "ddb_entry 0x%p sess 0x%p conn 0x%p\n",
+                                       __func__, ddb_entry,
+                                       ddb_entry->sess, ddb_entry->conn));
                        qla4xxx_mark_device_missing(ha, ddb_entry);
+               }
+
                /*
                 * Relogin if device state changed to a not active state.
-                * However, do not relogin if this aen is a result of an IOCTL
-                * logout (DF_NO_RELOGIN) or if this is a discovered device.
+                * However, do not relogin if a RELOGIN is in process, or
+                * we are not allowed to relogin to this DDB.
                 */
                if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&
                    !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
                    !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) &&
-                   !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) {
+                   qla4_is_relogin_allowed(ha, conn_err)) {
                        /*
                         * This triggers a relogin.  After the relogin_timer
                         * expires, the relogin gets scheduled.  We must wait a
@@ -1338,7 +1534,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
                         * with failed device_state or a logout response before
                         * we can issue another relogin.
                         */
-                       /* Firmware padds this timeout: (time2wait +1).
+                       /* Firmware pads this timeout: (time2wait +1).
                         * Driver retry to login should be longer than F/W.
                         * Otherwise F/W will fail
                         * set_ddb() mbx cmd with 0x4005 since it still
index e0c3215..e66f3f2 100644 (file)
@@ -299,7 +299,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
        qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
        wmb();
 
-       srb->cmd->host_scribble = (unsigned char *)srb;
+       srb->cmd->host_scribble = (unsigned char *)(unsigned long)index;
 
        /* update counters */
        srb->state = SRB_ACTIVE_STATE;
index c196d55..596c303 100644 (file)
@@ -97,7 +97,7 @@ qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
 
        /* Place command on done queue. */
        if (srb->req_sense_len == 0) {
-               qla4xxx_srb_compl(ha, srb);
+               kref_put(&srb->srb_ref, qla4xxx_srb_compl);
                ha->status_srb = NULL;
        }
 }
@@ -329,7 +329,7 @@ status_entry_exit:
        /* complete the request, if not waiting for status_continuation pkt */
        srb->cc_stat = sts_entry->completionStatus;
        if (ha->status_srb == NULL)
-               qla4xxx_srb_compl(ha, srb);
+               kref_put(&srb->srb_ref, qla4xxx_srb_compl);
 }
 
 /**
@@ -393,7 +393,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
                        /* ETRY normally by sending it back with
                         * DID_BUS_BUSY */
                        srb->cmd->result = DID_BUS_BUSY << 16;
-                       qla4xxx_srb_compl(ha, srb);
+                       kref_put(&srb->srb_ref, qla4xxx_srb_compl);
                        break;
 
                case ET_CONTINUE:
@@ -498,15 +498,22 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
                        break;
 
                case MBOX_ASTS_LINK_UP:
-                       DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n",
-                                     ha->host_no, mbox_status));
                        set_bit(AF_LINK_UP, &ha->flags);
+                       if (test_bit(AF_INIT_DONE, &ha->flags))
+                               set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
+
+                       DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter"
+                                       " LINK UP\n", ha->host_no,
+                                       mbox_status));
                        break;
 
                case MBOX_ASTS_LINK_DOWN:
-                       DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n",
-                                     ha->host_no, mbox_status));
                        clear_bit(AF_LINK_UP, &ha->flags);
+                       set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
+
+                       DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter"
+                                       " LINK DOWN\n", ha->host_no,
+                                       mbox_status));
                        break;
 
                case MBOX_ASTS_HEARTBEAT:
@@ -831,7 +838,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
                                qla4xxx_reinitialize_ddb_list(ha);
                        } else if (mbox_sts[1] == 1) {  /* Specific device. */
                                qla4xxx_process_ddb_changed(ha, mbox_sts[2],
-                                                           mbox_sts[3]);
+                                               mbox_sts[3], mbox_sts[4]);
                        }
                        break;
                }
index caeb7d1..75496fb 100644 (file)
@@ -172,108 +172,207 @@ mbox_exit:
        return status;
 }
 
+uint8_t
+qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
+                uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
+{
+       memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
+       memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
+       mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
+       mbox_cmd[1] = 0;
+       mbox_cmd[2] = LSDW(init_fw_cb_dma);
+       mbox_cmd[3] = MSDW(init_fw_cb_dma);
+       mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
+       mbox_cmd[5] = (IFCB_VER_MAX << 8) | IFCB_VER_MIN;
+
+       if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) !=
+           QLA_SUCCESS) {
+               DEBUG2(printk(KERN_WARNING "scsi%ld: %s: "
+                             "MBOX_CMD_INITIALIZE_FIRMWARE"
+                             " failed w/ status %04X\n",
+                             ha->host_no, __func__, mbox_sts[0]));
+               return QLA_ERROR;
+       }
+       return QLA_SUCCESS;
+}
+
+uint8_t
+qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
+                uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
+{
+       memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
+       memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
+       mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
+       mbox_cmd[2] = LSDW(init_fw_cb_dma);
+       mbox_cmd[3] = MSDW(init_fw_cb_dma);
+       mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
+
+       if (qla4xxx_mailbox_command(ha, 5, 5, mbox_cmd, mbox_sts) !=
+           QLA_SUCCESS) {
+               DEBUG2(printk(KERN_WARNING "scsi%ld: %s: "
+                             "MBOX_CMD_GET_INIT_FW_CTRL_BLOCK"
+                             " failed w/ status %04X\n",
+                             ha->host_no, __func__, mbox_sts[0]));
+               return QLA_ERROR;
+       }
+       return QLA_SUCCESS;
+}
+
+void
+qla4xxx_update_local_ip(struct scsi_qla_host *ha,
+                        struct addr_ctrl_blk  *init_fw_cb)
+{
+       /* Save IPv4 Address Info */
+       memcpy(ha->ip_address, init_fw_cb->ipv4_addr,
+               min(sizeof(ha->ip_address), sizeof(init_fw_cb->ipv4_addr)));
+       memcpy(ha->subnet_mask, init_fw_cb->ipv4_subnet,
+               min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->ipv4_subnet)));
+       memcpy(ha->gateway, init_fw_cb->ipv4_gw_addr,
+               min(sizeof(ha->gateway), sizeof(init_fw_cb->ipv4_gw_addr)));
+
+       if (is_ipv6_enabled(ha)) {
+               /* Save IPv6 Address */
+               ha->ipv6_link_local_state = init_fw_cb->ipv6_lnk_lcl_addr_state;
+               ha->ipv6_addr0_state = init_fw_cb->ipv6_addr0_state;
+               ha->ipv6_addr1_state = init_fw_cb->ipv6_addr1_state;
+               ha->ipv6_default_router_state = init_fw_cb->ipv6_dflt_rtr_state;
+               ha->ipv6_link_local_addr.in6_u.u6_addr8[0] = 0xFE;
+               ha->ipv6_link_local_addr.in6_u.u6_addr8[1] = 0x80;
+
+               memcpy(&ha->ipv6_link_local_addr.in6_u.u6_addr8[8],
+                       init_fw_cb->ipv6_if_id,
+                       min(sizeof(ha->ipv6_link_local_addr)/2,
+                       sizeof(init_fw_cb->ipv6_if_id)));
+               memcpy(&ha->ipv6_addr0, init_fw_cb->ipv6_addr0,
+                       min(sizeof(ha->ipv6_addr0),
+                       sizeof(init_fw_cb->ipv6_addr0)));
+               memcpy(&ha->ipv6_addr1, init_fw_cb->ipv6_addr1,
+                       min(sizeof(ha->ipv6_addr1),
+                       sizeof(init_fw_cb->ipv6_addr1)));
+               memcpy(&ha->ipv6_default_router_addr,
+                       init_fw_cb->ipv6_dflt_rtr_addr,
+                       min(sizeof(ha->ipv6_default_router_addr),
+                       sizeof(init_fw_cb->ipv6_dflt_rtr_addr)));
+       }
+}
+
+uint8_t
+qla4xxx_update_local_ifcb(struct scsi_qla_host *ha,
+                         uint32_t *mbox_cmd,
+                         uint32_t *mbox_sts,
+                         struct addr_ctrl_blk  *init_fw_cb,
+                         dma_addr_t init_fw_cb_dma)
+{
+       if (qla4xxx_get_ifcb(ha, mbox_cmd, mbox_sts, init_fw_cb_dma)
+           != QLA_SUCCESS) {
+               DEBUG2(printk(KERN_WARNING
+                             "scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
+                             ha->host_no, __func__));
+               return QLA_ERROR;
+       }
+
+       DEBUG2(qla4xxx_dump_buffer(init_fw_cb, sizeof(struct addr_ctrl_blk)));
+
+       /* Save some info in adapter structure. */
+       ha->acb_version = init_fw_cb->acb_version;
+       ha->firmware_options = le16_to_cpu(init_fw_cb->fw_options);
+       ha->tcp_options = le16_to_cpu(init_fw_cb->ipv4_tcp_opts);
+       ha->ipv4_options = le16_to_cpu(init_fw_cb->ipv4_ip_opts);
+       ha->ipv4_addr_state = le16_to_cpu(init_fw_cb->ipv4_addr_state);
+       ha->heartbeat_interval = init_fw_cb->hb_interval;
+       memcpy(ha->name_string, init_fw_cb->iscsi_name,
+               min(sizeof(ha->name_string),
+               sizeof(init_fw_cb->iscsi_name)));
+       /*memcpy(ha->alias, init_fw_cb->Alias,
+              min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/
+
+       /* Save Command Line Paramater info */
+       ha->port_down_retry_count = le16_to_cpu(init_fw_cb->conn_ka_timeout);
+       ha->discovery_wait = ql4xdiscoverywait;
+
+       if (ha->acb_version == ACB_SUPPORTED) {
+               ha->ipv6_options = init_fw_cb->ipv6_opts;
+               ha->ipv6_addl_options = init_fw_cb->ipv6_addtl_opts;
+       }
+       qla4xxx_update_local_ip(ha, init_fw_cb);
+
+       return QLA_SUCCESS;
+}
+
 /**
  * qla4xxx_initialize_fw_cb - initializes firmware control block.
  * @ha: Pointer to host adapter structure.
  **/
 int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
 {
-       struct init_fw_ctrl_blk *init_fw_cb;
+       struct addr_ctrl_blk *init_fw_cb;
        dma_addr_t init_fw_cb_dma;
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
        int status = QLA_ERROR;
 
        init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
-                                       sizeof(struct init_fw_ctrl_blk),
+                                       sizeof(struct addr_ctrl_blk),
                                        &init_fw_cb_dma, GFP_KERNEL);
        if (init_fw_cb == NULL) {
                DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
                              ha->host_no, __func__));
                return 10;
        }
-       memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
+       memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
 
        /* Get Initialize Firmware Control Block. */
        memset(&mbox_cmd, 0, sizeof(mbox_cmd));
        memset(&mbox_sts, 0, sizeof(mbox_sts));
 
-       mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
-       mbox_cmd[2] = LSDW(init_fw_cb_dma);
-       mbox_cmd[3] = MSDW(init_fw_cb_dma);
-       mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
-
-       if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+       if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=
            QLA_SUCCESS) {
                dma_free_coherent(&ha->pdev->dev,
-                                 sizeof(struct init_fw_ctrl_blk),
+                                 sizeof(struct addr_ctrl_blk),
                                  init_fw_cb, init_fw_cb_dma);
-               return status;
+               goto exit_init_fw_cb;
        }
 
        /* Initialize request and response queues. */
        qla4xxx_init_rings(ha);
 
        /* Fill in the request and response queue information. */
-       init_fw_cb->pri.rqq_consumer_idx = cpu_to_le16(ha->request_out);
-       init_fw_cb->pri.compq_producer_idx = cpu_to_le16(ha->response_in);
-       init_fw_cb->pri.rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
-       init_fw_cb->pri.compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
-       init_fw_cb->pri.rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma));
-       init_fw_cb->pri.rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma));
-       init_fw_cb->pri.compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma));
-       init_fw_cb->pri.compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma));
-       init_fw_cb->pri.shdwreg_addr_lo =
-               cpu_to_le32(LSDW(ha->shadow_regs_dma));
-       init_fw_cb->pri.shdwreg_addr_hi =
-               cpu_to_le32(MSDW(ha->shadow_regs_dma));
+       init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out);
+       init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in);
+       init_fw_cb->rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
+       init_fw_cb->compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
+       init_fw_cb->rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma));
+       init_fw_cb->rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma));
+       init_fw_cb->compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma));
+       init_fw_cb->compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma));
+       init_fw_cb->shdwreg_addr_lo = cpu_to_le32(LSDW(ha->shadow_regs_dma));
+       init_fw_cb->shdwreg_addr_hi = cpu_to_le32(MSDW(ha->shadow_regs_dma));
 
        /* Set up required options. */
-       init_fw_cb->pri.fw_options |=
+       init_fw_cb->fw_options |=
                __constant_cpu_to_le16(FWOPT_SESSION_MODE |
                                       FWOPT_INITIATOR_MODE);
-       init_fw_cb->pri.fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
-
-       /* Save some info in adapter structure. */
-       ha->firmware_options = le16_to_cpu(init_fw_cb->pri.fw_options);
-       ha->tcp_options = le16_to_cpu(init_fw_cb->pri.ipv4_tcp_opts);
-       ha->heartbeat_interval = init_fw_cb->pri.hb_interval;
-       memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr,
-              min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr)));
-       memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet,
-              min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet)));
-       memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr,
-              min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr)));
-       memcpy(ha->name_string, init_fw_cb->pri.iscsi_name,
-              min(sizeof(ha->name_string),
-                  sizeof(init_fw_cb->pri.iscsi_name)));
-       /*memcpy(ha->alias, init_fw_cb->Alias,
-              min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/
-
-       /* Save Command Line Paramater info */
-       ha->port_down_retry_count = le16_to_cpu(init_fw_cb->pri.conn_ka_timeout);
-       ha->discovery_wait = ql4xdiscoverywait;
+       init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
 
-       /* Send Initialize Firmware Control Block. */
-       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
-       memset(&mbox_sts, 0, sizeof(mbox_sts));
-
-       mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
-       mbox_cmd[1] = 0;
-       mbox_cmd[2] = LSDW(init_fw_cb_dma);
-       mbox_cmd[3] = MSDW(init_fw_cb_dma);
-       mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
+       if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)
+               != QLA_SUCCESS) {
+               DEBUG2(printk(KERN_WARNING
+                             "scsi%ld: %s: Failed to set init_fw_ctrl_blk\n",
+                             ha->host_no, __func__));
+               goto exit_init_fw_cb;
+       }
 
-       if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) ==
-           QLA_SUCCESS)
-               status = QLA_SUCCESS;
-        else {
-               DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE "
-                             "failed w/ status %04X\n", ha->host_no, __func__,
-                             mbox_sts[0]));
+       if (qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0],
+               init_fw_cb, init_fw_cb_dma) != QLA_SUCCESS) {
+               DEBUG2(printk("scsi%ld: %s: Failed to update local ifcb\n",
+                               ha->host_no, __func__));
+               goto exit_init_fw_cb;
        }
-       dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
-                         init_fw_cb, init_fw_cb_dma);
+       status = QLA_SUCCESS;
+
+exit_init_fw_cb:
+       dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
+                               init_fw_cb, init_fw_cb_dma);
 
        return status;
 }
@@ -284,13 +383,13 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
  **/
 int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
 {
-       struct init_fw_ctrl_blk *init_fw_cb;
+       struct addr_ctrl_blk *init_fw_cb;
        dma_addr_t init_fw_cb_dma;
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
 
        init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
-                                       sizeof(struct init_fw_ctrl_blk),
+                                       sizeof(struct addr_ctrl_blk),
                                        &init_fw_cb_dma, GFP_KERNEL);
        if (init_fw_cb == NULL) {
                printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
@@ -299,35 +398,21 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
        }
 
        /* Get Initialize Firmware Control Block. */
-       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
-       memset(&mbox_sts, 0, sizeof(mbox_sts));
-
-       memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
-       mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
-       mbox_cmd[2] = LSDW(init_fw_cb_dma);
-       mbox_cmd[3] = MSDW(init_fw_cb_dma);
-       mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
-
-       if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+       memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk));
+       if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=
            QLA_SUCCESS) {
                DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
                              ha->host_no, __func__));
                dma_free_coherent(&ha->pdev->dev,
-                                 sizeof(struct init_fw_ctrl_blk),
+                                 sizeof(struct addr_ctrl_blk),
                                  init_fw_cb, init_fw_cb_dma);
                return QLA_ERROR;
        }
 
        /* Save IP Address. */
-       memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr,
-              min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr)));
-       memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet,
-              min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet)));
-       memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr,
-              min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr)));
-
-       dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
-                         init_fw_cb, init_fw_cb_dma);
+       qla4xxx_update_local_ip(ha, init_fw_cb);
+       dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
+                               init_fw_cb, init_fw_cb_dma);
 
        return QLA_SUCCESS;
 }
@@ -409,6 +494,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
                            uint16_t *connection_id)
 {
        int status = QLA_ERROR;
+       uint16_t options;
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
 
@@ -441,14 +527,26 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
                goto exit_get_fwddb;
        }
        if (fw_ddb_entry) {
-               dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
-                          "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
-                          fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
-                          mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0],
-                          fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2],
-                          fw_ddb_entry->ip_addr[3],
-                          le16_to_cpu(fw_ddb_entry->port),
-                          fw_ddb_entry->iscsi_name);
+               options = le16_to_cpu(fw_ddb_entry->options);
+               if (options & DDB_OPT_IPV6_DEVICE) {
+                       dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d "
+                               "Next %d State %04x ConnErr %08x %pI6 "
+                               ":%04d \"%s\"\n", __func__, fw_ddb_index,
+                               mbox_sts[0], mbox_sts[2], mbox_sts[3],
+                               mbox_sts[4], mbox_sts[5],
+                               fw_ddb_entry->ip_addr,
+                               le16_to_cpu(fw_ddb_entry->port),
+                               fw_ddb_entry->iscsi_name);
+               } else {
+                       dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d "
+                               "Next %d State %04x ConnErr %08x %pI4 "
+                               ":%04d \"%s\"\n", __func__, fw_ddb_index,
+                               mbox_sts[0], mbox_sts[2], mbox_sts[3],
+                               mbox_sts[4], mbox_sts[5],
+                               fw_ddb_entry->ip_addr,
+                               le16_to_cpu(fw_ddb_entry->port),
+                               fw_ddb_entry->iscsi_name);
+               }
        }
        if (num_valid_ddb_entries)
                *num_valid_ddb_entries = mbox_sts[2];
@@ -664,6 +762,59 @@ exit_get_event_log:
 }
 
 /**
+ * qla4xxx_abort_task - issues Abort Task
+ * @ha: Pointer to host adapter structure.
+ * @srb: Pointer to srb entry
+ *
+ * This routine performs a LUN RESET on the specified target/lun.
+ * The caller must ensure that the ddb_entry and lun_entry pointers
+ * are valid before calling this routine.
+ **/
+int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb)
+{
+       uint32_t mbox_cmd[MBOX_REG_COUNT];
+       uint32_t mbox_sts[MBOX_REG_COUNT];
+       struct scsi_cmnd *cmd = srb->cmd;
+       int status = QLA_SUCCESS;
+       unsigned long flags = 0;
+       uint32_t index;
+
+       /*
+        * Send abort task command to ISP, so that the ISP will return
+        * request with ABORT status
+        */
+       memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+       memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       index = (unsigned long)(unsigned char *)cmd->host_scribble;
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       /* Firmware already posted completion on response queue */
+       if (index == MAX_SRBS)
+               return status;
+
+       mbox_cmd[0] = MBOX_CMD_ABORT_TASK;
+       mbox_cmd[1] = srb->fw_ddb_index;
+       mbox_cmd[2] = index;
+       /* Immediate Command Enable */
+       mbox_cmd[5] = 0x01;
+
+       qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
+           &mbox_sts[0]);
+       if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) {
+               status = QLA_ERROR;
+
+               DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%d: abort task FAILED: "
+                   "mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n",
+                   ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0],
+                   mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4]));
+       }
+
+       return status;
+}
+
+/**
  * qla4xxx_reset_lun - issues LUN Reset
  * @ha: Pointer to host adapter structure.
  * @db_entry: Pointer to device database entry
index 2ccad36..38b1d38 100644 (file)
@@ -74,6 +74,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
  */
 static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
                                void (*done) (struct scsi_cmnd *));
+static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
 static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
 static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
 static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
@@ -88,6 +89,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
        .proc_name              = DRIVER_NAME,
        .queuecommand           = qla4xxx_queuecommand,
 
+       .eh_abort_handler       = qla4xxx_eh_abort,
        .eh_device_reset_handler = qla4xxx_eh_device_reset,
        .eh_target_reset_handler = qla4xxx_eh_target_reset,
        .eh_host_reset_handler  = qla4xxx_eh_host_reset,
@@ -384,12 +386,12 @@ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
        if (!srb)
                return srb;
 
-       atomic_set(&srb->ref_count, 1);
+       kref_init(&srb->srb_ref);
        srb->ha = ha;
        srb->ddb = ddb_entry;
        srb->cmd = cmd;
        srb->flags = 0;
-       cmd->SCp.ptr = (void *)srb;
+       CMD_SP(cmd) = (void *)srb;
        cmd->scsi_done = done;
 
        return srb;
@@ -403,12 +405,14 @@ static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
                scsi_dma_unmap(cmd);
                srb->flags &= ~SRB_DMA_VALID;
        }
-       cmd->SCp.ptr = NULL;
+       CMD_SP(cmd) = NULL;
 }
 
-void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
+void qla4xxx_srb_compl(struct kref *ref)
 {
+       struct srb *srb = container_of(ref, struct srb, srb_ref);
        struct scsi_cmnd *cmd = srb->cmd;
+       struct scsi_qla_host *ha = srb->ha;
 
        qla4xxx_srb_free_dma(ha, srb);
 
@@ -685,6 +689,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
             test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
             test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
             test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
+            test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) ||
             test_bit(DPC_AEN, &ha->dpc_flags)) &&
             ha->dpc_thread) {
                DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
@@ -886,11 +891,10 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
                srb = qla4xxx_del_from_active_array(ha, i);
                if (srb != NULL) {
                        srb->cmd->result = DID_RESET << 16;
-                       qla4xxx_srb_compl(ha, srb);
+                       kref_put(&srb->srb_ref, qla4xxx_srb_compl);
                }
        }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
 }
 
 /**
@@ -1069,6 +1073,54 @@ static void qla4xxx_do_dpc(struct work_struct *work)
        if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
                qla4xxx_get_dhcp_ip_address(ha);
 
+       /* ---- link change? --- */
+       if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) {
+               if (!test_bit(AF_LINK_UP, &ha->flags)) {
+                       /* ---- link down? --- */
+                       list_for_each_entry_safe(ddb_entry, dtemp,
+                                                &ha->ddb_list, list) {
+                               if (atomic_read(&ddb_entry->state) ==
+                                               DDB_STATE_ONLINE)
+                                       qla4xxx_mark_device_missing(ha,
+                                                       ddb_entry);
+                       }
+               } else {
+                       /* ---- link up? --- *
+                        * F/W will auto login to all devices ONLY ONCE after
+                        * link up during driver initialization and runtime
+                        * fatal error recovery.  Therefore, the driver must
+                        * manually relogin to devices when recovering from
+                        * connection failures, logouts, expired KATO, etc. */
+
+                       list_for_each_entry_safe(ddb_entry, dtemp,
+                                                       &ha->ddb_list, list) {
+                               if ((atomic_read(&ddb_entry->state) ==
+                                                DDB_STATE_MISSING) ||
+                                   (atomic_read(&ddb_entry->state) ==
+                                                DDB_STATE_DEAD)) {
+                                       if (ddb_entry->fw_ddb_device_state ==
+                                           DDB_DS_SESSION_ACTIVE) {
+                                               atomic_set(&ddb_entry->state,
+                                                          DDB_STATE_ONLINE);
+                                               dev_info(&ha->pdev->dev,
+                                                   "scsi%ld: %s: ddb[%d]"
+                                                   " os[%d] marked"
+                                                   " ONLINE\n",
+                                                   ha->host_no, __func__,
+                                                   ddb_entry->fw_ddb_index,
+                                                   ddb_entry->os_target_id);
+
+                                               iscsi_unblock_session(
+                                                   ddb_entry->sess);
+                                       } else
+                                               qla4xxx_relogin_device(
+                                                   ha, ddb_entry);
+                               }
+
+                       }
+               }
+       }
+
        /* ---- relogin device? --- */
        if (adapter_up(ha) &&
            test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
@@ -1430,12 +1482,14 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev)
 struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)
 {
        struct srb *srb = NULL;
-       struct scsi_cmnd *cmd;
+       struct scsi_cmnd *cmd = NULL;
 
-       if (!(cmd = scsi_host_find_tag(ha->host, index)))
+       cmd = scsi_host_find_tag(ha->host, index);
+       if (!cmd)
                return srb;
 
-       if (!(srb = (struct srb *)cmd->host_scribble))
+       srb = (struct srb *)CMD_SP(cmd);
+       if (!srb)
                return srb;
 
        /* update counters */
@@ -1443,14 +1497,15 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t in
                ha->req_q_count += srb->iocb_cnt;
                ha->iocb_cnt -= srb->iocb_cnt;
                if (srb->cmd)
-                       srb->cmd->host_scribble = NULL;
+                       srb->cmd->host_scribble =
+                               (unsigned char *)(unsigned long) MAX_SRBS;
        }
        return srb;
 }
 
 /**
  * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
- * @ha: actual ha whose done queue will contain the comd returned by firmware.
+ * @ha: Pointer to host adapter structure.
  * @cmd: Scsi Command to wait on.
  *
  * This routine waits for the command to be returned by the Firmware
@@ -1465,7 +1520,7 @@ static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
 
        do {
                /* Checking to see if its returned to OS */
-               rp = (struct srb *) cmd->SCp.ptr;
+               rp = (struct srb *) CMD_SP(cmd);
                if (rp == NULL) {
                        done++;
                        break;
@@ -1534,6 +1589,62 @@ static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
 }
 
 /**
+ * qla4xxx_eh_abort - callback for abort task.
+ * @cmd: Pointer to Linux's SCSI command structure
+ *
+ * This routine is called by the Linux OS to abort the specified
+ * command.
+ **/
+static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
+{
+       struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+       unsigned int id = cmd->device->id;
+       unsigned int lun = cmd->device->lun;
+       unsigned long serial = cmd->serial_number;
+       struct srb *srb = NULL;
+       int ret = SUCCESS;
+       int wait = 0;
+
+       dev_info(&ha->pdev->dev,
+           "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
+           ha->host_no, id, lun, cmd, serial);
+
+       srb = (struct srb *) CMD_SP(cmd);
+
+       if (!srb)
+               return SUCCESS;
+
+       kref_get(&srb->srb_ref);
+
+       if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
+               DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
+                   ha->host_no, id, lun));
+               ret = FAILED;
+       } else {
+               DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n",
+                   ha->host_no, id, lun));
+               wait = 1;
+       }
+
+       kref_put(&srb->srb_ref, qla4xxx_srb_compl);
+
+       /* Wait for command to complete */
+       if (wait) {
+               if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
+                       DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n",
+                           ha->host_no, id, lun));
+                       ret = FAILED;
+               }
+       }
+
+       dev_info(&ha->pdev->dev,
+           "scsi%ld:%d:%d: Abort command - %s\n",
+           ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed");
+
+       return ret;
+}
+
+/**
  * qla4xxx_eh_device_reset - callback for target reset.
  * @cmd: Pointer to Linux's SCSI command structure
  *
index 6980cb2..28a6c49 100644 (file)
@@ -5,5 +5,4 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION "5.01.00-k9"
-
+#define QLA4XXX_DRIVER_VERSION "5.02.00-k1"
index 1c08f61..ad0ed21 100644 (file)
@@ -67,6 +67,9 @@
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/scsi.h>
+
 static void scsi_done(struct scsi_cmnd *cmd);
 
 /*
@@ -747,10 +750,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
                cmd->result = (DID_NO_CONNECT << 16);
                scsi_done(cmd);
        } else {
+               trace_scsi_dispatch_cmd_start(cmd);
                rtn = host->hostt->queuecommand(cmd, scsi_done);
        }
        spin_unlock_irqrestore(host->host_lock, flags);
        if (rtn) {
+               trace_scsi_dispatch_cmd_error(cmd, rtn);
                if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
                    rtn != SCSI_MLQUEUE_TARGET_BUSY)
                        rtn = SCSI_MLQUEUE_HOST_BUSY;
@@ -781,6 +786,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
  */
 static void scsi_done(struct scsi_cmnd *cmd)
 {
+       trace_scsi_dispatch_cmd_done(cmd);
        blk_complete_request(cmd->request);
 }
 
index 3a5bfd1..136329b 100644 (file)
@@ -12,7 +12,7 @@
  *  SAS disks.
  *
  *
- *  For documentation see http://www.torque.net/sg/sdebug26.html
+ *  For documentation see http://sg.danny.cz/sg/sdebug26.html
  *
  *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
  *   dpg: work for devfs large number of disks [20010809]
@@ -58,8 +58,8 @@
 #include "sd.h"
 #include "scsi_logging.h"
 
-#define SCSI_DEBUG_VERSION "1.81"
-static const char * scsi_debug_version_date = "20070104";
+#define SCSI_DEBUG_VERSION "1.82"
+static const char * scsi_debug_version_date = "20100324";
 
 /* Additional Sense Code (ASC) */
 #define NO_ADDITIONAL_SENSE 0x0
@@ -108,6 +108,7 @@ static const char * scsi_debug_version_date = "20070104";
 #define DEF_ATO 1
 #define DEF_PHYSBLK_EXP 0
 #define DEF_LOWEST_ALIGNED 0
+#define DEF_OPT_BLKS 64
 #define DEF_UNMAP_MAX_BLOCKS 0
 #define DEF_UNMAP_MAX_DESC 0
 #define DEF_UNMAP_GRANULARITY 0
@@ -147,12 +148,18 @@ static const char * scsi_debug_version_date = "20070104";
 #define SAM2_LUN_ADDRESS_METHOD 0
 #define SAM2_WLUN_REPORT_LUNS 0xc101
 
+/* Can queue up to this number of commands. Typically commands that
+ * that have a non-zero delay are queued. */
+#define SCSI_DEBUG_CANQUEUE  255
+
 static int scsi_debug_add_host = DEF_NUM_HOST;
 static int scsi_debug_delay = DEF_DELAY;
 static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
 static int scsi_debug_every_nth = DEF_EVERY_NTH;
 static int scsi_debug_max_luns = DEF_MAX_LUNS;
+static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
 static int scsi_debug_num_parts = DEF_NUM_PARTS;
+static int scsi_debug_no_uld = 0;
 static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
 static int scsi_debug_opts = DEF_OPTS;
 static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
@@ -169,6 +176,7 @@ static int scsi_debug_guard = DEF_GUARD;
 static int scsi_debug_ato = DEF_ATO;
 static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
 static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
+static int scsi_debug_opt_blks = DEF_OPT_BLKS;
 static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
 static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
 static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
@@ -192,7 +200,6 @@ static int sdebug_sectors_per;              /* sectors per cylinder */
 
 #define SDEBUG_SENSE_LEN 32
 
-#define SCSI_DEBUG_CANQUEUE  255
 #define SCSI_DEBUG_MAX_CMD_LEN 32
 
 struct sdebug_dev_info {
@@ -699,9 +706,13 @@ static int inquiry_evpd_b0(unsigned char * arr)
        unsigned int gran;
 
        memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
+
+       /* Optimal transfer length granularity */
        gran = 1 << scsi_debug_physblk_exp;
        arr[2] = (gran >> 8) & 0xff;
        arr[3] = gran & 0xff;
+
+       /* Maximum Transfer Length */
        if (sdebug_store_sectors > 0x400) {
                arr[4] = (sdebug_store_sectors >> 24) & 0xff;
                arr[5] = (sdebug_store_sectors >> 16) & 0xff;
@@ -709,6 +720,9 @@ static int inquiry_evpd_b0(unsigned char * arr)
                arr[7] = sdebug_store_sectors & 0xff;
        }
 
+       /* Optimal Transfer Length */
+       put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
+
        if (scsi_debug_unmap_max_desc) {
                unsigned int blocks;
 
@@ -717,15 +731,20 @@ static int inquiry_evpd_b0(unsigned char * arr)
                else
                        blocks = 0xffffffff;
 
+               /* Maximum Unmap LBA Count */
                put_unaligned_be32(blocks, &arr[16]);
+
+               /* Maximum Unmap Block Descriptor Count */
                put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
        }
 
+       /* Unmap Granularity Alignment */
        if (scsi_debug_unmap_alignment) {
                put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
                arr[28] |= 0x80; /* UGAVALID */
        }
 
+       /* Optimal Unmap Granularity */
        if (scsi_debug_unmap_granularity) {
                put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
                return 0x3c; /* Mandatory page length for thin provisioning */
@@ -2266,7 +2285,7 @@ static void timer_intr_handler(unsigned long indx)
        struct sdebug_queued_cmd * sqcp;
        unsigned long iflags;
 
-       if (indx >= SCSI_DEBUG_CANQUEUE) {
+       if (indx >= scsi_debug_max_queue) {
                printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
                       "large\n");
                return;
@@ -2380,6 +2399,8 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)
                scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
                                        sdp->host->cmd_per_lun);
        blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
+       if (scsi_debug_no_uld)
+               sdp->no_uld_attach = 1;
        return 0;
 }
 
@@ -2406,7 +2427,7 @@ static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
        struct sdebug_queued_cmd *sqcp;
 
        spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+       for (k = 0; k < scsi_debug_max_queue; ++k) {
                sqcp = &queued_arr[k];
                if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
                        del_timer_sync(&sqcp->cmnd_timer);
@@ -2416,7 +2437,7 @@ static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
                }
        }
        spin_unlock_irqrestore(&queued_arr_lock, iflags);
-       return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
+       return (k < scsi_debug_max_queue) ? 1 : 0;
 }
 
 /* Deletes (stops) timers of all queued commands */
@@ -2427,7 +2448,7 @@ static void stop_all_queued(void)
        struct sdebug_queued_cmd *sqcp;
 
        spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+       for (k = 0; k < scsi_debug_max_queue; ++k) {
                sqcp = &queued_arr[k];
                if (sqcp->in_use && sqcp->a_cmnd) {
                        del_timer_sync(&sqcp->cmnd_timer);
@@ -2533,7 +2554,7 @@ static void __init init_all_queued(void)
        struct sdebug_queued_cmd * sqcp;
 
        spin_lock_irqsave(&queued_arr_lock, iflags);
-       for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+       for (k = 0; k < scsi_debug_max_queue; ++k) {
                sqcp = &queued_arr[k];
                init_timer(&sqcp->cmnd_timer);
                sqcp->in_use = 0;
@@ -2625,12 +2646,12 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
                struct sdebug_queued_cmd * sqcp = NULL;
 
                spin_lock_irqsave(&queued_arr_lock, iflags);
-               for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+               for (k = 0; k < scsi_debug_max_queue; ++k) {
                        sqcp = &queued_arr[k];
                        if (! sqcp->in_use)
                                break;
                }
-               if (k >= SCSI_DEBUG_CANQUEUE) {
+               if (k >= scsi_debug_max_queue) {
                        spin_unlock_irqrestore(&queued_arr_lock, iflags);
                        printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
                        return 1;       /* report busy to mid level */
@@ -2662,7 +2683,9 @@ module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
 module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
 module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
 module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
+module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
 module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
+module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
 module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
 module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
 module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
@@ -2677,6 +2700,7 @@ module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
 module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
 module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
 module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
+module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
 module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
 module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
 module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
@@ -2695,7 +2719,9 @@ MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
 MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
 MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
 MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
+MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
 MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
+MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
 MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
 MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
 MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
@@ -2705,6 +2731,7 @@ MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)")
 MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
 MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
 MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
+MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
 MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
 MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
 MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
@@ -2970,6 +2997,31 @@ static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
 DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
            sdebug_max_luns_store);
 
+static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
+}
+static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
+                                     const char * buf, size_t count)
+{
+        int n;
+
+       if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
+           (n <= SCSI_DEBUG_CANQUEUE)) {
+               scsi_debug_max_queue = n;
+               return count;
+       }
+       return -EINVAL;
+}
+DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
+           sdebug_max_queue_store);
+
+static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
+}
+DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
+
 static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
 {
         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
@@ -3107,7 +3159,9 @@ static int do_create_driverfs_files(void)
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+       ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+       ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
        ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
@@ -3139,7 +3193,9 @@ static void do_remove_driverfs_files(void)
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+       driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+       driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
        driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
@@ -3830,12 +3886,13 @@ static int sdebug_driver_probe(struct device * dev)
 
        sdbg_host = to_sdebug_host(dev);
 
-        hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
-        if (NULL == hpnt) {
-                printk(KERN_ERR "%s: scsi_register failed\n", __func__);
-                error = -ENODEV;
+       sdebug_driver_template.can_queue = scsi_debug_max_queue;
+       hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
+       if (NULL == hpnt) {
+               printk(KERN_ERR "%s: scsi_register failed\n", __func__);
+               error = -ENODEV;
                return error;
-        }
+       }
 
         sdbg_host->shost = hpnt;
        *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
index 7ad53fa..a5d630f 100644 (file)
@@ -39,6 +39,8 @@
 #include "scsi_logging.h"
 #include "scsi_transport_api.h"
 
+#include <trace/events/scsi.h>
+
 #define SENSE_TIMEOUT          (10*HZ)
 
 /*
@@ -52,6 +54,7 @@
 void scsi_eh_wakeup(struct Scsi_Host *shost)
 {
        if (shost->host_busy == shost->host_failed) {
+               trace_scsi_eh_wakeup(shost);
                wake_up_process(shost->ehandler);
                SCSI_LOG_ERROR_RECOVERY(5,
                                printk("Waking error handler thread\n"));
@@ -127,6 +130,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
        struct scsi_cmnd *scmd = req->special;
        enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
+       trace_scsi_dispatch_cmd_timeout(scmd);
        scsi_log_completion(scmd, TIMEOUT_ERROR);
 
        if (scmd->device->host->transportt->eh_timed_out)
@@ -970,9 +974,10 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                                                  "0x%p\n", current->comm,
                                                  scmd));
                rtn = scsi_try_to_abort_cmd(scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD;
                        if (!scsi_device_online(scmd->device) ||
+                           rtn == FAST_IO_FAIL ||
                            !scsi_eh_tur(scmd)) {
                                scsi_eh_finish_cmd(scmd, done_q);
                        }
@@ -1099,8 +1104,9 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
                                                  " 0x%p\n", current->comm,
                                                  sdev));
                rtn = scsi_try_bus_device_reset(bdr_scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        if (!scsi_device_online(sdev) ||
+                           rtn == FAST_IO_FAIL ||
                            !scsi_eh_tur(bdr_scmd)) {
                                list_for_each_entry_safe(scmd, next,
                                                         work_q, eh_entry) {
@@ -1163,10 +1169,11 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
                                                  "to target %d\n",
                                                  current->comm, id));
                rtn = scsi_try_target_reset(tgtr_scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
                                if (id == scmd_id(scmd))
                                        if (!scsi_device_online(scmd->device) ||
+                                           rtn == FAST_IO_FAIL ||
                                            !scsi_eh_tur(tgtr_scmd))
                                                scsi_eh_finish_cmd(scmd,
                                                                   done_q);
@@ -1222,10 +1229,11 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
                                                  " %d\n", current->comm,
                                                  channel));
                rtn = scsi_try_bus_reset(chan_scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
                                if (channel == scmd_channel(scmd))
                                        if (!scsi_device_online(scmd->device) ||
+                                           rtn == FAST_IO_FAIL ||
                                            !scsi_eh_tur(scmd))
                                                scsi_eh_finish_cmd(scmd,
                                                                   done_q);
@@ -1259,9 +1267,10 @@ static int scsi_eh_host_reset(struct list_head *work_q,
                                                  , current->comm));
 
                rtn = scsi_try_host_reset(scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
                                if (!scsi_device_online(scmd->device) ||
+                                   rtn == FAST_IO_FAIL ||
                                    (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) ||
                                    !scsi_eh_tur(scmd))
                                        scsi_eh_finish_cmd(scmd, done_q);
index 38518b0..c992ecf 100644 (file)
@@ -459,8 +459,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        found_target->reap_ref++;
        spin_unlock_irqrestore(shost->host_lock, flags);
        if (found_target->state != STARGET_DEL) {
-               put_device(parent);
-               kfree(starget);
+               put_device(dev);
                return found_target;
        }
        /* Unfortunately, we found a dying target; need to
index 429c9b7..c23ab97 100644 (file)
@@ -474,7 +474,7 @@ static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL);
 
 
 /*
- * sdev_rd_attr: create a function and attribute variable for a
+ * sdev_rw_attr: create a function and attribute variable for a
  * read/write field.
  */
 #define sdev_rw_attr(field, format_string)                             \
@@ -486,7 +486,7 @@ sdev_store_##field (struct device *dev, struct device_attribute *attr,      \
 {                                                                      \
        struct scsi_device *sdev;                                       \
        sdev = to_scsi_device(dev);                                     \
-       snscanf (buf, 20, format_string, &sdev->field);                 \
+       sscanf (buf, format_string, &sdev->field);                      \
        return count;                                                   \
 }                                                                      \
 static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
@@ -853,9 +853,6 @@ static int scsi_target_add(struct scsi_target *starget)
        error = device_add(&starget->dev);
        if (error) {
                dev_err(&starget->dev, "target device_add failed, error %d\n", error);
-               get_device(&starget->dev);
-               scsi_target_reap(starget);
-               put_device(&starget->dev);
                return error;
        }
        transport_add_device(&starget->dev);
diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c
new file mode 100644 (file)
index 0000000..b587289
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2010 FUJITSU LIMITED
+ * Copyright (C) 2010 Tomohiro Kusumi <kusumi.tomohiro@jp.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/kernel.h>
+#include <linux/trace_seq.h>
+#include <trace/events/scsi.h>
+
+#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
+#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
+
+static const char *
+scsi_trace_misc(struct trace_seq *, unsigned char *, int);
+
+static const char *
+scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len;
+       sector_t lba = 0, txlen = 0;
+
+       lba |= ((cdb[1] & 0x1F) << 16);
+       lba |=  (cdb[2] << 8);
+       lba |=   cdb[3];
+       txlen = cdb[4];
+
+       trace_seq_printf(p, "lba=%llu txlen=%llu",
+                        (unsigned long long)lba, (unsigned long long)txlen);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *
+scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len;
+       sector_t lba = 0, txlen = 0;
+
+       lba |= (cdb[2] << 24);
+       lba |= (cdb[3] << 16);
+       lba |= (cdb[4] << 8);
+       lba |=  cdb[5];
+       txlen |= (cdb[7] << 8);
+       txlen |=  cdb[8];
+
+       trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
+                        (unsigned long long)lba, (unsigned long long)txlen,
+                        cdb[1] >> 5);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *
+scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len;
+       sector_t lba = 0, txlen = 0;
+
+       lba |= (cdb[2] << 24);
+       lba |= (cdb[3] << 16);
+       lba |= (cdb[4] << 8);
+       lba |=  cdb[5];
+       txlen |= (cdb[6] << 24);
+       txlen |= (cdb[7] << 16);
+       txlen |= (cdb[8] << 8);
+       txlen |=  cdb[9];
+
+       trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
+                        (unsigned long long)lba, (unsigned long long)txlen,
+                        cdb[1] >> 5);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *
+scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len;
+       sector_t lba = 0, txlen = 0;
+
+       lba |= ((u64)cdb[2] << 56);
+       lba |= ((u64)cdb[3] << 48);
+       lba |= ((u64)cdb[4] << 40);
+       lba |= ((u64)cdb[5] << 32);
+       lba |= (cdb[6] << 24);
+       lba |= (cdb[7] << 16);
+       lba |= (cdb[8] << 8);
+       lba |=  cdb[9];
+       txlen |= (cdb[10] << 24);
+       txlen |= (cdb[11] << 16);
+       txlen |= (cdb[12] << 8);
+       txlen |=  cdb[13];
+
+       trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
+                        (unsigned long long)lba, (unsigned long long)txlen,
+                        cdb[1] >> 5);
+
+       if (cdb[0] == WRITE_SAME_16)
+               trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
+
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *
+scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len, *cmd;
+       sector_t lba = 0, txlen = 0;
+       u32 ei_lbrt = 0;
+
+       switch (SERVICE_ACTION32(cdb)) {
+       case READ_32:
+               cmd = "READ";
+               break;
+       case VERIFY_32:
+               cmd = "VERIFY";
+               break;
+       case WRITE_32:
+               cmd = "WRITE";
+               break;
+       case WRITE_SAME_32:
+               cmd = "WRITE_SAME";
+               break;
+       default:
+               trace_seq_printf(p, "UNKNOWN");
+               goto out;
+       }
+
+       lba |= ((u64)cdb[12] << 56);
+       lba |= ((u64)cdb[13] << 48);
+       lba |= ((u64)cdb[14] << 40);
+       lba |= ((u64)cdb[15] << 32);
+       lba |= (cdb[16] << 24);
+       lba |= (cdb[17] << 16);
+       lba |= (cdb[18] << 8);
+       lba |=  cdb[19];
+       ei_lbrt |= (cdb[20] << 24);
+       ei_lbrt |= (cdb[21] << 16);
+       ei_lbrt |= (cdb[22] << 8);
+       ei_lbrt |=  cdb[23];
+       txlen |= (cdb[28] << 24);
+       txlen |= (cdb[29] << 16);
+       txlen |= (cdb[30] << 8);
+       txlen |=  cdb[31];
+
+       trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
+                        cmd, (unsigned long long)lba,
+                        (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
+
+       if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
+               trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
+
+out:
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *
+scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len;
+       unsigned int regions = cdb[7] << 8 | cdb[8];
+
+       trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *
+scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len, *cmd;
+       sector_t lba = 0;
+       u32 alloc_len = 0;
+
+       switch (SERVICE_ACTION16(cdb)) {
+       case SAI_READ_CAPACITY_16:
+               cmd = "READ_CAPACITY_16";
+               break;
+       case SAI_GET_LBA_STATUS:
+               cmd = "GET_LBA_STATUS";
+               break;
+       default:
+               trace_seq_printf(p, "UNKNOWN");
+               goto out;
+       }
+
+       lba |= ((u64)cdb[2] << 56);
+       lba |= ((u64)cdb[3] << 48);
+       lba |= ((u64)cdb[4] << 40);
+       lba |= ((u64)cdb[5] << 32);
+       lba |= (cdb[6] << 24);
+       lba |= (cdb[7] << 16);
+       lba |= (cdb[8] << 8);
+       lba |=  cdb[9];
+       alloc_len |= (cdb[10] << 24);
+       alloc_len |= (cdb[11] << 16);
+       alloc_len |= (cdb[12] << 8);
+       alloc_len |=  cdb[13];
+
+       trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
+                        (unsigned long long)lba, alloc_len);
+
+out:
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+static const char *
+scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       switch (SERVICE_ACTION32(cdb)) {
+       case READ_32:
+       case VERIFY_32:
+       case WRITE_32:
+       case WRITE_SAME_32:
+               return scsi_trace_rw32(p, cdb, len);
+       default:
+               return scsi_trace_misc(p, cdb, len);
+       }
+}
+
+static const char *
+scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       const char *ret = p->buffer + p->len;
+
+       trace_seq_printf(p, "-");
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+
+const char *
+scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
+{
+       switch (cdb[0]) {
+       case READ_6:
+       case WRITE_6:
+               return scsi_trace_rw6(p, cdb, len);
+       case READ_10:
+       case VERIFY:
+       case WRITE_10:
+       case WRITE_SAME:
+               return scsi_trace_rw10(p, cdb, len);
+       case READ_12:
+       case VERIFY_12:
+       case WRITE_12:
+               return scsi_trace_rw12(p, cdb, len);
+       case READ_16:
+       case VERIFY_16:
+       case WRITE_16:
+       case WRITE_SAME_16:
+               return scsi_trace_rw16(p, cdb, len);
+       case UNMAP:
+               return scsi_trace_unmap(p, cdb, len);
+       case SERVICE_ACTION_IN:
+               return scsi_trace_service_action_in(p, cdb, len);
+       case VARIABLE_LENGTH_CMD:
+               return scsi_trace_varlen(p, cdb, len);
+       default:
+               return scsi_trace_misc(p, cdb, len);
+       }
+}
index 6cfffc8..0681378 100644 (file)
@@ -834,7 +834,7 @@ static ssize_t
 store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       int val;
+       unsigned long val;
        struct fc_rport *rport = transport_class_to_rport(dev);
        struct Scsi_Host *shost = rport_to_shost(rport);
        struct fc_internal *i = to_fc_internal(shost->transportt);
@@ -848,6 +848,12 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        /*
+        * Check for overflow; dev_loss_tmo is u32
+        */
+       if (val > UINT_MAX)
+               return -EINVAL;
+
+       /*
         * If fast_io_fail is off we have to cap
         * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT
         */
@@ -2865,7 +2871,7 @@ void
 fc_remote_port_delete(struct fc_rport  *rport)
 {
        struct Scsi_Host *shost = rport_to_shost(rport);
-       int timeout = rport->dev_loss_tmo;
+       unsigned long timeout = rport->dev_loss_tmo;
        unsigned long flags;
 
        /*
@@ -3191,23 +3197,33 @@ fc_scsi_scan_rport(struct work_struct *work)
  *
  * This routine can be called from a FC LLD scsi_eh callback. It
  * blocks the scsi_eh thread until the fc_rport leaves the
- * FC_PORTSTATE_BLOCKED. This is necessary to avoid the scsi_eh
- * failing recovery actions for blocked rports which would lead to
- * offlined SCSI devices.
+ * FC_PORTSTATE_BLOCKED, or the fast_io_fail_tmo fires. This is
+ * necessary to avoid the scsi_eh failing recovery actions for blocked
+ * rports which would lead to offlined SCSI devices.
+ *
+ * Returns: 0 if the fc_rport left the state FC_PORTSTATE_BLOCKED.
+ *         FAST_IO_FAIL if the fast_io_fail_tmo fired, this should be
+ *         passed back to scsi_eh.
  */
-void fc_block_scsi_eh(struct scsi_cmnd *cmnd)
+int fc_block_scsi_eh(struct scsi_cmnd *cmnd)
 {
        struct Scsi_Host *shost = cmnd->device->host;
        struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
        unsigned long flags;
 
        spin_lock_irqsave(shost->host_lock, flags);
-       while (rport->port_state == FC_PORTSTATE_BLOCKED) {
+       while (rport->port_state == FC_PORTSTATE_BLOCKED &&
+              !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) {
                spin_unlock_irqrestore(shost->host_lock, flags);
                msleep(1000);
                spin_lock_irqsave(shost->host_lock, flags);
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
+
+       if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)
+               return FAST_IO_FAIL;
+
+       return 0;
 }
 EXPORT_SYMBOL(fc_block_scsi_eh);
 
index de6c603..829cc37 100644 (file)
@@ -1434,6 +1434,8 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
 #error RC16_LEN must not be more than SD_BUF_SIZE
 #endif
 
+#define READ_CAPACITY_RETRIES_ON_RESET 10
+
 static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
                                                unsigned char *buffer)
 {
@@ -1441,7 +1443,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
        struct scsi_sense_hdr sshdr;
        int sense_valid = 0;
        int the_result;
-       int retries = 3;
+       int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
        unsigned int alignment;
        unsigned long long lba;
        unsigned sector_size;
@@ -1470,6 +1472,13 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
                                 * Invalid Field in CDB, just retry
                                 * silently with RC10 */
                                return -EINVAL;
+                       if (sense_valid &&
+                           sshdr.sense_key == UNIT_ATTENTION &&
+                           sshdr.asc == 0x29 && sshdr.ascq == 0x00)
+                               /* Device reset might occur several times,
+                                * give it one more chance */
+                               if (--reset_retries > 0)
+                                       continue;
                }
                retries--;
 
@@ -1528,7 +1537,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
        struct scsi_sense_hdr sshdr;
        int sense_valid = 0;
        int the_result;
-       int retries = 3;
+       int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
        sector_t lba;
        unsigned sector_size;
 
@@ -1544,8 +1553,16 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
                if (media_not_present(sdkp, &sshdr))
                        return -ENODEV;
 
-               if (the_result)
+               if (the_result) {
                        sense_valid = scsi_sense_valid(&sshdr);
+                       if (sense_valid &&
+                           sshdr.sense_key == UNIT_ATTENTION &&
+                           sshdr.asc == 0x29 && sshdr.ascq == 0x00)
+                               /* Device reset might occur several times,
+                                * give it one more chance */
+                               if (--reset_retries > 0)
+                                       continue;
+               }
                retries--;
 
        } while (the_result && retries);
@@ -1574,6 +1591,8 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
 
 static int sd_try_rc16_first(struct scsi_device *sdp)
 {
+       if (sdp->host->max_cmd_len < 16)
+               return 0;
        if (sdp->scsi_level > SCSI_SPC_2)
                return 1;
        if (scsi_device_protection(sdp))
index 5fda881..b701bf2 100644 (file)
@@ -2224,14 +2224,8 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
 
 }
 
-void
-wd33c93_release(void)
-{
-}
-
 EXPORT_SYMBOL(wd33c93_host_reset);
 EXPORT_SYMBOL(wd33c93_init);
-EXPORT_SYMBOL(wd33c93_release);
 EXPORT_SYMBOL(wd33c93_abort);
 EXPORT_SYMBOL(wd33c93_queuecommand);
 EXPORT_SYMBOL(wd33c93_intr);
index 00123f2..1ed5f3b 100644 (file)
@@ -348,6 +348,5 @@ int wd33c93_queuecommand (struct scsi_cmnd *cmd,
 void wd33c93_intr (struct Scsi_Host *instance);
 int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 int wd33c93_host_reset (struct scsi_cmnd *);
-void wd33c93_release(void);
 
 #endif /* WD33C93_H */
index 39e71b0..c082f22 100644 (file)
@@ -25,6 +25,9 @@ const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
 const char *ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
                                     const struct trace_print_flags *symbol_array);
 
+const char *ftrace_print_hex_seq(struct trace_seq *p,
+                                const unsigned char *buf, int len);
+
 /*
  * The trace entry - the most basic unit of tracing. This is what
  * is printed in the end as a single line in the trace output, such as:
index b3a0ee6..f2b9491 100644 (file)
@@ -1,4 +1,3 @@
-header-y += scsi.h
 header-y += scsi_netlink.h
 header-y += scsi_netlink_fc.h
 header-y += scsi_bsg_fc.h
index 747e2c7..8e9b222 100644 (file)
@@ -76,6 +76,7 @@ struct fcp_cmnd32 {
 #define        FCP_PTA_HEADQ       1   /* head of queue task attribute */
 #define        FCP_PTA_ORDERED     2   /* ordered task attribute */
 #define        FCP_PTA_ACA         4   /* auto. contigent allegiance */
+#define        FCP_PTA_MASK        7   /* mask for task attribute field */
 #define        FCP_PRI_SHIFT       3   /* priority field starts in bit 3 */
 #define        FCP_PRI_RESVD_MASK  0x80        /* reserved bits in priority field */
 
index 8eb0a0f..9b4867c 100644 (file)
@@ -74,7 +74,7 @@ static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp)
        adisc->adisc_cmd = ELS_ADISC;
        put_unaligned_be64(lport->wwpn, &adisc->adisc_wwpn);
        put_unaligned_be64(lport->wwnn, &adisc->adisc_wwnn);
-       hton24(adisc->adisc_port_id, fc_host_port_id(lport->host));
+       hton24(adisc->adisc_port_id, lport->port_id);
 }
 
 /**
@@ -127,15 +127,13 @@ static inline int fc_ct_fill(struct fc_lport *lport,
 
        case FC_NS_RFT_ID:
                ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rft));
-               hton24(ct->payload.rft.fid.fp_fid,
-                      fc_host_port_id(lport->host));
+               hton24(ct->payload.rft.fid.fp_fid, lport->port_id);
                ct->payload.rft.fts = lport->fcts;
                break;
 
        case FC_NS_RFF_ID:
                ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id));
-               hton24(ct->payload.rff.fr_fid.fp_fid,
-                      fc_host_port_id(lport->host));
+               hton24(ct->payload.rff.fr_fid.fp_fid, lport->port_id);
                ct->payload.rff.fr_type = FC_TYPE_FCP;
                if (lport->service_params & FCP_SPPF_INIT_FCN)
                        ct->payload.rff.fr_feat = FCP_FEAT_INIT;
@@ -145,16 +143,14 @@ static inline int fc_ct_fill(struct fc_lport *lport,
 
        case FC_NS_RNN_ID:
                ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id));
-               hton24(ct->payload.rn.fr_fid.fp_fid,
-                      fc_host_port_id(lport->host));
+               hton24(ct->payload.rn.fr_fid.fp_fid, lport->port_id);
                put_unaligned_be64(lport->wwnn, &ct->payload.rn.fr_wwn);
                break;
 
        case FC_NS_RSPN_ID:
                len = strnlen(fc_host_symbolic_name(lport->host), 255);
                ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rspn) + len);
-               hton24(ct->payload.spn.fr_fid.fp_fid,
-                      fc_host_port_id(lport->host));
+               hton24(ct->payload.spn.fr_fid.fp_fid, lport->port_id);
                strncpy(ct->payload.spn.fr_name,
                        fc_host_symbolic_name(lport->host), len);
                ct->payload.spn.fr_name_len = len;
@@ -268,7 +264,7 @@ static inline void fc_logo_fill(struct fc_lport *lport, struct fc_frame *fp)
        logo = fc_frame_payload_get(fp, sizeof(*logo));
        memset(logo, 0, sizeof(*logo));
        logo->fl_cmd = ELS_LOGO;
-       hton24(logo->fl_n_port_id, fc_host_port_id(lport->host));
+       hton24(logo->fl_n_port_id, lport->port_id);
        logo->fl_n_port_wwn = htonll(lport->wwpn);
 }
 
@@ -295,7 +291,7 @@ static inline void fc_rec_fill(struct fc_lport *lport, struct fc_frame *fp)
        rec = fc_frame_payload_get(fp, sizeof(*rec));
        memset(rec, 0, sizeof(*rec));
        rec->rec_cmd = ELS_REC;
-       hton24(rec->rec_s_id, fc_host_port_id(lport->host));
+       hton24(rec->rec_s_id, lport->port_id);
        rec->rec_ox_id = htons(ep->oxid);
        rec->rec_rx_id = htons(ep->rxid);
 }
index 4b912ee..7495c0b 100644 (file)
 #define ntohll(x) be64_to_cpu(x)
 #define htonll(x) cpu_to_be64(x)
 
-#define ntoh24(p) (((p)[0] << 16) | ((p)[1] << 8) | ((p)[2]))
 
-#define hton24(p, v)   do {                    \
-               p[0] = (((v) >> 16) & 0xFF);    \
-               p[1] = (((v) >> 8) & 0xFF);     \
-               p[2] = ((v) & 0xFF);            \
-       } while (0)
+static inline u32 ntoh24(const u8 *p)
+{
+       return (p[0] << 16) | (p[1] << 8) | p[2];
+}
+
+static inline void hton24(u8 *p, u32 v)
+{
+       p[0] = (v >> 16) & 0xff;
+       p[1] = (v >> 8) & 0xff;
+       p[2] = v & 0xff;
+}
 
 /**
  * enum fc_lport_state - Local port states
@@ -775,6 +780,7 @@ struct fc_disc {
  * @dev_stats:             FCoE device stats (TODO: libfc should not be
  *                         FCoE aware)
  * @retry_count:           Number of retries in the current state
+ * @port_id:               FC Port ID
  * @wwpn:                  World Wide Port Name
  * @wwnn:                  World Wide Node Name
  * @service_params:        Common service parameters
@@ -821,6 +827,7 @@ struct fc_lport {
        u8                             retry_count;
 
        /* Fabric information */
+       u32                            port_id;
        u64                            wwpn;
        u64                            wwnn;
        unsigned int                   service_params;
@@ -918,15 +925,6 @@ static inline void fc_lport_free_stats(struct fc_lport *lport)
 }
 
 /**
- * fc_lport_get_stats() - Get a local port's statistics
- * @lport: The local port whose statistics are to be retreived
- */
-static inline struct fcoe_dev_stats *fc_lport_get_stats(struct fc_lport *lport)
-{
-       return per_cpu_ptr(lport->dev_stats, smp_processor_id());
-}
-
-/**
  * lport_priv() - Return the private data from a local port
  * @lport: The local port whose private data is to be retreived
  */
@@ -1053,7 +1051,6 @@ void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id);
  * Functions for fc_functions_template
  */
 void fc_get_host_speed(struct Scsi_Host *);
-void fc_get_host_port_type(struct Scsi_Host *);
 void fc_get_host_port_state(struct Scsi_Host *);
 void fc_set_rport_loss_tmo(struct fc_rport *, u32 timeout);
 struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *);
index c603f4a..ec13f51 100644 (file)
@@ -29,6 +29,8 @@
 #include <scsi/fc/fc_fcoe.h>
 #include <scsi/libfc.h>
 
+#define FCOE_MAX_CMD_LEN       16      /* Supported CDB length */
+
 /*
  * FIP tunable parameters.
  */
@@ -65,14 +67,12 @@ enum fip_state {
  * @port_ka_time:  time of next port keep-alive.
  * @ctlr_ka_time:  time of next controller keep-alive.
  * @timer:        timer struct used for all delayed events.
- * @link_work:    &work_struct for doing FCF selection.
+ * @timer_work:           &work_struct for doing keep-alives and resets.
  * @recv_work:    &work_struct for receiving FIP frames.
  * @fip_recv_list: list of received FIP frames.
  * @user_mfs:     configured maximum FC frame size, including FC header.
  * @flogi_oxid:    exchange ID of most recent fabric login.
  * @flogi_count:   number of FLOGI attempts in AUTO mode.
- * @link:         current link status for libfc.
- * @last_link:    last link state reported to libfc.
  * @map_dest:     use the FC_MAP mode for destination MAC addresses.
  * @spma:         supports SPMA server-provided MACs mode
  * @send_ctlr_ka:  need to send controller keep alive
@@ -100,14 +100,12 @@ struct fcoe_ctlr {
        unsigned long port_ka_time;
        unsigned long ctlr_ka_time;
        struct timer_list timer;
-       struct work_struct link_work;
+       struct work_struct timer_work;
        struct work_struct recv_work;
        struct sk_buff_head fip_recv_list;
        u16 user_mfs;
        u16 flogi_oxid;
        u8 flogi_count;
-       u8 link;
-       u8 last_link;
        u8 reset_req;
        u8 map_dest;
        u8 spma;
index 8b4deca..9ae5c61 100644 (file)
@@ -114,6 +114,7 @@ struct scsi_cmnd;
 #define READ_12               0xa8
 #define WRITE_12              0xaa
 #define WRITE_VERIFY_12       0xae
+#define VERIFY_12            0xaf
 #define SEARCH_HIGH_12        0xb0
 #define SEARCH_EQUAL_12       0xb1
 #define SEARCH_LOW_12         0xb2
@@ -134,6 +135,7 @@ struct scsi_cmnd;
 #define MO_SET_TARGET_PGS     0x0a
 /* values for variable length command */
 #define READ_32                      0x09
+#define VERIFY_32            0x0a
 #define WRITE_32             0x0b
 #define WRITE_SAME_32        0x0d
 
@@ -423,6 +425,7 @@ static inline int scsi_is_wlun(unsigned int lun)
 #define ADD_TO_MLQUEUE  0x2006
 #define TIMEOUT_ERROR   0x2007
 #define SCSI_RETURN_NOT_HANDLED   0x2008
+#define FAST_IO_FAIL   0x2009
 
 /*
  * Midlevel queue return values.
index 8e86a94..87d81b3 100644 (file)
@@ -807,6 +807,6 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
 struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel,
                struct fc_vport_identifiers *);
 int fc_vport_terminate(struct fc_vport *vport);
-void fc_block_scsi_eh(struct scsi_cmnd *cmnd);
+int fc_block_scsi_eh(struct scsi_cmnd *cmnd);
 
 #endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/trace/events/scsi.h b/include/trace/events/scsi.h
new file mode 100644 (file)
index 0000000..25fbefd
--- /dev/null
@@ -0,0 +1,345 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM scsi
+
+#if !defined(_TRACE_SCSI_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SCSI_H
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#define scsi_opcode_name(opcode)       { opcode, #opcode }
+#define show_opcode_name(val)                                  \
+       __print_symbolic(val,                                   \
+               scsi_opcode_name(TEST_UNIT_READY),              \
+               scsi_opcode_name(REZERO_UNIT),                  \
+               scsi_opcode_name(REQUEST_SENSE),                \
+               scsi_opcode_name(FORMAT_UNIT),                  \
+               scsi_opcode_name(READ_BLOCK_LIMITS),            \
+               scsi_opcode_name(REASSIGN_BLOCKS),              \
+               scsi_opcode_name(INITIALIZE_ELEMENT_STATUS),    \
+               scsi_opcode_name(READ_6),                       \
+               scsi_opcode_name(WRITE_6),                      \
+               scsi_opcode_name(SEEK_6),                       \
+               scsi_opcode_name(READ_REVERSE),                 \
+               scsi_opcode_name(WRITE_FILEMARKS),              \
+               scsi_opcode_name(SPACE),                        \
+               scsi_opcode_name(INQUIRY),                      \
+               scsi_opcode_name(RECOVER_BUFFERED_DATA),        \
+               scsi_opcode_name(MODE_SELECT),                  \
+               scsi_opcode_name(RESERVE),                      \
+               scsi_opcode_name(RELEASE),                      \
+               scsi_opcode_name(COPY),                         \
+               scsi_opcode_name(ERASE),                        \
+               scsi_opcode_name(MODE_SENSE),                   \
+               scsi_opcode_name(START_STOP),                   \
+               scsi_opcode_name(RECEIVE_DIAGNOSTIC),           \
+               scsi_opcode_name(SEND_DIAGNOSTIC),              \
+               scsi_opcode_name(ALLOW_MEDIUM_REMOVAL),         \
+               scsi_opcode_name(SET_WINDOW),                   \
+               scsi_opcode_name(READ_CAPACITY),                \
+               scsi_opcode_name(READ_10),                      \
+               scsi_opcode_name(WRITE_10),                     \
+               scsi_opcode_name(SEEK_10),                      \
+               scsi_opcode_name(POSITION_TO_ELEMENT),          \
+               scsi_opcode_name(WRITE_VERIFY),                 \
+               scsi_opcode_name(VERIFY),                       \
+               scsi_opcode_name(SEARCH_HIGH),                  \
+               scsi_opcode_name(SEARCH_EQUAL),                 \
+               scsi_opcode_name(SEARCH_LOW),                   \
+               scsi_opcode_name(SET_LIMITS),                   \
+               scsi_opcode_name(PRE_FETCH),                    \
+               scsi_opcode_name(READ_POSITION),                \
+               scsi_opcode_name(SYNCHRONIZE_CACHE),            \
+               scsi_opcode_name(LOCK_UNLOCK_CACHE),            \
+               scsi_opcode_name(READ_DEFECT_DATA),             \
+               scsi_opcode_name(MEDIUM_SCAN),                  \
+               scsi_opcode_name(COMPARE),                      \
+               scsi_opcode_name(COPY_VERIFY),                  \
+               scsi_opcode_name(WRITE_BUFFER),                 \
+               scsi_opcode_name(READ_BUFFER),                  \
+               scsi_opcode_name(UPDATE_BLOCK),                 \
+               scsi_opcode_name(READ_LONG),                    \
+               scsi_opcode_name(WRITE_LONG),                   \
+               scsi_opcode_name(CHANGE_DEFINITION),            \
+               scsi_opcode_name(WRITE_SAME),                   \
+               scsi_opcode_name(UNMAP),                        \
+               scsi_opcode_name(READ_TOC),                     \
+               scsi_opcode_name(LOG_SELECT),                   \
+               scsi_opcode_name(LOG_SENSE),                    \
+               scsi_opcode_name(XDWRITEREAD_10),               \
+               scsi_opcode_name(MODE_SELECT_10),               \
+               scsi_opcode_name(RESERVE_10),                   \
+               scsi_opcode_name(RELEASE_10),                   \
+               scsi_opcode_name(MODE_SENSE_10),                \
+               scsi_opcode_name(PERSISTENT_RESERVE_IN),        \
+               scsi_opcode_name(PERSISTENT_RESERVE_OUT),       \
+               scsi_opcode_name(VARIABLE_LENGTH_CMD),          \
+               scsi_opcode_name(REPORT_LUNS),                  \
+               scsi_opcode_name(MAINTENANCE_IN),               \
+               scsi_opcode_name(MAINTENANCE_OUT),              \
+               scsi_opcode_name(MOVE_MEDIUM),                  \
+               scsi_opcode_name(EXCHANGE_MEDIUM),              \
+               scsi_opcode_name(READ_12),                      \
+               scsi_opcode_name(WRITE_12),                     \
+               scsi_opcode_name(WRITE_VERIFY_12),              \
+               scsi_opcode_name(SEARCH_HIGH_12),               \
+               scsi_opcode_name(SEARCH_EQUAL_12),              \
+               scsi_opcode_name(SEARCH_LOW_12),                \
+               scsi_opcode_name(READ_ELEMENT_STATUS),          \
+               scsi_opcode_name(SEND_VOLUME_TAG),              \
+               scsi_opcode_name(WRITE_LONG_2),                 \
+               scsi_opcode_name(READ_16),                      \
+               scsi_opcode_name(WRITE_16),                     \
+               scsi_opcode_name(VERIFY_16),                    \
+               scsi_opcode_name(WRITE_SAME_16),                \
+               scsi_opcode_name(SERVICE_ACTION_IN),            \
+               scsi_opcode_name(SAI_READ_CAPACITY_16),         \
+               scsi_opcode_name(SAI_GET_LBA_STATUS),           \
+               scsi_opcode_name(MI_REPORT_TARGET_PGS),         \
+               scsi_opcode_name(MO_SET_TARGET_PGS),            \
+               scsi_opcode_name(READ_32),                      \
+               scsi_opcode_name(WRITE_32),                     \
+               scsi_opcode_name(WRITE_SAME_32),                \
+               scsi_opcode_name(ATA_16),                       \
+               scsi_opcode_name(ATA_12))
+
+#define scsi_hostbyte_name(result)     { result, #result }
+#define show_hostbyte_name(val)                                        \
+       __print_symbolic(val,                                   \
+               scsi_hostbyte_name(DID_OK),                     \
+               scsi_hostbyte_name(DID_NO_CONNECT),             \
+               scsi_hostbyte_name(DID_BUS_BUSY),               \
+               scsi_hostbyte_name(DID_TIME_OUT),               \
+               scsi_hostbyte_name(DID_BAD_TARGET),             \
+               scsi_hostbyte_name(DID_ABORT),                  \
+               scsi_hostbyte_name(DID_PARITY),                 \
+               scsi_hostbyte_name(DID_ERROR),                  \
+               scsi_hostbyte_name(DID_RESET),                  \
+               scsi_hostbyte_name(DID_BAD_INTR),               \
+               scsi_hostbyte_name(DID_PASSTHROUGH),            \
+               scsi_hostbyte_name(DID_SOFT_ERROR),             \
+               scsi_hostbyte_name(DID_IMM_RETRY),              \
+               scsi_hostbyte_name(DID_REQUEUE),                \
+               scsi_hostbyte_name(DID_TRANSPORT_DISRUPTED),    \
+               scsi_hostbyte_name(DID_TRANSPORT_FAILFAST))
+
+#define scsi_driverbyte_name(result)   { result, #result }
+#define show_driverbyte_name(val)                              \
+       __print_symbolic(val,                                   \
+               scsi_driverbyte_name(DRIVER_OK),                \
+               scsi_driverbyte_name(DRIVER_BUSY),              \
+               scsi_driverbyte_name(DRIVER_SOFT),              \
+               scsi_driverbyte_name(DRIVER_MEDIA),             \
+               scsi_driverbyte_name(DRIVER_ERROR),             \
+               scsi_driverbyte_name(DRIVER_INVALID),           \
+               scsi_driverbyte_name(DRIVER_TIMEOUT),           \
+               scsi_driverbyte_name(DRIVER_HARD),              \
+               scsi_driverbyte_name(DRIVER_SENSE))
+
+#define scsi_msgbyte_name(result)      { result, #result }
+#define show_msgbyte_name(val)                                 \
+       __print_symbolic(val,                                   \
+               scsi_msgbyte_name(COMMAND_COMPLETE),            \
+               scsi_msgbyte_name(EXTENDED_MESSAGE),            \
+               scsi_msgbyte_name(SAVE_POINTERS),               \
+               scsi_msgbyte_name(RESTORE_POINTERS),            \
+               scsi_msgbyte_name(DISCONNECT),                  \
+               scsi_msgbyte_name(INITIATOR_ERROR),             \
+               scsi_msgbyte_name(ABORT_TASK_SET),              \
+               scsi_msgbyte_name(MESSAGE_REJECT),              \
+               scsi_msgbyte_name(NOP),                         \
+               scsi_msgbyte_name(MSG_PARITY_ERROR),            \
+               scsi_msgbyte_name(LINKED_CMD_COMPLETE),         \
+               scsi_msgbyte_name(LINKED_FLG_CMD_COMPLETE),     \
+               scsi_msgbyte_name(TARGET_RESET),                \
+               scsi_msgbyte_name(ABORT_TASK),                  \
+               scsi_msgbyte_name(CLEAR_TASK_SET),              \
+               scsi_msgbyte_name(INITIATE_RECOVERY),           \
+               scsi_msgbyte_name(RELEASE_RECOVERY),            \
+               scsi_msgbyte_name(CLEAR_ACA),                   \
+               scsi_msgbyte_name(LOGICAL_UNIT_RESET),          \
+               scsi_msgbyte_name(SIMPLE_QUEUE_TAG),            \
+               scsi_msgbyte_name(HEAD_OF_QUEUE_TAG),           \
+               scsi_msgbyte_name(ORDERED_QUEUE_TAG),           \
+               scsi_msgbyte_name(IGNORE_WIDE_RESIDUE),         \
+               scsi_msgbyte_name(ACA),                         \
+               scsi_msgbyte_name(QAS_REQUEST),                 \
+               scsi_msgbyte_name(BUS_DEVICE_RESET),            \
+               scsi_msgbyte_name(ABORT))
+
+#define scsi_statusbyte_name(result)   { result, #result }
+#define show_statusbyte_name(val)                              \
+       __print_symbolic(val,                                   \
+               scsi_statusbyte_name(SAM_STAT_GOOD),            \
+               scsi_statusbyte_name(SAM_STAT_CHECK_CONDITION), \
+               scsi_statusbyte_name(SAM_STAT_CONDITION_MET),   \
+               scsi_statusbyte_name(SAM_STAT_BUSY),            \
+               scsi_statusbyte_name(SAM_STAT_INTERMEDIATE),    \
+               scsi_statusbyte_name(SAM_STAT_INTERMEDIATE_CONDITION_MET), \
+               scsi_statusbyte_name(SAM_STAT_RESERVATION_CONFLICT),    \
+               scsi_statusbyte_name(SAM_STAT_COMMAND_TERMINATED),      \
+               scsi_statusbyte_name(SAM_STAT_TASK_SET_FULL),   \
+               scsi_statusbyte_name(SAM_STAT_ACA_ACTIVE),      \
+               scsi_statusbyte_name(SAM_STAT_TASK_ABORTED))
+
+const char *scsi_trace_parse_cdb(struct trace_seq*, unsigned char*, int);
+#define __parse_cdb(cdb, len) scsi_trace_parse_cdb(p, cdb, len)
+
+TRACE_EVENT(scsi_dispatch_cmd_start,
+
+       TP_PROTO(struct scsi_cmnd *cmd),
+
+       TP_ARGS(cmd),
+
+       TP_STRUCT__entry(
+               __field( unsigned int,  host_no )
+               __field( unsigned int,  channel )
+               __field( unsigned int,  id      )
+               __field( unsigned int,  lun     )
+               __field( unsigned int,  opcode  )
+               __field( unsigned int,  cmd_len )
+               __field( unsigned int,  data_sglen )
+               __field( unsigned int,  prot_sglen )
+               __dynamic_array(unsigned char,  cmnd, cmd->cmd_len)
+       ),
+
+       TP_fast_assign(
+               __entry->host_no        = cmd->device->host->host_no;
+               __entry->channel        = cmd->device->channel;
+               __entry->id             = cmd->device->id;
+               __entry->lun            = cmd->device->lun;
+               __entry->opcode         = cmd->cmnd[0];
+               __entry->cmd_len        = cmd->cmd_len;
+               __entry->data_sglen     = scsi_sg_count(cmd);
+               __entry->prot_sglen     = scsi_prot_sg_count(cmd);
+               memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len);
+       ),
+
+       TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \
+                 " cmnd=(%s %s raw=%s)",
+                 __entry->host_no, __entry->channel, __entry->id,
+                 __entry->lun, __entry->data_sglen, __entry->prot_sglen,
+                 show_opcode_name(__entry->opcode),
+                 __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len),
+                 __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len))
+);
+
+TRACE_EVENT(scsi_dispatch_cmd_error,
+
+       TP_PROTO(struct scsi_cmnd *cmd, int rtn),
+
+       TP_ARGS(cmd, rtn),
+
+       TP_STRUCT__entry(
+               __field( unsigned int,  host_no )
+               __field( unsigned int,  channel )
+               __field( unsigned int,  id      )
+               __field( unsigned int,  lun     )
+               __field( int,           rtn     )
+               __field( unsigned int,  opcode  )
+               __field( unsigned int,  cmd_len )
+               __field( unsigned int,  data_sglen )
+               __field( unsigned int,  prot_sglen )
+               __dynamic_array(unsigned char,  cmnd, cmd->cmd_len)
+       ),
+
+       TP_fast_assign(
+               __entry->host_no        = cmd->device->host->host_no;
+               __entry->channel        = cmd->device->channel;
+               __entry->id             = cmd->device->id;
+               __entry->lun            = cmd->device->lun;
+               __entry->rtn            = rtn;
+               __entry->opcode         = cmd->cmnd[0];
+               __entry->cmd_len        = cmd->cmd_len;
+               __entry->data_sglen     = scsi_sg_count(cmd);
+               __entry->prot_sglen     = scsi_prot_sg_count(cmd);
+               memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len);
+       ),
+
+       TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u prot_sgl=%u" \
+                 " cmnd=(%s %s raw=%s) rtn=%d",
+                 __entry->host_no, __entry->channel, __entry->id,
+                 __entry->lun, __entry->data_sglen, __entry->prot_sglen,
+                 show_opcode_name(__entry->opcode),
+                 __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len),
+                 __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len),
+                 __entry->rtn)
+);
+
+DECLARE_EVENT_CLASS(scsi_cmd_done_timeout_template,
+
+       TP_PROTO(struct scsi_cmnd *cmd),
+
+       TP_ARGS(cmd),
+
+       TP_STRUCT__entry(
+               __field( unsigned int,  host_no )
+               __field( unsigned int,  channel )
+               __field( unsigned int,  id      )
+               __field( unsigned int,  lun     )
+               __field( int,           result  )
+               __field( unsigned int,  opcode  )
+               __field( unsigned int,  cmd_len )
+               __field( unsigned int,  data_sglen )
+               __field( unsigned int,  prot_sglen )
+               __dynamic_array(unsigned char,  cmnd, cmd->cmd_len)
+       ),
+
+       TP_fast_assign(
+               __entry->host_no        = cmd->device->host->host_no;
+               __entry->channel        = cmd->device->channel;
+               __entry->id             = cmd->device->id;
+               __entry->lun            = cmd->device->lun;
+               __entry->result         = cmd->result;
+               __entry->opcode         = cmd->cmnd[0];
+               __entry->cmd_len        = cmd->cmd_len;
+               __entry->data_sglen     = scsi_sg_count(cmd);
+               __entry->prot_sglen     = scsi_prot_sg_count(cmd);
+               memcpy(__get_dynamic_array(cmnd), cmd->cmnd, cmd->cmd_len);
+       ),
+
+       TP_printk("host_no=%u channel=%u id=%u lun=%u data_sgl=%u " \
+                 "prot_sgl=%u cmnd=(%s %s raw=%s) result=(driver=%s host=%s " \
+                 "message=%s status=%s)",
+                 __entry->host_no, __entry->channel, __entry->id,
+                 __entry->lun, __entry->data_sglen, __entry->prot_sglen,
+                 show_opcode_name(__entry->opcode),
+                 __parse_cdb(__get_dynamic_array(cmnd), __entry->cmd_len),
+                 __print_hex(__get_dynamic_array(cmnd), __entry->cmd_len),
+                 show_driverbyte_name(((__entry->result) >> 24) & 0xff),
+                 show_hostbyte_name(((__entry->result) >> 16) & 0xff),
+                 show_msgbyte_name(((__entry->result) >> 8) & 0xff),
+                 show_statusbyte_name(__entry->result & 0xff))
+);
+
+DEFINE_EVENT(scsi_cmd_done_timeout_template, scsi_dispatch_cmd_done,
+            TP_PROTO(struct scsi_cmnd *cmd),
+            TP_ARGS(cmd));
+
+DEFINE_EVENT(scsi_cmd_done_timeout_template, scsi_dispatch_cmd_timeout,
+            TP_PROTO(struct scsi_cmnd *cmd),
+            TP_ARGS(cmd));
+
+TRACE_EVENT(scsi_eh_wakeup,
+
+       TP_PROTO(struct Scsi_Host *shost),
+
+       TP_ARGS(shost),
+
+       TP_STRUCT__entry(
+               __field( unsigned int,  host_no )
+       ),
+
+       TP_fast_assign(
+               __entry->host_no        = shost->host_no;
+       ),
+
+       TP_printk("host_no=%u", __entry->host_no)
+);
+
+#endif /*  _TRACE_SCSI_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 16253db..88c59c1 100644 (file)
                ftrace_print_symbols_seq(p, value, symbols);            \
        })
 
+#undef __print_hex
+#define __print_hex(buf, buf_len) ftrace_print_hex_seq(p, buf, buf_len)
+
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
 static notrace enum print_line_t                                       \
index 2404c12..ab13d70 100644 (file)
@@ -209,6 +209,7 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c)
 
        return 1;
 }
+EXPORT_SYMBOL(trace_seq_putc);
 
 int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)
 {
@@ -355,6 +356,21 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
 }
 EXPORT_SYMBOL(ftrace_print_symbols_seq);
 
+const char *
+ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len)
+{
+       int i;
+       const char *ret = p->buffer + p->len;
+
+       for (i = 0; i < buf_len; i++)
+               trace_seq_printf(p, "%s%2.2x", i == 0 ? "" : " ", buf[i]);
+
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(ftrace_print_hex_seq);
+
 #ifdef CONFIG_KRETPROBES
 static inline const char *kretprobed(const char *name)
 {