scsi: lpfc: SLI path split: Refactor fast and slow paths to native SLI4
authorJames Smart <jsmart2021@gmail.com>
Fri, 25 Feb 2022 02:22:53 +0000 (18:22 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Aug 2022 12:24:21 +0000 (14:24 +0200)
[ Upstream commit 1b64aa9eae28ac598a03ed3d62a63ac5e5b295fc ]

Convert the SLI4 fast and slow paths to use native SLI4 wqe constructs
instead of iocb SLI3-isms.

Includes the following:

 - Create simple get_xxx and set_xxx routines to wrapper access to common
   elements in both SLI3 and SLI4 commands - allowing calling routines to
   avoid sli-rev-specific structures to access the elements.

 - using the wqe in the job structure as the primary element

 - use defines from SLI-4, not SLI-3

 - Removal of iocb to wqe conversion from fast and slow path

 - Add below routines to handle fast path
lpfc_prep_embed_io - prepares the wqe for fast path
lpfc_wqe_bpl2sgl   - manages bpl to sgl conversion
lpfc_sli_wqe2iocb  - converts a WQE to IOCB for SLI-3 path

 - Add lpfc_sli3_iocb2wcqecmpl in completion path to convert an SLI-3
   iocb completion to wcqe completion

 - Refactor some of the code that works on both revs for clarity

Link: https://lore.kernel.org/r/20220225022308.16486-3-jsmart2021@gmail.com
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h

index b2508a0..266d980 100644 (file)
@@ -1803,3 +1803,39 @@ static inline int lpfc_is_vmid_enabled(struct lpfc_hba *phba)
 {
        return phba->cfg_vmid_app_header || phba->cfg_vmid_priority_tagging;
 }
+
+static inline
+u8 get_job_ulpstatus(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               return bf_get(lpfc_wcqe_c_status, &iocbq->wcqe_cmpl);
+       else
+               return iocbq->iocb.ulpStatus;
+}
+
+static inline
+u32 get_job_word4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               return iocbq->wcqe_cmpl.parameter;
+       else
+               return iocbq->iocb.un.ulpWord[4];
+}
+
+static inline
+u8 get_job_cmnd(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               return bf_get(wqe_cmnd, &iocbq->wqe.generic.wqe_com);
+       else
+               return iocbq->iocb.ulpCommand;
+}
+
+static inline
+u16 get_job_ulpcontext(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               return bf_get(wqe_ctxt_tag, &iocbq->wqe.generic.wqe_com);
+       else
+               return iocbq->iocb.ulpContext;
+}
index ed27a0a..f7bf589 100644 (file)
@@ -129,6 +129,7 @@ void lpfc_disc_list_loopmap(struct lpfc_vport *);
 void lpfc_disc_start(struct lpfc_vport *);
 void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
 void lpfc_cleanup(struct lpfc_vport *);
+void lpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd);
 void lpfc_disc_timeout(struct timer_list *);
 
 int lpfc_unregister_fcf_prep(struct lpfc_hba *);
index 824fc8c..215fbf1 100644 (file)
        ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \
                 ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT))))
 
+#define get_wqe_reqtag(x)      (((x)->wqe.words[9] >>  0) & 0xFFFF)
+
+#define get_job_ulpword(x, y)  ((x)->iocb.un.ulpWord[y])
+
+#define set_job_ulpstatus(x, y)        bf_set(lpfc_wcqe_c_status, &(x)->wcqe_cmpl, y)
+#define set_job_ulpword4(x, y) ((&(x)->wcqe_cmpl)->parameter = y)
+
 struct dma_address {
        uint32_t addr_lo;
        uint32_t addr_hi;
index 413824f..464a251 100644 (file)
@@ -70,8 +70,9 @@ static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *,
                                  uint32_t);
 static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *,
                              uint8_t *, uint32_t *);
-static struct lpfc_iocbq *lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *,
-                                                        struct lpfc_iocbq *);
+static struct lpfc_iocbq *
+lpfc_sli4_els_preprocess_rspiocbq(struct lpfc_hba *phba,
+                                 struct lpfc_iocbq *rspiocbq);
 static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *,
                                      struct hbq_dmabuf *);
 static void lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport,
@@ -89,6 +90,9 @@ static struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q);
 static void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba,
                                    struct lpfc_queue *cq,
                                    struct lpfc_cqe *cqe);
+static uint16_t lpfc_wqe_bpl2sgl(struct lpfc_hba *phba,
+                                struct lpfc_iocbq *pwqeq,
+                                struct lpfc_sglq *sglq);
 
 union lpfc_wqe128 lpfc_iread_cmd_template;
 union lpfc_wqe128 lpfc_iwrite_cmd_template;
@@ -3550,17 +3554,12 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
                      struct lpfc_iocbq *prspiocb)
 {
        struct lpfc_iocbq *cmd_iocb = NULL;
-       uint16_t iotag;
-       spinlock_t *temp_lock = NULL;
-       unsigned long iflag = 0;
+       u16 iotag;
 
        if (phba->sli_rev == LPFC_SLI_REV4)
-               temp_lock = &pring->ring_lock;
+               iotag = get_wqe_reqtag(prspiocb);
        else
-               temp_lock = &phba->hbalock;
-
-       spin_lock_irqsave(temp_lock, iflag);
-       iotag = prspiocb->iocb.ulpIoTag;
+               iotag = prspiocb->iocb.ulpIoTag;
 
        if (iotag != 0 && iotag <= phba->sli.last_iotag) {
                cmd_iocb = phba->sli.iocbq_lookup[iotag];
@@ -3569,17 +3568,14 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
                        list_del_init(&cmd_iocb->list);
                        cmd_iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
                        pring->txcmplq_cnt--;
-                       spin_unlock_irqrestore(temp_lock, iflag);
                        return cmd_iocb;
                }
        }
 
-       spin_unlock_irqrestore(temp_lock, iflag);
        lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
                        "0317 iotag x%x is out of "
-                       "range: max iotag x%x wd0 x%x\n",
-                       iotag, phba->sli.last_iotag,
-                       *(((uint32_t *) &prspiocb->iocb) + 7));
+                       "range: max iotag x%x\n",
+                       iotag, phba->sli.last_iotag);
        return NULL;
 }
 
@@ -3600,15 +3596,7 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
                             struct lpfc_sli_ring *pring, uint16_t iotag)
 {
        struct lpfc_iocbq *cmd_iocb = NULL;
-       spinlock_t *temp_lock = NULL;
-       unsigned long iflag = 0;
 
-       if (phba->sli_rev == LPFC_SLI_REV4)
-               temp_lock = &pring->ring_lock;
-       else
-               temp_lock = &phba->hbalock;
-
-       spin_lock_irqsave(temp_lock, iflag);
        if (iotag != 0 && iotag <= phba->sli.last_iotag) {
                cmd_iocb = phba->sli.iocbq_lookup[iotag];
                if (cmd_iocb->cmd_flag & LPFC_IO_ON_TXCMPLQ) {
@@ -3616,12 +3604,10 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
                        list_del_init(&cmd_iocb->list);
                        cmd_iocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
                        pring->txcmplq_cnt--;
-                       spin_unlock_irqrestore(temp_lock, iflag);
                        return cmd_iocb;
                }
        }
 
-       spin_unlock_irqrestore(temp_lock, iflag);
        lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
                        "0372 iotag x%x lookup error: max iotag (x%x) "
                        "cmd_flag x%x\n",
@@ -3654,18 +3640,29 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        struct lpfc_iocbq *cmdiocbp;
        int rc = 1;
        unsigned long iflag;
+       u32 ulp_command, ulp_status, ulp_word4, ulp_context, iotag;
 
        cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq);
+
+       ulp_command = get_job_cmnd(phba, saveq);
+       ulp_status = get_job_ulpstatus(phba, saveq);
+       ulp_word4 = get_job_word4(phba, saveq);
+       ulp_context = get_job_ulpcontext(phba, saveq);
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               iotag = get_wqe_reqtag(saveq);
+       else
+               iotag = saveq->iocb.ulpIoTag;
+
        if (cmdiocbp) {
+               ulp_command = get_job_cmnd(phba, cmdiocbp);
                if (cmdiocbp->cmd_cmpl) {
                        /*
                         * If an ELS command failed send an event to mgmt
                         * application.
                         */
-                       if (saveq->iocb.ulpStatus &&
+                       if (ulp_status &&
                             (pring->ringno == LPFC_ELS_RING) &&
-                            (cmdiocbp->iocb.ulpCommand ==
-                               CMD_ELS_REQUEST64_CR))
+                            (ulp_command == CMD_ELS_REQUEST64_CR))
                                lpfc_send_els_failure_event(phba,
                                        cmdiocbp, saveq);
 
@@ -3727,20 +3724,20 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                                        ~LPFC_DRIVER_ABORTED;
                                                spin_unlock_irqrestore(
                                                        &phba->hbalock, iflag);
-                                               cmdiocbp->iocb.ulpStatus =
-                                                       IOSTAT_LOCAL_REJECT;
-                                               cmdiocbp->iocb.un.ulpWord[4] =
-                                                       IOERR_ABORT_REQUESTED;
+                                               set_job_ulpstatus(cmdiocbp,
+                                                                 IOSTAT_LOCAL_REJECT);
+                                               set_job_ulpword4(cmdiocbp,
+                                                                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;
+                                               set_job_ulpstatus(saveq,
+                                                                 IOSTAT_LOCAL_REJECT);
+                                               set_job_ulpword4(saveq,
+                                                                IOERR_SLI_ABORTED);
                                                spin_lock_irqsave(
                                                        &phba->hbalock, iflag);
                                                saveq->cmd_flag |=
@@ -3768,12 +3765,8 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                         "0322 Ring %d handler: "
                                         "unexpected completion IoTag x%x "
                                         "Data: x%x x%x x%x x%x\n",
-                                        pring->ringno,
-                                        saveq->iocb.ulpIoTag,
-                                        saveq->iocb.ulpStatus,
-                                        saveq->iocb.un.ulpWord[4],
-                                        saveq->iocb.ulpCommand,
-                                        saveq->iocb.ulpContext);
+                                        pring->ringno, iotag, ulp_status,
+                                        ulp_word4, ulp_command, ulp_context);
                }
        }
 
@@ -4088,155 +4081,159 @@ lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        struct lpfc_iocbq *rspiocbp)
 {
        struct lpfc_iocbq *saveq;
-       struct lpfc_iocbq *cmdiocbp;
+       struct lpfc_iocbq *cmdiocb;
        struct lpfc_iocbq *next_iocb;
-       IOCB_t *irsp = NULL;
+       IOCB_t *irsp;
        uint32_t free_saveq;
-       uint8_t iocb_cmd_type;
+       ucmd_type;
        lpfc_iocb_type type;
        unsigned long iflag;
+       u32 ulp_status = get_job_ulpstatus(phba, rspiocbp);
+       u32 ulp_word4 = get_job_word4(phba, rspiocbp);
+       u32 ulp_command = get_job_cmnd(phba, rspiocbp);
        int rc;
 
        spin_lock_irqsave(&phba->hbalock, iflag);
        /* First add the response iocb to the countinueq list */
-       list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
+       list_add_tail(&rspiocbp->list, &pring->iocb_continueq);
        pring->iocb_continueq_cnt++;
 
-       /* Now, determine whether the list is completed for processing */
-       irsp = &rspiocbp->iocb;
-       if (irsp->ulpLe) {
-               /*
-                * By default, the driver expects to free all resources
-                * associated with this iocb completion.
-                */
-               free_saveq = 1;
-               saveq = list_get_first(&pring->iocb_continueq,
-                                      struct lpfc_iocbq, list);
-               irsp = &(saveq->iocb);
-               list_del_init(&pring->iocb_continueq);
-               pring->iocb_continueq_cnt = 0;
+       /*
+        * By default, the driver expects to free all resources
+        * associated with this iocb completion.
+        */
+       free_saveq = 1;
+       saveq = list_get_first(&pring->iocb_continueq,
+                              struct lpfc_iocbq, list);
+       list_del_init(&pring->iocb_continueq);
+       pring->iocb_continueq_cnt = 0;
 
-               pring->stats.iocb_rsp++;
+       pring->stats.iocb_rsp++;
 
-               /*
-                * If resource errors reported from HBA, reduce
-                * queuedepths of the SCSI device.
-                */
-               if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-                   ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) ==
-                    IOERR_NO_RESOURCES)) {
-                       spin_unlock_irqrestore(&phba->hbalock, iflag);
-                       phba->lpfc_rampdown_queue_depth(phba);
-                       spin_lock_irqsave(&phba->hbalock, iflag);
-               }
+       /*
+        * If resource errors reported from HBA, reduce
+        * queuedepths of the SCSI device.
+        */
+       if (ulp_status == IOSTAT_LOCAL_REJECT &&
+           ((ulp_word4 & IOERR_PARAM_MASK) ==
+            IOERR_NO_RESOURCES)) {
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               phba->lpfc_rampdown_queue_depth(phba);
+               spin_lock_irqsave(&phba->hbalock, iflag);
+       }
 
-               if (irsp->ulpStatus) {
-                       /* Rsp ring <ringno> error: IOCB */
+       if (ulp_status) {
+               /* Rsp ring <ringno> error: IOCB */
+               if (phba->sli_rev < LPFC_SLI_REV4) {
+                       irsp = &rspiocbp->iocb;
                        lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-                                       "0328 Rsp Ring %d error: "
+                                       "0328 Rsp Ring %d error: ulp_status x%x "
+                                       "IOCB Data: "
+                                       "x%08x x%08x x%08x x%08x "
+                                       "x%08x x%08x x%08x x%08x "
+                                       "x%08x x%08x x%08x x%08x "
+                                       "x%08x x%08x x%08x x%08x\n",
+                                       pring->ringno, ulp_status,
+                                       get_job_ulpword(rspiocbp, 0),
+                                       get_job_ulpword(rspiocbp, 1),
+                                       get_job_ulpword(rspiocbp, 2),
+                                       get_job_ulpword(rspiocbp, 3),
+                                       get_job_ulpword(rspiocbp, 4),
+                                       get_job_ulpword(rspiocbp, 5),
+                                       *(((uint32_t *)irsp) + 6),
+                                       *(((uint32_t *)irsp) + 7),
+                                       *(((uint32_t *)irsp) + 8),
+                                       *(((uint32_t *)irsp) + 9),
+                                       *(((uint32_t *)irsp) + 10),
+                                       *(((uint32_t *)irsp) + 11),
+                                       *(((uint32_t *)irsp) + 12),
+                                       *(((uint32_t *)irsp) + 13),
+                                       *(((uint32_t *)irsp) + 14),
+                                       *(((uint32_t *)irsp) + 15));
+               } else {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+                                       "0321 Rsp Ring %d error: "
                                        "IOCB Data: "
-                                       "x%x x%x x%x x%x "
-                                       "x%x x%x x%x x%x "
-                                       "x%x x%x x%x x%x "
                                        "x%x x%x x%x x%x\n",
                                        pring->ringno,
-                                       irsp->un.ulpWord[0],
-                                       irsp->un.ulpWord[1],
-                                       irsp->un.ulpWord[2],
-                                       irsp->un.ulpWord[3],
-                                       irsp->un.ulpWord[4],
-                                       irsp->un.ulpWord[5],
-                                       *(((uint32_t *) irsp) + 6),
-                                       *(((uint32_t *) irsp) + 7),
-                                       *(((uint32_t *) irsp) + 8),
-                                       *(((uint32_t *) irsp) + 9),
-                                       *(((uint32_t *) irsp) + 10),
-                                       *(((uint32_t *) irsp) + 11),
-                                       *(((uint32_t *) irsp) + 12),
-                                       *(((uint32_t *) irsp) + 13),
-                                       *(((uint32_t *) irsp) + 14),
-                                       *(((uint32_t *) irsp) + 15));
+                                       rspiocbp->wcqe_cmpl.word0,
+                                       rspiocbp->wcqe_cmpl.total_data_placed,
+                                       rspiocbp->wcqe_cmpl.parameter,
+                                       rspiocbp->wcqe_cmpl.word3);
                }
+       }
 
-               /*
-                * Fetch the IOCB command type and call the correct completion
-                * routine. Solicited and Unsolicited IOCBs on the ELS ring
-                * get freed back to the lpfc_iocb_list by the discovery
-                * kernel thread.
-                */
-               iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
-               type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
-               switch (type) {
-               case LPFC_SOL_IOCB:
-                       spin_unlock_irqrestore(&phba->hbalock, iflag);
-                       rc = lpfc_sli_process_sol_iocb(phba, pring, saveq);
-                       spin_lock_irqsave(&phba->hbalock, iflag);
-                       break;
 
-               case LPFC_UNSOL_IOCB:
-                       spin_unlock_irqrestore(&phba->hbalock, iflag);
-                       rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq);
-                       spin_lock_irqsave(&phba->hbalock, iflag);
-                       if (!rc)
-                               free_saveq = 0;
-                       break;
-
-               case LPFC_ABORT_IOCB:
-                       cmdiocbp = NULL;
-                       if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) {
+       /*
+        * Fetch the iocb command type and call the correct completion
+        * routine. Solicited and Unsolicited IOCBs on the ELS ring
+        * get freed back to the lpfc_iocb_list by the discovery
+        * kernel thread.
+        */
+       cmd_type = ulp_command & CMD_IOCB_MASK;
+       type = lpfc_sli_iocb_cmd_type(cmd_type);
+       switch (type) {
+       case LPFC_SOL_IOCB:
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               rc = lpfc_sli_process_sol_iocb(phba, pring, saveq);
+               spin_lock_irqsave(&phba->hbalock, iflag);
+               break;
+       case LPFC_UNSOL_IOCB:
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq);
+               spin_lock_irqsave(&phba->hbalock, iflag);
+               if (!rc)
+                       free_saveq = 0;
+               break;
+       case LPFC_ABORT_IOCB:
+               cmdiocb = NULL;
+               if (ulp_command != CMD_XRI_ABORTED_CX)
+                       cmdiocb = lpfc_sli_iocbq_lookup(phba, pring,
+                                                       saveq);
+               if (cmdiocb) {
+                       /* Call the specified completion routine */
+                       if (cmdiocb->cmd_cmpl) {
                                spin_unlock_irqrestore(&phba->hbalock, iflag);
-                               cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring,
-                                                                saveq);
+                               cmdiocb->cmd_cmpl(phba, cmdiocb, saveq);
                                spin_lock_irqsave(&phba->hbalock, iflag);
-                       }
-                       if (cmdiocbp) {
-                               /* Call the specified completion routine */
-                               if (cmdiocbp->cmd_cmpl) {
-                                       spin_unlock_irqrestore(&phba->hbalock,
-                                                              iflag);
-                                       (cmdiocbp->cmd_cmpl)(phba, cmdiocbp,
-                                                             saveq);
-                                       spin_lock_irqsave(&phba->hbalock,
-                                                         iflag);
-                               } else
-                                       __lpfc_sli_release_iocbq(phba,
-                                                                cmdiocbp);
-                       }
-                       break;
-
-               case LPFC_UNKNOWN_IOCB:
-                       if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
-                               char adaptermsg[LPFC_MAX_ADPTMSG];
-                               memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
-                               memcpy(&adaptermsg[0], (uint8_t *)irsp,
-                                      MAX_MSG_DATA);
-                               dev_warn(&((phba->pcidev)->dev),
-                                        "lpfc%d: %s\n",
-                                        phba->brd_no, adaptermsg);
                        } else {
-                               /* Unknown IOCB command */
-                               lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
-                                               "0335 Unknown IOCB "
-                                               "command Data: x%x "
-                                               "x%x x%x x%x\n",
-                                               irsp->ulpCommand,
-                                               irsp->ulpStatus,
-                                               irsp->ulpIoTag,
-                                               irsp->ulpContext);
+                               __lpfc_sli_release_iocbq(phba, cmdiocb);
                        }
-                       break;
                }
+               break;
+       case LPFC_UNKNOWN_IOCB:
+               if (ulp_command == CMD_ADAPTER_MSG) {
+                       char adaptermsg[LPFC_MAX_ADPTMSG];
+
+                       memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
+                       memcpy(&adaptermsg[0], (uint8_t *)&rspiocbp->wqe,
+                              MAX_MSG_DATA);
+                       dev_warn(&((phba->pcidev)->dev),
+                                "lpfc%d: %s\n",
+                                phba->brd_no, adaptermsg);
+               } else {
+                       /* Unknown command */
+                       lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
+                                       "0335 Unknown IOCB "
+                                       "command Data: x%x "
+                                       "x%x x%x x%x\n",
+                                       ulp_command,
+                                       ulp_status,
+                                       get_wqe_reqtag(rspiocbp),
+                                       get_job_ulpcontext(phba, rspiocbp));
+               }
+               break;
+       }
 
-               if (free_saveq) {
-                       list_for_each_entry_safe(rspiocbp, next_iocb,
-                                                &saveq->list, list) {
-                               list_del_init(&rspiocbp->list);
-                               __lpfc_sli_release_iocbq(phba, rspiocbp);
-                       }
-                       __lpfc_sli_release_iocbq(phba, saveq);
+       if (free_saveq) {
+               list_for_each_entry_safe(rspiocbp, next_iocb,
+                                        &saveq->list, list) {
+                       list_del_init(&rspiocbp->list);
+                       __lpfc_sli_release_iocbq(phba, rspiocbp);
                }
-               rspiocbp = NULL;
+               __lpfc_sli_release_iocbq(phba, saveq);
        }
+       rspiocbp = NULL;
        spin_unlock_irqrestore(&phba->hbalock, iflag);
        return rspiocbp;
 }
@@ -4429,8 +4426,8 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
                        irspiocbq = container_of(cq_event, struct lpfc_iocbq,
                                                 cq_event);
                        /* Translate ELS WCQE to response IOCBQ */
-                       irspiocbq = lpfc_sli4_els_wcqe_to_rspiocbq(phba,
-                                                                  irspiocbq);
+                       irspiocbq = lpfc_sli4_els_preprocess_rspiocbq(phba,
+                                                                     irspiocbq);
                        if (irspiocbq)
                                lpfc_sli_sp_handle_rspiocb(phba, pring,
                                                           irspiocbq);
@@ -10974,7 +10971,17 @@ __lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number,
        int rc;
        struct lpfc_io_buf *lpfc_cmd =
                (struct lpfc_io_buf *)piocb->context1;
-       union lpfc_wqe128 *wqe = &piocb->wqe;
+
+       lpfc_prep_embed_io(phba, lpfc_cmd);
+       rc = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb);
+       return rc;
+}
+
+void
+lpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
+{
+       struct lpfc_iocbq *piocb = &lpfc_cmd->cur_iocbq;
+       union lpfc_wqe128 *wqe = &lpfc_cmd->cur_iocbq.wqe;
        struct sli4_sge *sgl;
 
        /* 128 byte wqe support here */
@@ -11023,8 +11030,6 @@ __lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number,
                        wqe->words[31] = piocb->vmid_tag.app_id;
                }
        }
-       rc = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb);
-       return rc;
 }
 
 /**
@@ -11046,9 +11051,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
                         struct lpfc_iocbq *piocb, uint32_t flag)
 {
        struct lpfc_sglq *sglq;
-       union lpfc_wqe128 wqe;
+       union lpfc_wqe128 *wqe;
        struct lpfc_queue *wq;
        struct lpfc_sli_ring *pring;
+       u32 ulp_command = get_job_cmnd(phba, piocb);
 
        /* Get the WQ */
        if ((piocb->cmd_flag & LPFC_IO_FCP) ||
@@ -11066,10 +11072,9 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
         */
 
        lockdep_assert_held(&pring->ring_lock);
-
+       wqe = &piocb->wqe;
        if (piocb->sli4_xritag == NO_XRI) {
-               if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
-                   piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
+               if (ulp_command == CMD_ABORT_XRI_WQE)
                        sglq = NULL;
                else {
                        if (!list_empty(&pring->txq)) {
@@ -11110,14 +11115,24 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
        if (sglq) {
                piocb->sli4_lxritag = sglq->sli4_lxritag;
                piocb->sli4_xritag = sglq->sli4_xritag;
-               if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq))
+
+               /* ABTS sent by initiator to CT exchange, the
+                * RX_ID field will be filled with the newly
+                * allocated responder XRI.
+                */
+               if (ulp_command == CMD_XMIT_BLS_RSP64_CX &&
+                   piocb->abort_bls == LPFC_ABTS_UNSOL_INT)
+                       bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp,
+                              piocb->sli4_xritag);
+
+               bf_set(wqe_xri_tag, &wqe->generic.wqe_com,
+                      piocb->sli4_xritag);
+
+               if (lpfc_wqe_bpl2sgl(phba, piocb, sglq) == NO_XRI)
                        return IOCB_ERROR;
        }
 
-       if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe))
-               return IOCB_ERROR;
-
-       if (lpfc_sli4_wq_put(wq, &wqe))
+       if (lpfc_sli4_wq_put(wq, wqe))
                return IOCB_ERROR;
        lpfc_sli_ringtxcmpl_put(phba, pring, piocb);
 
@@ -14115,123 +14130,7 @@ 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_hba *phba,
-                             struct lpfc_iocbq *pIocbIn,
-                             struct lpfc_iocbq *pIocbOut,
-                             struct lpfc_wcqe_complete *wcqe)
-{
-       int numBdes, i;
-       unsigned long iflags;
-       uint32_t status, max_response;
-       struct lpfc_dmabuf *dmabuf;
-       struct ulp_bde64 *bpl, bde;
-       size_t offset = offsetof(struct lpfc_iocbq, iocb);
-
-       memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
-              sizeof(struct lpfc_iocbq) - offset);
-       /* Map WCQE parameters into irspiocb parameters */
-       status = bf_get(lpfc_wcqe_c_status, wcqe);
-       pIocbIn->iocb.ulpStatus = (status & LPFC_IOCB_STATUS_MASK);
-       if (pIocbOut->cmd_flag & LPFC_IO_FCP)
-               if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR)
-                       pIocbIn->iocb.un.fcpi.fcpi_parm =
-                                       pIocbOut->iocb.un.fcpi.fcpi_parm -
-                                       wcqe->total_data_placed;
-               else
-                       pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
-       else {
-               pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter;
-               switch (pIocbOut->iocb.ulpCommand) {
-               case CMD_ELS_REQUEST64_CR:
-                       dmabuf = (struct lpfc_dmabuf *)pIocbOut->context3;
-                       bpl  = (struct ulp_bde64 *)dmabuf->virt;
-                       bde.tus.w = le32_to_cpu(bpl[1].tus.w);
-                       max_response = bde.tus.f.bdeSize;
-                       break;
-               case CMD_GEN_REQUEST64_CR:
-                       max_response = 0;
-                       if (!pIocbOut->context3)
-                               break;
-                       numBdes = pIocbOut->iocb.un.genreq64.bdl.bdeSize/
-                                       sizeof(struct ulp_bde64);
-                       dmabuf = (struct lpfc_dmabuf *)pIocbOut->context3;
-                       bpl = (struct ulp_bde64 *)dmabuf->virt;
-                       for (i = 0; i < numBdes; i++) {
-                               bde.tus.w = le32_to_cpu(bpl[i].tus.w);
-                               if (bde.tus.f.bdeFlags != BUFF_TYPE_BDE_64)
-                                       max_response += bde.tus.f.bdeSize;
-                       }
-                       break;
-               default:
-                       max_response = wcqe->total_data_placed;
-                       break;
-               }
-               if (max_response < wcqe->total_data_placed)
-                       pIocbIn->iocb.un.genreq64.bdl.bdeSize = max_response;
-               else
-                       pIocbIn->iocb.un.genreq64.bdl.bdeSize =
-                               wcqe->total_data_placed;
-       }
-
-       /* Convert BG errors for completion status */
-       if (status == CQE_STATUS_DI_ERROR) {
-               pIocbIn->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
-
-               if (bf_get(lpfc_wcqe_c_bg_edir, wcqe))
-                       pIocbIn->iocb.un.ulpWord[4] = IOERR_RX_DMA_FAILED;
-               else
-                       pIocbIn->iocb.un.ulpWord[4] = IOERR_TX_DMA_FAILED;
-
-               pIocbIn->iocb.unsli3.sli3_bg.bgstat = 0;
-               if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */
-                       pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
-                               BGS_GUARD_ERR_MASK;
-               if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* App Tag Check failed */
-                       pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
-                               BGS_APPTAG_ERR_MASK;
-               if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* Ref Tag Check failed */
-                       pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
-                               BGS_REFTAG_ERR_MASK;
-
-               /* Check to see if there was any good data before the error */
-               if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) {
-                       pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
-                               BGS_HI_WATER_MARK_PRESENT_MASK;
-                       pIocbIn->iocb.unsli3.sli3_bg.bghm =
-                               wcqe->total_data_placed;
-               }
-
-               /*
-               * Set ALL the error bits to indicate we don't know what
-               * type of error it is.
-               */
-               if (!pIocbIn->iocb.unsli3.sli3_bg.bgstat)
-                       pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
-                               (BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK |
-                               BGS_GUARD_ERR_MASK);
-       }
-
-       /* Pick up HBA exchange busy condition */
-       if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
-               spin_lock_irqsave(&phba->hbalock, iflags);
-               pIocbIn->cmd_flag |= LPFC_EXCHANGE_BUSY;
-               spin_unlock_irqrestore(&phba->hbalock, iflags);
-       }
-}
-
-/**
- * lpfc_sli4_els_wcqe_to_rspiocbq - Get response iocbq from els wcqe
+ * lpfc_sli4_els_preprocess_rspiocbq - Get response iocbq from els wcqe
  * @phba: Pointer to HBA context object.
  * @irspiocbq: Pointer to work-queue completion queue entry.
  *
@@ -14242,8 +14141,8 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
  * Return: Pointer to the receive IOCBQ, NULL otherwise.
  **/
 static struct lpfc_iocbq *
-lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
-                              struct lpfc_iocbq *irspiocbq)
+lpfc_sli4_els_preprocess_rspiocbq(struct lpfc_hba *phba,
+                                 struct lpfc_iocbq *irspiocbq)
 {
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *cmdiocbq;
@@ -14255,11 +14154,13 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
                return NULL;
 
        wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl;
+       spin_lock_irqsave(&pring->ring_lock, iflags);
        pring->stats.iocb_event++;
        /* Look up the ELS command IOCB and create pseudo response IOCB */
        cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
                                bf_get(lpfc_wcqe_c_request_tag, wcqe));
        if (unlikely(!cmdiocbq)) {
+               spin_unlock_irqrestore(&pring->ring_lock, iflags);
                lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
                                "0386 ELS complete with no corresponding "
                                "cmdiocb: 0x%x 0x%x 0x%x 0x%x\n",
@@ -14269,13 +14170,18 @@ lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba,
                return NULL;
        }
 
-       spin_lock_irqsave(&pring->ring_lock, iflags);
+       memcpy(&irspiocbq->wqe, &cmdiocbq->wqe, sizeof(union lpfc_wqe128));
+       memcpy(&irspiocbq->wcqe_cmpl, wcqe, sizeof(*wcqe));
+
        /* Put the iocb back on the txcmplq */
        lpfc_sli_ringtxcmpl_put(phba, pring, cmdiocbq);
        spin_unlock_irqrestore(&pring->ring_lock, iflags);
 
-       /* Fake the irspiocbq and copy necessary response information */
-       lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe);
+       if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
+               spin_lock_irqsave(&phba->hbalock, iflags);
+               cmdiocbq->cmd_flag |= LPFC_EXCHANGE_BUSY;
+               spin_unlock_irqrestore(&phba->hbalock, iflags);
+       }
 
        return irspiocbq;
 }
@@ -15101,9 +15007,9 @@ lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
        /* Look up the FCP command IOCB and create pseudo response IOCB */
        spin_lock_irqsave(&pring->ring_lock, iflags);
        pring->stats.iocb_event++;
-       spin_unlock_irqrestore(&pring->ring_lock, iflags);
        cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring,
                                bf_get(lpfc_wcqe_c_request_tag, wcqe));
+       spin_unlock_irqrestore(&pring->ring_lock, iflags);
        if (unlikely(!cmdiocbq)) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
                                "0374 FCP complete with no corresponding "
@@ -18964,13 +18870,16 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport,
        ctiocb->sli4_lxritag = NO_XRI;
        ctiocb->sli4_xritag = NO_XRI;
 
-       if (fctl & FC_FC_EX_CTX)
+       if (fctl & FC_FC_EX_CTX) {
                /* Exchange responder sent the abort so we
                 * own the oxid.
                 */
+               ctiocb->abort_bls = LPFC_ABTS_UNSOL_RSP;
                xri = oxid;
-       else
+       } else {
+               ctiocb->abort_bls = LPFC_ABTS_UNSOL_INT;
                xri = rxid;
+       }
        lxri = lpfc_sli4_xri_inrange(phba, xri);
        if (lxri != NO_XRI)
                lpfc_set_rrq_active(phba, ndlp, lxri,
index 968c831..06682ad 100644 (file)
@@ -76,6 +76,8 @@ struct lpfc_iocbq {
        struct lpfc_wcqe_complete wcqe_cmpl;    /* WQE cmpl */
 
        uint8_t num_bdes;
+       uint8_t abort_bls;      /* ABTS by initiator or responder */
+
        uint8_t priority;       /* OAS priority */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
        u32 cmd_flag;