]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: lpfc: Update PRLO handling in direct attached topology
authorJustin Tee <justin.tee@broadcom.com>
Fri, 26 Jul 2024 23:15:10 +0000 (16:15 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 3 Aug 2024 01:48:05 +0000 (21:48 -0400)
A kref imbalance occurs when handling an unsolicited PRLO in direct
attached topology.

Rework PRLO rcv handling when in MAPPED state.  Save the state that we were
handling a PRLO by setting nlp_last_elscmd to ELS_CMD_PRLO.  Then in the
lpfc_cmpl_els_logo_acc() completion routine, manually restart discovery.
By issuing the PLOGI, which nlp_gets, before nlp_put at the end of the
lpfc_cmpl_els_logo_acc() routine, we are saving us from a final nlp_put.
And, we are still allowing the unreg_rpi to happen.

Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Link: https://lore.kernel.org/r/20240726231512.92867-7-justintee8345@gmail.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_nportdisc.c

index b5a8d050419afefb8c5e92dd4155d5afd490bc7a..de0ec945d2f1ea088d1a70ca180322b8cfd42312 100644 (file)
@@ -5246,9 +5246,10 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        /* ACC to LOGO completes to NPort <nlp_DID> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "0109 ACC to LOGO completes to NPort x%x refcnt %d "
-                        "Data: x%x x%x x%x\n",
-                        ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag,
-                        ndlp->nlp_state, ndlp->nlp_rpi);
+                        "last els x%x Data: x%x x%x x%x\n",
+                        ndlp->nlp_DID, kref_read(&ndlp->kref),
+                        ndlp->nlp_last_elscmd, ndlp->nlp_flag, ndlp->nlp_state,
+                        ndlp->nlp_rpi);
 
        /* This clause allows the LOGO ACC to complete and free resources
         * for the Fabric Domain Controller.  It does deliberately skip
@@ -5260,18 +5261,22 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                goto out;
 
        if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
-               /* If PLOGI is being retried, PLOGI completion will cleanup the
-                * node. The NLP_NPR_2B_DISC flag needs to be retained to make
-                * progress on nodes discovered from last RSCN.
-                */
-               if ((ndlp->nlp_flag & NLP_DELAY_TMO) &&
-                   (ndlp->nlp_last_elscmd == ELS_CMD_PLOGI))
-                       goto out;
-
                if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
                        lpfc_unreg_rpi(vport, ndlp);
 
+               /* If came from PRLO, then PRLO_ACC is done.
+                * Start rediscovery now.
+                */
+               if (ndlp->nlp_last_elscmd == ELS_CMD_PRLO) {
+                       spin_lock_irq(&ndlp->lock);
+                       ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+                       spin_unlock_irq(&ndlp->lock);
+                       ndlp->nlp_prev_state = ndlp->nlp_state;
+                       lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+                       lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+               }
        }
+
  out:
        /*
         * The driver received a LOGO from the rport and has ACK'd it.
index f6a53446e57f9dc483c8495337ed353c746fdac2..4574716c8764fba6d6db103f1f287b7cdb87cebc 100644 (file)
@@ -2652,8 +2652,26 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        /* flush the target */
        lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT);
 
-       /* Treat like rcv logo */
-       lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
+       /* Send PRLO_ACC */
+       spin_lock_irq(&ndlp->lock);
+       ndlp->nlp_flag |= NLP_LOGO_ACC;
+       spin_unlock_irq(&ndlp->lock);
+       lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
+
+       /* Save ELS_CMD_PRLO as the last elscmd and then set to NPR.
+        * lpfc_cmpl_els_logo_acc is expected to restart discovery.
+        */
+       ndlp->nlp_last_elscmd = ELS_CMD_PRLO;
+       ndlp->nlp_prev_state = ndlp->nlp_state;
+
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_ELS | LOG_DISCOVERY,
+                        "3422 DID x%06x nflag x%x lastels x%x ref cnt %u\n",
+                        ndlp->nlp_DID, ndlp->nlp_flag,
+                        ndlp->nlp_last_elscmd,
+                        kref_read(&ndlp->kref));
+
+       lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+
        return ndlp->nlp_state;
 }