scsi: lpfc: Fix list corruption in lpfc_sli_get_iocbq
authorJames Smart <jsmart2021@gmail.com>
Sun, 22 Sep 2019 03:58:59 +0000 (20:58 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 1 Oct 2019 02:07:10 +0000 (22:07 -0400)
After study, it was determined there was a double free of a CT iocb during
execution of lpfc_offline_prep and lpfc_offline.  The prep routine issued
an abort for some CT iocbs, but the aborts did not complete fast enough for
a subsequent routine that waits for completion. Thus the driver proceeded
to lpfc_offline, which releases any pending iocbs. Unfortunately, the
completions for the aborts were then received which re-released the ct
iocbs.

Turns out the issue for why the aborts didn't complete fast enough was not
their time on the wire/in the adapter. It was the lpfc_work_done routine,
which requires the adapter state to be UP before it calls
lpfc_sli_handle_slow_ring_event() to process the completions. The issue is
the prep routine takes the link down as part of it's processing.

To fix, the following was performed:

 - Prevent the offline routine from releasing iocbs that have had aborts
   issued on them. Defer to the abort completions. Also means the driver
   fully waits for the completions.  Given this change, the recognition of
   "driver-generated" status which then releases the iocb is no longer
   valid. As such, the change made in the commit 296012285c90 is reverted.
   As recognition of "driver-generated" status is no longer valid, this
   patch reverts the changes made in
   commit 296012285c90 ("scsi: lpfc: Fix leak of ELS completions on adapter reset")

 - Modify lpfc_work_done to allow slow path completions so that the abort
   completions aren't ignored.

 - Updated the fdmi path to recognize a CT request that fails due to the
   port being unusable. This stops FDMI retries. FDMI will be restarted on
   next link up.

Link: https://lore.kernel.org/r/20190922035906.10977-14-jsmart2021@gmail.com
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_sli.c

index 25e86706e2072753111bb66b10f742cbd00f22e3..f883fac2d2b1dc19fcadf0a9e33fd62b5d38545b 100644 (file)
@@ -1868,6 +1868,12 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
                        switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
                        case IOERR_SLI_ABORTED:
+                       case IOERR_SLI_DOWN:
+                               /* Driver aborted this IO.  No retry as error
+                                * is likely Offline->Online or some adapter
+                                * error.  Recovery will try again.
+                                */
+                               break;
                        case IOERR_ABORT_IN_PROGRESS:
                        case IOERR_SEQUENCE_TIMEOUT:
                        case IOERR_ILLEGAL_FRAME:
index 55ab37572e928755ab01645de9c6ef378f8ed18a..bd8109b2a083bc9ff8aa218ea72c779caf0160cb 100644 (file)
@@ -8019,6 +8019,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
                if (piocb->vport != vport)
                        continue;
 
+               if (piocb->iocb_flag & LPFC_DRIVER_ABORTED)
+                       continue;
+
                /* On the ELS ring we can have ELS_REQUESTs or
                 * GEN_REQUESTs waiting for a response.
                 */
index f483b3aea22b6a1b1b9dc26323367103ed00a6f7..808ad666bb1bc3dd252a5c73a0a4449104acd84b 100644 (file)
@@ -700,7 +700,10 @@ lpfc_work_done(struct lpfc_hba *phba)
                        if (!(phba->hba_flag & HBA_SP_QUEUE_EVT))
                                set_bit(LPFC_DATA_READY, &phba->data_flags);
                } else {
-                       if (phba->link_state >= LPFC_LINK_UP ||
+                       /* Driver could have abort request completed in queue
+                        * when link goes down.  Allow for this transition.
+                        */
+                       if (phba->link_state >= LPFC_LINK_DOWN ||
                            phba->link_flag & LS_MDS_LOOPBACK) {
                                pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
                                lpfc_sli_handle_slow_ring_event(phba, pring,
index 412cd8c56d90a7aa53857292c9820eb15e613d72..ff261c0c738ade382a735b89538067218d8759e9 100644 (file)
@@ -11090,9 +11090,6 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                irsp->ulpStatus, irsp->un.ulpWord[4]);
 
                spin_unlock_irq(&phba->hbalock);
-               if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT &&
-                   irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)
-                       lpfc_sli_release_iocbq(phba, abort_iocb);
        }
 release_iocb:
        lpfc_sli_release_iocbq(phba, cmdiocb);