scsi: lpfc: Clear deferred RSCN processing flag when driver is unloading
authorJustin Tee <justin.tee@broadcom.com>
Mon, 29 Apr 2024 22:15:42 +0000 (15:15 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 7 May 2024 01:53:58 +0000 (21:53 -0400)
Device recovery logic is skipped when the RSCN processing flag is set.
However during rmmod, the flag is not cleared leading to unnecessary delays
in waiting for completions on a link that is being offlined.

Move clearing of the RSCN deferred flag to a refactored routine when called
from device recovery, and set the IA flag when issuing an abort during
unload.

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

index c4172791c267511742a1e68a152abe00d2dfd7cc..b24fabbf20c45b2aa9949cd6fbafa47de38ab8ec 100644 (file)
 #include "lpfc_debugfs.h"
 
 
+/* Called to clear RSCN discovery flags when driver is unloading. */
+static bool
+lpfc_check_unload_and_clr_rscn(unsigned long *fc_flag)
+{
+       /* If unloading, then clear the FC_RSCN_DEFERRED flag */
+       if (test_bit(FC_UNLOADING, fc_flag)) {
+               clear_bit(FC_RSCN_DEFERRED, fc_flag);
+               return false;
+       }
+       return test_bit(FC_RSCN_DEFERRED, fc_flag);
+}
+
 /* Called to verify a rcv'ed ADISC was intended for us. */
 static int
 lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
@@ -213,8 +225,10 @@ void
 lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
        LIST_HEAD(abort_list);
+       LIST_HEAD(drv_cmpl_list);
        struct lpfc_sli_ring *pring;
        struct lpfc_iocbq *iocb, *next_iocb;
+       int retval = 0;
 
        pring = lpfc_phba_elsring(phba);
 
@@ -250,11 +264,20 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 
        /* Abort the targeted IOs and remove them from the abort list. */
        list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
-                       spin_lock_irq(&phba->hbalock);
-                       list_del_init(&iocb->dlist);
-                       lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL);
-                       spin_unlock_irq(&phba->hbalock);
+               spin_lock_irq(&phba->hbalock);
+               list_del_init(&iocb->dlist);
+               retval = lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL);
+               spin_unlock_irq(&phba->hbalock);
+
+               if (retval && test_bit(FC_UNLOADING, &phba->pport->load_flag)) {
+                       list_del_init(&iocb->list);
+                       list_add_tail(&iocb->list, &drv_cmpl_list);
+               }
        }
+
+       lpfc_sli_cancel_iocbs(phba, &drv_cmpl_list, IOSTAT_LOCAL_REJECT,
+                             IOERR_SLI_ABORTED);
+
        /* Make sure HBA is alive */
        lpfc_issue_hb_tmo(phba);
 
@@ -1604,10 +1627,8 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport,
 {
        struct lpfc_hba  *phba = vport->phba;
 
-       /* Don't do anything that will mess up processing of the
-        * previous RSCN.
-        */
-       if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag))
+       /* Don't do anything that disrupts the RSCN unless lpfc is unloading. */
+       if (lpfc_check_unload_and_clr_rscn(&vport->fc_flag))
                return ndlp->nlp_state;
 
        /* software abort outstanding PLOGI */
@@ -1790,10 +1811,8 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
 {
        struct lpfc_hba  *phba = vport->phba;
 
-       /* Don't do anything that will mess up processing of the
-        * previous RSCN.
-        */
-       if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag))
+       /* Don't do anything that disrupts the RSCN unless lpfc is unloading. */
+       if (lpfc_check_unload_and_clr_rscn(&vport->fc_flag))
                return ndlp->nlp_state;
 
        /* software abort outstanding ADISC */
@@ -2059,10 +2078,8 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
                                 void *arg,
                                 uint32_t evt)
 {
-       /* Don't do anything that will mess up processing of the
-        * previous RSCN.
-        */
-       if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag))
+       /* Don't do anything that disrupts the RSCN unless lpfc is unloading. */
+       if (lpfc_check_unload_and_clr_rscn(&vport->fc_flag))
                return ndlp->nlp_state;
 
        ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
@@ -2375,10 +2392,8 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
 {
        struct lpfc_hba  *phba = vport->phba;
 
-       /* Don't do anything that will mess up processing of the
-        * previous RSCN.
-        */
-       if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag))
+       /* Don't do anything that disrupts the RSCN unless lpfc is unloading. */
+       if (lpfc_check_unload_and_clr_rscn(&vport->fc_flag))
                return ndlp->nlp_state;
 
        /* software abort outstanding PRLI */
@@ -2894,10 +2909,8 @@ static uint32_t
 lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                           void *arg, uint32_t evt)
 {
-       /* Don't do anything that will mess up processing of the
-        * previous RSCN.
-        */
-       if (test_bit(FC_RSCN_DEFERRED, &vport->fc_flag))
+       /* Don't do anything that disrupts the RSCN unless lpfc is unloading. */
+       if (lpfc_check_unload_and_clr_rscn(&vport->fc_flag))
                return ndlp->nlp_state;
 
        lpfc_cancel_retry_delay_tmo(vport, ndlp);
index a028e008dd1ee8937e448b13db3394be2d562d41..fa3d458af1931e77a5fac53c3e5824ae221c731c 100644 (file)
@@ -12361,10 +12361,10 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        /* ELS cmd tag <ulpIoTag> completes */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "0139 Ignoring ELS cmd code x%x completion Data: "
+                       "0139 Ignoring ELS cmd code x%x ref cnt x%x Data: "
                        "x%x x%x x%x x%px\n",
-                       ulp_command, ulp_status, ulp_word4, iotag,
-                       cmdiocb->ndlp);
+                       ulp_command, kref_read(&cmdiocb->ndlp->kref),
+                       ulp_status, ulp_word4, iotag, cmdiocb->ndlp);
        /*
         * Deref the ndlp after free_iocb. sli_release_iocb will access the ndlp
         * if exchange is busy.
@@ -12460,7 +12460,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                }
        }
 
-       if (phba->link_state < LPFC_LINK_UP ||
+       /* Just close the exchange under certain conditions. */
+       if (test_bit(FC_UNLOADING, &vport->load_flag) ||
+           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->link_flag & LS_EXTERNAL_LOOPBACK))
@@ -12507,10 +12509,10 @@ abort_iotag_exit:
        lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
                         "0339 Abort IO XRI x%x, Original iotag x%x, "
                         "abort tag x%x Cmdjob : x%px Abortjob : x%px "
-                        "retval x%x\n",
+                        "retval x%x : IA %d\n",
                         ulp_context, (phba->sli_rev == LPFC_SLI_REV4) ?
                         cmdiocb->iotag : iotag, iotag, cmdiocb, abtsiocbp,
-                        retval);
+                        retval, ia);
        if (retval) {
                cmdiocb->cmd_flag &= ~LPFC_DRIVER_ABORTED;
                __lpfc_sli_release_iocbq(phba, abtsiocbp);