OSDN Git Service

lpfc: fix locking issues with abort data paths
authorJames Smart <james.smart@emulex.com>
Wed, 3 Sep 2014 16:57:30 +0000 (12:57 -0400)
committerChristoph Hellwig <hch@lst.de>
Tue, 16 Sep 2014 16:10:11 +0000 (09:10 -0700)
Fix locking issues with abort data paths

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: Dick Kennedy <dick.kennedy@emulex.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h

index 6094545..0f6be85 100644 (file)
@@ -3466,7 +3466,7 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
         */
        if ((phba->cfg_fof) && ((struct lpfc_device_data *)
                scsi_cmnd->device->hostdata)->oas_enabled)
-               lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_OAS;
+               lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF);
        return 0;
 }
 
@@ -3606,6 +3606,14 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
         */
        iocb_cmd->un.fcpi.fcpi_parm = fcpdl;
 
+       /*
+        * If the OAS driver feature is enabled and the lun is enabled for
+        * OAS, set the oas iocb related flags.
+        */
+       if ((phba->cfg_fof) && ((struct lpfc_device_data *)
+               scsi_cmnd->device->hostdata)->oas_enabled)
+               lpfc_cmd->cur_iocbq.iocb_flag |= (LPFC_IO_OAS | LPFC_IO_FOF);
+
        return 0;
 err:
        if (lpfc_cmd->seg_cnt)
@@ -4876,6 +4884,8 @@ 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 (iocb->iocb_flag & LPFC_IO_FOF)
+               abtsiocb->iocb_flag |= LPFC_IO_FOF;
 
        if (lpfc_is_link_up(phba))
                icmd->ulpCommand = CMD_ABORT_XRI_CN;
index deb7f12..7185aac 100644 (file)
@@ -8753,6 +8753,37 @@ lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
        return 0;
 }
 
+int
+lpfc_sli_calc_ring(struct lpfc_hba *phba, uint32_t ring_number,
+                   struct lpfc_iocbq *piocb)
+{
+       uint32_t idx;
+
+       if (phba->sli_rev == LPFC_SLI_REV4) {
+               if (piocb->iocb_flag &  (LPFC_IO_FCP | LPFC_USE_FCPWQIDX)) {
+                       /*
+                        * fcp_wqidx should already be setup based on what
+                        * completion queue we want to use.
+                        */
+                       if (!(phba->cfg_fof) ||
+                           (!(piocb->iocb_flag & LPFC_IO_FOF))) {
+                               if (unlikely(!phba->sli4_hba.fcp_wq))
+                                       return LPFC_HBA_ERROR;
+                               idx = lpfc_sli4_scmd_to_wqidx_distr(phba);
+                               piocb->fcp_wqidx = idx;
+                               ring_number = MAX_SLI3_CONFIGURED_RINGS + idx;
+                       } else {
+                               if (unlikely(!phba->sli4_hba.oas_wq))
+                                       return LPFC_HBA_ERROR;
+                               idx = 0;
+                               piocb->fcp_wqidx = idx;
+                               ring_number =  LPFC_FCP_OAS_RING;
+                       }
+               }
+       }
+       return ring_number;
+}
+
 /**
  * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb
  * @phba: Pointer to HBA context object.
@@ -8778,61 +8809,42 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
        int rc, idx;
 
        if (phba->sli_rev == LPFC_SLI_REV4) {
-               if (piocb->iocb_flag &  LPFC_IO_FCP) {
-                       if (!phba->cfg_fof || (!(piocb->iocb_flag &
-                               LPFC_IO_OAS))) {
-                               if (unlikely(!phba->sli4_hba.fcp_wq))
-                                       return IOCB_ERROR;
-                               idx = lpfc_sli4_scmd_to_wqidx_distr(phba);
-                               piocb->fcp_wqidx = idx;
-                               ring_number = MAX_SLI3_CONFIGURED_RINGS + idx;
-                       } else {
-                               if (unlikely(!phba->sli4_hba.oas_wq))
-                                       return IOCB_ERROR;
-                               idx = 0;
-                               piocb->fcp_wqidx = 0;
-                               ring_number =  LPFC_FCP_OAS_RING;
-                       }
-                       pring = &phba->sli.ring[ring_number];
-                       spin_lock_irqsave(&pring->ring_lock, iflags);
-                       rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb,
-                               flag);
-                       spin_unlock_irqrestore(&pring->ring_lock, iflags);
+               ring_number = lpfc_sli_calc_ring(phba, ring_number, piocb);
+               if (unlikely(ring_number == LPFC_HBA_ERROR))
+                       return IOCB_ERROR;
+               idx = piocb->fcp_wqidx;
 
-                       if (lpfc_fcp_look_ahead) {
-                               fcp_eq_hdl = &phba->sli4_hba.fcp_eq_hdl[idx];
+               pring = &phba->sli.ring[ring_number];
+               spin_lock_irqsave(&pring->ring_lock, iflags);
+               rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag);
+               spin_unlock_irqrestore(&pring->ring_lock, iflags);
 
-                               if (atomic_dec_and_test(&fcp_eq_hdl->
-                                       fcp_eq_in_use)) {
+               if (lpfc_fcp_look_ahead && (piocb->iocb_flag &  LPFC_IO_FCP)) {
+                       fcp_eq_hdl = &phba->sli4_hba.fcp_eq_hdl[idx];
 
-                                       /* Get associated EQ with this index */
-                                       fpeq = phba->sli4_hba.hba_eq[idx];
+                       if (atomic_dec_and_test(&fcp_eq_hdl->
+                               fcp_eq_in_use)) {
 
-                                       /* Turn off interrupts from this EQ */
-                                       lpfc_sli4_eq_clr_intr(fpeq);
+                               /* Get associated EQ with this index */
+                               fpeq = phba->sli4_hba.hba_eq[idx];
 
-                                       /*
-                                        * Process all the events on FCP EQ
-                                        */
-                                       while ((eqe = lpfc_sli4_eq_get(fpeq))) {
-                                               lpfc_sli4_hba_handle_eqe(phba,
-                                                       eqe, idx);
-                                               fpeq->EQ_processed++;
-                                       }
+                               /* Turn off interrupts from this EQ */
+                               lpfc_sli4_eq_clr_intr(fpeq);
 
-                                       /* Always clear and re-arm the EQ */
-                                       lpfc_sli4_eq_release(fpeq,
-                                               LPFC_QUEUE_REARM);
+                               /*
+                                * Process all the events on FCP EQ
+                                */
+                               while ((eqe = lpfc_sli4_eq_get(fpeq))) {
+                                       lpfc_sli4_hba_handle_eqe(phba,
+                                               eqe, idx);
+                                       fpeq->EQ_processed++;
                                }
-                               atomic_inc(&fcp_eq_hdl->fcp_eq_in_use);
-                       }
-               } else {
-                       pring = &phba->sli.ring[ring_number];
-                       spin_lock_irqsave(&pring->ring_lock, iflags);
-                       rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb,
-                               flag);
-                       spin_unlock_irqrestore(&pring->ring_lock, iflags);
 
+                               /* Always clear and re-arm the EQ */
+                               lpfc_sli4_eq_release(fpeq,
+                                       LPFC_QUEUE_REARM);
+                       }
+                       atomic_inc(&fcp_eq_hdl->fcp_eq_in_use);
                }
        } else {
                /* For now, SLI2/3 will still use hbalock */
@@ -9715,6 +9727,7 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        struct lpfc_iocbq *abtsiocbp;
        IOCB_t *icmd = NULL;
        IOCB_t *iabt = NULL;
+       int ring_number;
        int retval;
        unsigned long iflags;
 
@@ -9755,6 +9768,8 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx;
        if (cmdiocb->iocb_flag & LPFC_IO_FCP)
                abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX;
+       if (cmdiocb->iocb_flag & LPFC_IO_FOF)
+               abtsiocbp->iocb_flag |= LPFC_IO_FOF;
 
        if (phba->link_state >= LPFC_LINK_UP)
                iabt->ulpCommand = CMD_ABORT_XRI_CN;
@@ -9771,6 +9786,11 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                         abtsiocbp->iotag);
 
        if (phba->sli_rev == LPFC_SLI_REV4) {
+               ring_number =
+                       lpfc_sli_calc_ring(phba, pring->ringno, abtsiocbp);
+               if (unlikely(ring_number == LPFC_HBA_ERROR))
+                       return 0;
+               pring = &phba->sli.ring[ring_number];
                /* Note: both hbalock and ring_lock need to be set here */
                spin_lock_irqsave(&pring->ring_lock, iflags);
                retval = __lpfc_sli_issue_iocb(phba, pring->ringno,
@@ -10068,6 +10088,8 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                abtsiocb->fcp_wqidx = iocbq->fcp_wqidx;
                if (iocbq->iocb_flag & LPFC_IO_FCP)
                        abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX;
+               if (iocbq->iocb_flag & LPFC_IO_FOF)
+                       abtsiocb->iocb_flag |= LPFC_IO_FOF;
 
                if (lpfc_is_link_up(phba))
                        abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
@@ -10167,6 +10189,8 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                abtsiocbq->fcp_wqidx = iocbq->fcp_wqidx;
                if (iocbq->iocb_flag & LPFC_IO_FCP)
                        abtsiocbq->iocb_flag |= LPFC_USE_FCPWQIDX;
+               if (iocbq->iocb_flag & LPFC_IO_FOF)
+                       abtsiocbq->iocb_flag |= LPFC_IO_FOF;
 
                if (lpfc_is_link_up(phba))
                        abtsiocbq->iocb.ulpCommand = CMD_ABORT_XRI_CN;
index edb4883..4a01452 100644 (file)
@@ -79,6 +79,7 @@ struct lpfc_iocbq {
 #define LPFC_FIP_ELS_ID_SHIFT  14
 
 #define LPFC_IO_OAS            0x10000 /* OAS FCP IO */
+#define LPFC_IO_FOF            0x20000 /* FOF FCP IO */
 
        uint32_t drvrTimeout;   /* driver timeout in seconds */
        uint32_t fcp_wqidx;     /* index to FCP work queue */