scsi: lpfc: Fix link down processing to address NULL pointer dereference
authorJames Smart <jsmart2021@gmail.com>
Wed, 20 Oct 2021 21:14:15 +0000 (14:14 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Nov 2021 08:48:29 +0000 (09:48 +0100)
[ Upstream commit 1854f53ccd88ad4e7568ddfafafffe71f1ceb0a6 ]

If an FC link down transition while PLOGIs are outstanding to fabric well
known addresses, outstanding ABTS requests may result in a NULL pointer
dereference. Driver unload requests may hang with repeated "2878" log
messages.

The Link down processing results in ABTS requests for outstanding ELS
requests. The Abort WQEs are sent for the ELSs before the driver had set
the link state to down. Thus the driver is sending the Abort with the
expectation that an ABTS will be sent on the wire. The Abort request is
stalled waiting for the link to come up. In some conditions the driver may
auto-complete the ELSs thus if the link does come up, the Abort completions
may reference an invalid structure.

Fix by ensuring that Abort set the flag to avoid link traffic if issued due
to conditions where the link failed.

Link: https://lore.kernel.org/r/20211020211417.88754-7-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_sli.c

index 8e689f06afc922316a73da001b007cdbce5f578e..9c1f485952ef775b1d1cf1267cbd38a4bc950f41 100644 (file)
@@ -12404,17 +12404,17 @@ 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->hba_wqidx = cmdiocb->hba_wqidx;
-       if (cmdiocb->iocb_flag & LPFC_IO_FCP) {
-               abtsiocbp->iocb_flag |= LPFC_IO_FCP;
-               abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX;
-       }
+       if (cmdiocb->iocb_flag & LPFC_IO_FCP)
+               abtsiocbp->iocb_flag |= (LPFC_IO_FCP | 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;
-       else
+       if (phba->link_state < LPFC_LINK_UP ||
+           (phba->sli_rev == LPFC_SLI_REV4 &&
+            phba->sli4_hba.link_state.status == LPFC_FC_LA_TYPE_LINK_DOWN))
                iabt->ulpCommand = CMD_CLOSE_XRI_CN;
+       else
+               iabt->ulpCommand = CMD_ABORT_XRI_CN;
 
        if (cmpl)
                abtsiocbp->iocb_cmpl = cmpl;