[SCSI] lpfc 8.3.8: BugFixes: SLI relates changes
authorJames Smart <james.smart@emulex.com>
Wed, 27 Jan 2010 04:07:37 +0000 (23:07 -0500)
committerJames Bottomley <James.Bottomley@suse.de>
Tue, 9 Feb 2010 00:37:53 +0000 (18:37 -0600)
Fix hardware/SLI relates issues:
- Handle XB bit so that ELS XRIs are not prematurely released.
- Handle XB bit so that FCP XRIs are not prematurely released.
- Define new security SLI Commands.
- Remove unused security SLI commands
- Skip receive data size parameter check on received FLOGI.
- Added LPFC_USE_FCPWQIDX flag to iocb to force SLI layer
  to submit abort WQE on same WQ as the command WQE.

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_scsi.h
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h

index 650494d..14ee7d4 100644 (file)
@@ -99,7 +99,7 @@ int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
 
 void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
 int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
-                    struct serv_parm *, uint32_t);
+                    struct serv_parm *, uint32_t, int);
 int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
 void lpfc_more_plogi(struct lpfc_vport *);
 void lpfc_more_adisc(struct lpfc_vport *);
index 2cc3968..32e3c8d 100644 (file)
@@ -4385,7 +4385,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
        did = Fabric_DID;
 
-       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
+       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
                /* For a FLOGI we accept, then if our portname is greater
                 * then the remote portname we initiate Nport login.
                 */
index c9faa1d..44c2587 100644 (file)
@@ -1465,17 +1465,13 @@ typedef struct {                /* FireFly BIU registers */
 #define CMD_IOCB_LOGENTRY_CN           0x94
 #define CMD_IOCB_LOGENTRY_ASYNC_CN     0x96
 
-/* Unhandled Data Security SLI Commands */
-#define DSSCMD_IWRITE64_CR             0xD8
-#define DSSCMD_IWRITE64_CX             0xD9
-#define DSSCMD_IREAD64_CR              0xDA
-#define DSSCMD_IREAD64_CX              0xDB
-#define DSSCMD_INVALIDATE_DEK          0xDC
-#define DSSCMD_SET_KEK                 0xDD
-#define DSSCMD_GET_KEK_ID              0xDE
-#define DSSCMD_GEN_XFER                        0xDF
-
-#define CMD_MAX_IOCB_CMD        0xE6
+/* Data Security SLI Commands */
+#define DSSCMD_IWRITE64_CR             0xF8
+#define DSSCMD_IWRITE64_CX             0xF9
+#define DSSCMD_IREAD64_CR              0xFA
+#define DSSCMD_IREAD64_CX              0xFB
+
+#define CMD_MAX_IOCB_CMD        0xFB
 #define CMD_IOCB_MASK           0xff
 
 #define MAX_MSG_DATA            28     /* max msg data in CMD_ADAPTER_MSG
index 2ed6af1..293234a 100644 (file)
@@ -62,7 +62,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 int
 lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
-                struct serv_parm * sp, uint32_t class)
+                struct serv_parm *sp, uint32_t class, int flogi)
 {
        volatile struct serv_parm *hsp = &vport->fc_sparam;
        uint16_t hsp_value, ssp_value = 0;
@@ -75,49 +75,56 @@ lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
         * correcting the byte values.
         */
        if (sp->cls1.classValid) {
-               hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) |
-                               hsp->cls1.rcvDataSizeLsb;
-               ssp_value = (sp->cls1.rcvDataSizeMsb << 8) |
-                               sp->cls1.rcvDataSizeLsb;
-               if (!ssp_value)
-                       goto bad_service_param;
-               if (ssp_value > hsp_value) {
-                       sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
-                       sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
+               if (!flogi) {
+                       hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) |
+                                    hsp->cls1.rcvDataSizeLsb);
+                       ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) |
+                                    sp->cls1.rcvDataSizeLsb);
+                       if (!ssp_value)
+                               goto bad_service_param;
+                       if (ssp_value > hsp_value) {
+                               sp->cls1.rcvDataSizeLsb =
+                                       hsp->cls1.rcvDataSizeLsb;
+                               sp->cls1.rcvDataSizeMsb =
+                                       hsp->cls1.rcvDataSizeMsb;
+                       }
                }
-       } else if (class == CLASS1) {
+       } else if (class == CLASS1)
                goto bad_service_param;
-       }
-
        if (sp->cls2.classValid) {
-               hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) |
-                               hsp->cls2.rcvDataSizeLsb;
-               ssp_value = (sp->cls2.rcvDataSizeMsb << 8) |
-                               sp->cls2.rcvDataSizeLsb;
-               if (!ssp_value)
-                       goto bad_service_param;
-               if (ssp_value > hsp_value) {
-                       sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
-                       sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
+               if (!flogi) {
+                       hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) |
+                                    hsp->cls2.rcvDataSizeLsb);
+                       ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) |
+                                    sp->cls2.rcvDataSizeLsb);
+                       if (!ssp_value)
+                               goto bad_service_param;
+                       if (ssp_value > hsp_value) {
+                               sp->cls2.rcvDataSizeLsb =
+                                       hsp->cls2.rcvDataSizeLsb;
+                               sp->cls2.rcvDataSizeMsb =
+                                       hsp->cls2.rcvDataSizeMsb;
+                       }
                }
-       } else if (class == CLASS2) {
+       } else if (class == CLASS2)
                goto bad_service_param;
-       }
-
        if (sp->cls3.classValid) {
-               hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) |
-                               hsp->cls3.rcvDataSizeLsb;
-               ssp_value = (sp->cls3.rcvDataSizeMsb << 8) |
-                               sp->cls3.rcvDataSizeLsb;
-               if (!ssp_value)
-                       goto bad_service_param;
-               if (ssp_value > hsp_value) {
-                       sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
-                       sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
+               if (!flogi) {
+                       hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) |
+                                    hsp->cls3.rcvDataSizeLsb);
+                       ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) |
+                                    sp->cls3.rcvDataSizeLsb);
+                       if (!ssp_value)
+                               goto bad_service_param;
+                       if (ssp_value > hsp_value) {
+                               sp->cls3.rcvDataSizeLsb =
+                                       hsp->cls3.rcvDataSizeLsb;
+                               sp->cls3.rcvDataSizeMsb =
+                                       hsp->cls3.rcvDataSizeMsb;
+                       }
                }
-       } else if (class == CLASS3) {
+       } else if (class == CLASS3)
                goto bad_service_param;
-       }
 
        /*
         * Preserve the upper four bits of the MSB from the PLOGI response.
@@ -295,7 +302,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        NULL);
                return 0;
        }
-       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
+       if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) {
                /* Reject this request because invalid parameters */
                stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
                stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
@@ -831,7 +838,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
                                 "0142 PLOGI RSP: Invalid WWN.\n");
                goto out;
        }
-       if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
+       if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0))
                goto out;
        /* PLOGI chkparm OK */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
index a246410..d5cc6b8 100644 (file)
@@ -626,6 +626,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
                &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) {
                if (psb->cur_iocbq.sli4_xritag == xri) {
                        list_del(&psb->list);
+                       psb->exch_busy = 0;
                        psb->status = IOSTAT_SUCCESS;
                        spin_unlock_irqrestore(
                                &phba->sli4_hba.abts_scsi_buf_list_lock,
@@ -688,11 +689,12 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
                                         list);
                        if (status) {
                                /* Put this back on the abort scsi list */
-                               psb->status = IOSTAT_LOCAL_REJECT;
-                               psb->result = IOERR_ABORT_REQUESTED;
+                               psb->exch_busy = 1;
                                rc++;
-                       } else
+                       } else {
+                               psb->exch_busy = 0;
                                psb->status = IOSTAT_SUCCESS;
+                       }
                        /* Put it back into the SCSI buffer list */
                        lpfc_release_scsi_buf_s4(phba, psb);
                }
@@ -839,11 +841,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
                                                psb->cur_iocbq.sli4_xritag);
                        if (status) {
                                /* Put this back on the abort scsi list */
-                               psb->status = IOSTAT_LOCAL_REJECT;
-                               psb->result = IOERR_ABORT_REQUESTED;
+                               psb->exch_busy = 1;
                                rc++;
-                       } else
+                       } else {
+                               psb->exch_busy = 0;
                                psb->status = IOSTAT_SUCCESS;
+                       }
                        /* Put it back into the SCSI buffer list */
                        lpfc_release_scsi_buf_s4(phba, psb);
                        break;
@@ -857,11 +860,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
                                 list);
                        if (status) {
                                /* Put this back on the abort scsi list */
-                               psb->status = IOSTAT_LOCAL_REJECT;
-                               psb->result = IOERR_ABORT_REQUESTED;
+                               psb->exch_busy = 1;
                                rc++;
-                       } else
+                       } else {
+                               psb->exch_busy = 0;
                                psb->status = IOSTAT_SUCCESS;
+                       }
                        /* Put it back into the SCSI buffer list */
                        lpfc_release_scsi_buf_s4(phba, psb);
                }
@@ -951,8 +955,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
 {
        unsigned long iflag = 0;
 
-       if (psb->status == IOSTAT_LOCAL_REJECT
-               && psb->result == IOERR_ABORT_REQUESTED) {
+       if (psb->exch_busy) {
                spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock,
                                        iflag);
                psb->pCmd = NULL;
@@ -2221,6 +2224,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 
        lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
        lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
+       /* pick up SLI4 exhange busy status from HBA */
+       lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY;
+
        if (pnode && NLP_CHK_NODE_ACT(pnode))
                atomic_dec(&pnode->cmd_pending);
 
@@ -2990,6 +2996,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 
        /* ABTS WQE must go to the same WQ as the WQE to be aborted */
        abtsiocb->fcp_wqidx = iocb->fcp_wqidx;
+       abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX;
 
        if (lpfc_is_link_up(phba))
                icmd->ulpCommand = CMD_ABORT_XRI_CN;
index 65dfc8b..5932273 100644 (file)
@@ -118,6 +118,7 @@ struct lpfc_scsi_buf {
 
        uint32_t timeout;
 
+       uint16_t exch_busy;     /* SLI4 hba reported XB on complete WCQE */
        uint16_t status;        /* From IOCB Word 7- ulpStatus */
        uint32_t result;        /* From IOCB Word 4. */
 
index 589549b..dc7c5c1 100644 (file)
@@ -580,10 +580,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
        else
                sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag);
        if (sglq)  {
-               if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED
-                       && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT)
-                       && (iocbq->iocb.un.ulpWord[4]
-                               == IOERR_ABORT_REQUESTED))) {
+               if (iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) {
                        spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock,
                                        iflag);
                        list_add(&sglq->list,
@@ -764,10 +761,6 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case DSSCMD_IWRITE64_CX:
        case DSSCMD_IREAD64_CR:
        case DSSCMD_IREAD64_CX:
-       case DSSCMD_INVALIDATE_DEK:
-       case DSSCMD_SET_KEK:
-       case DSSCMD_GET_KEK_ID:
-       case DSSCMD_GEN_XFER:
                type = LPFC_SOL_IOCB;
                break;
        case CMD_ABORT_XRI_CN:
@@ -2228,9 +2221,15 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                         * All other are passed to the completion callback.
                         */
                        if (pring->ringno == LPFC_ELS_RING) {
-                               if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) {
+                               if ((phba->sli_rev < LPFC_SLI_REV4) &&
+                                   (cmdiocbp->iocb_flag &
+                                                       LPFC_DRIVER_ABORTED)) {
+                                       spin_lock_irqsave(&phba->hbalock,
+                                                         iflag);
                                        cmdiocbp->iocb_flag &=
                                                ~LPFC_DRIVER_ABORTED;
+                                       spin_unlock_irqrestore(&phba->hbalock,
+                                                              iflag);
                                        saveq->iocb.ulpStatus =
                                                IOSTAT_LOCAL_REJECT;
                                        saveq->iocb.un.ulpWord[4] =
@@ -2240,7 +2239,47 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                         * of DMAing payload, so don't free data
                                         * buffer till after a hbeat.
                                         */
+                                       spin_lock_irqsave(&phba->hbalock,
+                                                         iflag);
                                        saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
+                                       spin_unlock_irqrestore(&phba->hbalock,
+                                                              iflag);
+                               }
+                               if ((phba->sli_rev == LPFC_SLI_REV4) &&
+                                   (saveq->iocb_flag & LPFC_EXCHANGE_BUSY)) {
+                                       /* Set cmdiocb flag for the exchange
+                                        * busy so sgl (xri) will not be
+                                        * released until the abort xri is
+                                        * received from hba, clear the
+                                        * LPFC_DRIVER_ABORTED bit in case
+                                        * it was driver initiated abort.
+                                        */
+                                       spin_lock_irqsave(&phba->hbalock,
+                                                         iflag);
+                                       cmdiocbp->iocb_flag &=
+                                               ~LPFC_DRIVER_ABORTED;
+                                       cmdiocbp->iocb_flag |=
+                                               LPFC_EXCHANGE_BUSY;
+                                       spin_unlock_irqrestore(&phba->hbalock,
+                                                              iflag);
+                                       cmdiocbp->iocb.ulpStatus =
+                                               IOSTAT_LOCAL_REJECT;
+                                       cmdiocbp->iocb.un.ulpWord[4] =
+                                               IOERR_ABORT_REQUESTED;
+                                       /*
+                                        * For SLI4, irsiocb contains NO_XRI
+                                        * in sli_xritag, it shall not affect
+                                        * releasing sgl (xri) process.
+                                        */
+                                       saveq->iocb.ulpStatus =
+                                               IOSTAT_LOCAL_REJECT;
+                                       saveq->iocb.un.ulpWord[4] =
+                                               IOERR_SLI_ABORTED;
+                                       spin_lock_irqsave(&phba->hbalock,
+                                                         iflag);
+                                       saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
+                                       spin_unlock_irqrestore(&phba->hbalock,
+                                                              iflag);
                                }
                        }
                        (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -5987,12 +6026,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                else
                        bf_set(abort_cmd_ia, &wqe->abort_cmd, 0);
                bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG);
-               abort_tag = iocbq->iocb.un.acxri.abortIoTag;
                wqe->words[5] = 0;
                bf_set(lpfc_wqe_gen_ct, &wqe->generic,
                        ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
                abort_tag = iocbq->iocb.un.acxri.abortIoTag;
-               wqe->generic.abort_tag = abort_tag;
                /*
                 * The abort handler will send us CMD_ABORT_XRI_CN or
                 * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX
@@ -6121,15 +6158,15 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
        if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
                return IOCB_ERROR;
 
-       if (piocb->iocb_flag &  LPFC_IO_FCP) {
+       if ((piocb->iocb_flag & LPFC_IO_FCP) ||
+               (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) {
                /*
                 * For FCP command IOCB, get a new WQ index to distribute
                 * WQE across the WQsr. On the other hand, for abort IOCB,
                 * it carries the same WQ index to the original command
                 * IOCB.
                 */
-               if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
-                   (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN))
+               if (piocb->iocb_flag & LPFC_IO_FCP)
                        piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
                if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx],
                                     &wqe))
@@ -7004,7 +7041,14 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                    abort_iocb->iocb.ulpContext != abort_context ||
                    (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0)
                        spin_unlock_irq(&phba->hbalock);
-               else {
+               else if (phba->sli_rev < LPFC_SLI_REV4) {
+                       /*
+                        * leave the SLI4 aborted command on the txcmplq
+                        * list and the command complete WCQE's XB bit
+                        * will tell whether the SGL (XRI) can be released
+                        * immediately or to the aborted SGL list for the
+                        * following abort XRI from the HBA.
+                        */
                        list_del_init(&abort_iocb->list);
                        pring->txcmplq_cnt--;
                        spin_unlock_irq(&phba->hbalock);
@@ -7013,11 +7057,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                         * 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);
+
                        abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
-                       abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
+                       abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED;
                        (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
                }
        }
@@ -7106,7 +7152,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                return 0;
 
        /* This signals the response to set the correct status
-        * before calling the completion handler.
+        * before calling the completion handler
         */
        cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
 
@@ -7124,6 +7170,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        /* ABTS WQE must go to the same WQ as the WQE to be aborted */
        abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx;
+       if (cmdiocb->iocb_flag & LPFC_IO_FCP)
+               abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX;
 
        if (phba->link_state >= LPFC_LINK_UP)
                iabt->ulpCommand = CMD_ABORT_XRI_CN;
@@ -7330,6 +7378,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
 
                /* ABTS WQE must go to the same WQ as the WQE to be aborted */
                abtsiocb->fcp_wqidx = iocbq->fcp_wqidx;
+               if (iocbq->iocb_flag & LPFC_IO_FCP)
+                       abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX;
 
                if (lpfc_is_link_up(phba))
                        abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
@@ -8359,11 +8409,24 @@ void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba)
        }
 }
 
+/**
+ * lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn
+ * @phba: pointer to lpfc hba data structure
+ * @pIocbIn: pointer to the rspiocbq
+ * @pIocbOut: pointer to the cmdiocbq
+ * @wcqe: pointer to the complete wcqe
+ *
+ * This routine transfers the fields of a command iocbq to a response iocbq
+ * by copying all the IOCB fields from command iocbq and transferring the
+ * completion status information from the complete wcqe.
+ **/
 static void
-lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
+lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
+                             struct lpfc_iocbq *pIocbIn,
                              struct lpfc_iocbq *pIocbOut,
                              struct lpfc_wcqe_complete *wcqe)
 {
+       unsigned long iflags;
        size_t offset = offsetof(struct lpfc_iocbq, iocb);
 
        memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
@@ -8379,6 +8442,13 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn,
                        pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
        else
                pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
+
+       /* Pick up HBA exchange busy condition */
+       if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
+               spin_lock_irqsave(&phba->hbalock, iflags);
+               pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+       }
 }
 
 /**
@@ -8419,7 +8489,7 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
        }
 
        /* Fake the irspiocbq and copy necessary response information */
-       lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe);
+       lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe);
 
        return irspiocbq;
 }
@@ -8976,7 +9046,7 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba,
        }
 
        /* Fake the irspiocb and copy necessary response information */
-       lpfc_sli4_iocb_param_transfer(&irspiocbq, cmdiocbq, wcqe);
+       lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe);
 
        /* Pass the cmd_iocb and the rsp state to the upper layer */
        (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq);
index ba38de3..dfcf543 100644 (file)
@@ -53,17 +53,19 @@ struct lpfc_iocbq {
 
        IOCB_t iocb;            /* IOCB cmd */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
-       uint8_t iocb_flag;
+       uint16_t iocb_flag;
 #define LPFC_IO_LIBDFC         1       /* libdfc iocb */
 #define LPFC_IO_WAKE           2       /* High Priority Queue signal flag */
 #define LPFC_IO_FCP            4       /* FCP command -- iocbq in scsi_buf */
 #define LPFC_DRIVER_ABORTED    8       /* driver aborted this request */
 #define LPFC_IO_FABRIC         0x10    /* Iocb send using fabric scheduler */
 #define LPFC_DELAY_MEM_FREE    0x20    /* Defer free'ing of FC data */
-#define LPFC_FIP_ELS_ID_MASK   0xc0    /* ELS_ID range 0-3 */
-#define LPFC_FIP_ELS_ID_SHIFT  6
+#define LPFC_EXCHANGE_BUSY     0x40    /* SLI4 hba reported XB in response */
+#define LPFC_USE_FCPWQIDX      0x80    /* Submit to specified FCPWQ index */
+
+#define LPFC_FIP_ELS_ID_MASK   0xc000  /* ELS_ID range 0-3, non-shifted mask */
+#define LPFC_FIP_ELS_ID_SHIFT  14
 
-       uint8_t abort_count;
        uint8_t rsvd2;
        uint32_t drvrTimeout;   /* driver timeout in seconds */
        uint32_t fcp_wqidx;     /* index to FCP work queue */