scsi: lpfc: Inhibit aborts if external loopback plug is inserted
authorJames Smart <jsmart2021@gmail.com>
Fri, 6 May 2022 03:55:11 +0000 (20:55 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 11 May 2022 02:12:03 +0000 (22:12 -0400)
After running a short external loopback test, when the external loopback is
removed and a normal cable inserted that is directly connected to a target
device, the system oops in the llpfc_set_rrq_active() routine.

When the loopback was inserted an FLOGI was transmit. As we're looped back,
we receive the FLOGI request. The FLOGI is ABTS'd as we recognize the same
wppn thus understand it's a loopback. However, as the ABTS sends address
information the port is not set to (fffffe), the ABTS is dropped on the
wire. A short 1 frame loopback test is run and completes before the ABTS
times out. The looback is unplugged and the new cable plugged in, and the
an FLOGI to the new device occurs and completes. Due to a mixup in ref
counting the completion of the new FLOGI releases the fabric ndlp. Then the
original ABTS completes and references the released ndlp generating the
oops.

Correct by no-op'ing the ABTS when in loopback mode (it will be dropped
anyway). Added a flag to track the mode to recognize when it should be
no-op'd.

Link: https://lore.kernel.org/r/20220506035519.50908-5-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>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_sli.c

index 346661dc5bf2dd87a6170ea6b66a7210e2894707..405c8a8dd7956731312227026918e993f1ef220e 100644 (file)
@@ -1025,6 +1025,7 @@ struct lpfc_hba {
 #define LS_MDS_LINK_DOWN      0x8      /* MDS Diagnostics Link Down */
 #define LS_MDS_LOOPBACK       0x10     /* MDS Diagnostics Link Up (Loopback) */
 #define LS_CT_VEN_RPA         0x20     /* Vendor RPA sent to switch */
+#define LS_EXTERNAL_LOOPBACK  0x40     /* External loopback plug inserted */
 
        uint32_t hba_flag;      /* hba generic flags */
 #define HBA_ERATT_HANDLED      0x1 /* This flag is set when eratt handled */
index ace812ce857d839d4afd86d04bcc0f3f4c7ce0ba..583a287b2d0c2ef187366f4210e338123f5a4a34 100644 (file)
@@ -1373,6 +1373,9 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        phba->hba_flag |= (HBA_FLOGI_ISSUED | HBA_FLOGI_OUTSTANDING);
 
+       /* Clear external loopback plug detected flag */
+       phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+
        /* Check for a deferred FLOGI ACC condition */
        if (phba->defer_flogi_acc_flag) {
                /* lookup ndlp for received FLOGI */
@@ -8128,6 +8131,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        uint32_t fc_flag = 0;
        uint32_t port_state = 0;
 
+       /* Clear external loopback plug detected flag */
+       phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+
        cmd = *lp++;
        sp = (struct serv_parm *) lp;
 
@@ -8179,6 +8185,12 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                        return 1;
                }
 
+               /* External loopback plug insertion detected */
+               phba->link_flag |= LS_EXTERNAL_LOOPBACK;
+
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_LIBDFC,
+                                "1119 External Loopback plug detected\n");
+
                /* abort the flogi coming back to ourselves
                 * due to external loopback on the port.
                 */
index e4805101cd5c141e976aceee0727313d8c47cce2..a833a493a3ee96607ca102ab596fae875994105f 100644 (file)
@@ -1229,6 +1229,9 @@ lpfc_linkdown(struct lpfc_hba *phba)
 
        phba->defer_flogi_acc_flag = false;
 
+       /* Clear external loopback plug detected flag */
+       phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+
        spin_lock_irq(&phba->hbalock);
        phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
        spin_unlock_irq(&phba->hbalock);
index fe4eb36426df8cafce8af000304343af5d6cb1ac..b509b31477596f6d27aaf665bb8357de14b45061 100644 (file)
@@ -12201,7 +12201,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        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))
+            phba->sli4_hba.link_state.status == LPFC_FC_LA_TYPE_LINK_DOWN) ||
+           (phba->link_flag & LS_EXTERNAL_LOOPBACK))
                ia = true;
        else
                ia = false;
@@ -12660,7 +12661,8 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                ndlp = lpfc_cmd->rdata->pnode;
 
                if (lpfc_is_link_up(phba) &&
-                   (ndlp && ndlp->nlp_state == NLP_STE_MAPPED_NODE))
+                   (ndlp && ndlp->nlp_state == NLP_STE_MAPPED_NODE) &&
+                   !(phba->link_flag & LS_EXTERNAL_LOOPBACK))
                        ia = false;
                else
                        ia = true;
@@ -21112,7 +21114,7 @@ lpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        abtswqe = &abtsiocb->wqe;
        memset(abtswqe, 0, sizeof(*abtswqe));
 
-       if (!lpfc_is_link_up(phba))
+       if (!lpfc_is_link_up(phba) || (phba->link_flag & LS_EXTERNAL_LOOPBACK))
                bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 1);
        bf_set(abort_cmd_criteria, &abtswqe->abort_cmd, T_XRI_TAG);
        abtswqe->abort_cmd.rsrvd5 = 0;