Daniel Wagner aad03e
From: James Smart <jsmart2021@gmail.com>
Daniel Wagner aad03e
Date: Fri, 3 Dec 2021 16:26:39 -0800
Daniel Wagner aad03e
Subject: scsi: lpfc: Fix NPIV port deletion crash
Daniel Wagner aad03e
Patch-mainline: Queued in subsystem maintainer repository
Daniel Wagner aad03e
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git
Daniel Wagner aad03e
Git-commit: 8ed190a91950564775cbaae9e8e8083a69a8da23
Daniel Wagner aad03e
References: bsc1192145
Daniel Wagner aad03e
Daniel Wagner aad03e
The driver is calling schedule_timeout after the DA_ID nameserver request
Daniel Wagner aad03e
and LOGO commands are issued to the fabric by the initiator virtual
Daniel Wagner aad03e
endport.  These fixed delay functions are causing long delays in the
Daniel Wagner aad03e
driver's worker thread when processing discovery I/Os in a serialized
Daniel Wagner aad03e
fashion, which is then triggering mailbox timeout errors artificially.
Daniel Wagner aad03e
Daniel Wagner aad03e
To fix this, don't wait on the DA_ID request to complete and call
Daniel Wagner aad03e
wait_event_timeout to allow the vport delete thread to make progress on an
Daniel Wagner aad03e
event driven basis rather than fixing the wait time.
Daniel Wagner aad03e
Daniel Wagner aad03e
Link: https://lore.kernel.org/r/20211204002644.116455-5-jsmart2021@gmail.com
Daniel Wagner aad03e
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner aad03e
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner aad03e
Signed-off-by: James Smart <jsmart2021@gmail.com>
Daniel Wagner aad03e
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Daniel Wagner aad03e
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner aad03e
---
Daniel Wagner aad03e
 drivers/scsi/lpfc/lpfc.h         |    2 
Daniel Wagner aad03e
 drivers/scsi/lpfc/lpfc_els.c     |   11 ++++-
Daniel Wagner aad03e
 drivers/scsi/lpfc/lpfc_hbadisc.c |    2 
Daniel Wagner aad03e
 drivers/scsi/lpfc/lpfc_vport.c   |   83 +++++++++++++++++++++++++++++----------
Daniel Wagner aad03e
 4 files changed, 73 insertions(+), 25 deletions(-)
Daniel Wagner aad03e
Daniel Wagner aad03e
--- a/drivers/scsi/lpfc/lpfc.h
Daniel Wagner aad03e
+++ b/drivers/scsi/lpfc/lpfc.h
Daniel Wagner aad03e
@@ -607,8 +607,6 @@ struct lpfc_vport {
Daniel Wagner aad03e
 	struct timer_list els_tmofunc;
Daniel Wagner aad03e
 	struct timer_list delayed_disc_tmo;
Daniel Wagner aad03e
 
Daniel Wagner aad03e
-	int unreg_vpi_cmpl;
Daniel Wagner aad03e
-
Daniel Wagner aad03e
 	uint8_t load_flag;
Daniel Wagner aad03e
 #define FC_LOADING		0x1	/* HBA in process of loading drvr */
Daniel Wagner aad03e
 #define FC_UNLOADING		0x2	/* HBA in process of unloading drvr */
Daniel Wagner aad03e
--- a/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner aad03e
+++ b/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner aad03e
@@ -10925,10 +10925,19 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba
Daniel Wagner aad03e
 		lpfc_can_disctmo(vport);
Daniel Wagner aad03e
 	}
Daniel Wagner aad03e
 
Daniel Wagner aad03e
+	if (ndlp->save_flags & NLP_WAIT_FOR_LOGO) {
Daniel Wagner aad03e
+		/* Wake up lpfc_vport_delete if waiting...*/
Daniel Wagner aad03e
+		if (ndlp->logo_waitq)
Daniel Wagner aad03e
+			wake_up(ndlp->logo_waitq);
Daniel Wagner aad03e
+		spin_lock_irq(&ndlp->lock);
Daniel Wagner aad03e
+		ndlp->nlp_flag &= ~(NLP_ISSUE_LOGO | NLP_LOGO_SND);
Daniel Wagner aad03e
+		ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO;
Daniel Wagner aad03e
+		spin_unlock_irq(&ndlp->lock);
Daniel Wagner aad03e
+	}
Daniel Wagner aad03e
+
Daniel Wagner aad03e
 	/* Safe to release resources now. */
Daniel Wagner aad03e
 	lpfc_els_free_iocb(phba, cmdiocb);
Daniel Wagner aad03e
 	lpfc_nlp_put(ndlp);
Daniel Wagner aad03e
-	vport->unreg_vpi_cmpl = VPORT_ERROR;
Daniel Wagner aad03e
 }
Daniel Wagner aad03e
 
Daniel Wagner aad03e
 /**
Daniel Wagner aad03e
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner aad03e
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner aad03e
@@ -3776,7 +3776,6 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba
Daniel Wagner aad03e
 	vport->vpi_state &= ~LPFC_VPI_REGISTERED;
Daniel Wagner aad03e
 	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
Daniel Wagner aad03e
 	spin_unlock_irq(shost->host_lock);
Daniel Wagner aad03e
-	vport->unreg_vpi_cmpl = VPORT_OK;
Daniel Wagner aad03e
 	mempool_free(pmb, phba->mbox_mem_pool);
Daniel Wagner aad03e
 	lpfc_cleanup_vports_rrqs(vport, NULL);
Daniel Wagner aad03e
 	/*
Daniel Wagner aad03e
@@ -3806,7 +3805,6 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vp
Daniel Wagner aad03e
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
Daniel Wagner aad03e
 				 "1800 Could not issue unreg_vpi\n");
Daniel Wagner aad03e
 		mempool_free(mbox, phba->mbox_mem_pool);
Daniel Wagner aad03e
-		vport->unreg_vpi_cmpl = VPORT_ERROR;
Daniel Wagner aad03e
 		return rc;
Daniel Wagner aad03e
 	}
Daniel Wagner aad03e
 	return 0;
Daniel Wagner aad03e
--- a/drivers/scsi/lpfc/lpfc_vport.c
Daniel Wagner aad03e
+++ b/drivers/scsi/lpfc/lpfc_vport.c
Daniel Wagner aad03e
@@ -486,22 +486,67 @@ lpfc_vport_create(struct fc_vport *fc_vp
Daniel Wagner aad03e
 }
Daniel Wagner aad03e
 
Daniel Wagner aad03e
 static int
Daniel Wagner aad03e
+lpfc_send_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
Daniel Wagner aad03e
+{
Daniel Wagner aad03e
+	int rc;
Daniel Wagner aad03e
+	struct lpfc_hba *phba = vport->phba;
Daniel Wagner aad03e
+
Daniel Wagner aad03e
+	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
Daniel Wagner aad03e
+
Daniel Wagner aad03e
+	spin_lock_irq(&ndlp->lock);
Daniel Wagner aad03e
+	if (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO) &&
Daniel Wagner aad03e
+	    !ndlp->logo_waitq) {
Daniel Wagner aad03e
+		ndlp->logo_waitq = &waitq;
Daniel Wagner aad03e
+		ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
Daniel Wagner aad03e
+		ndlp->nlp_flag |= NLP_ISSUE_LOGO;
Daniel Wagner aad03e
+		ndlp->save_flags |= NLP_WAIT_FOR_LOGO;
Daniel Wagner aad03e
+	}
Daniel Wagner aad03e
+	spin_unlock_irq(&ndlp->lock);
Daniel Wagner aad03e
+	rc = lpfc_issue_els_npiv_logo(vport, ndlp);
Daniel Wagner aad03e
+	if (!rc) {
Daniel Wagner aad03e
+		wait_event_timeout(waitq,
Daniel Wagner aad03e
+				   (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO)),
Daniel Wagner aad03e
+				   msecs_to_jiffies(phba->fc_ratov * 2000));
Daniel Wagner aad03e
+
Daniel Wagner aad03e
+		if (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO))
Daniel Wagner aad03e
+			goto logo_cmpl;
Daniel Wagner aad03e
+		/* LOGO wait failed.  Correct status. */
Daniel Wagner aad03e
+		rc = -EINTR;
Daniel Wagner aad03e
+	} else {
Daniel Wagner aad03e
+		rc = -EIO;
Daniel Wagner aad03e
+	}
Daniel Wagner aad03e
+
Daniel Wagner aad03e
+	/* Error - clean up node flags. */
Daniel Wagner aad03e
+	spin_lock_irq(&ndlp->lock);
Daniel Wagner aad03e
+	ndlp->nlp_flag &= ~NLP_ISSUE_LOGO;
Daniel Wagner aad03e
+	ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO;
Daniel Wagner aad03e
+	spin_unlock_irq(&ndlp->lock);
Daniel Wagner aad03e
+
Daniel Wagner aad03e
+ logo_cmpl:
Daniel Wagner aad03e
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT,
Daniel Wagner aad03e
+			 "1824 Issue LOGO completes with status %d\n",
Daniel Wagner aad03e
+			 rc);
Daniel Wagner aad03e
+	spin_lock_irq(&ndlp->lock);
Daniel Wagner aad03e
+	ndlp->logo_waitq = NULL;
Daniel Wagner aad03e
+	spin_unlock_irq(&ndlp->lock);
Daniel Wagner aad03e
+	return rc;
Daniel Wagner aad03e
+}
Daniel Wagner aad03e
+
Daniel Wagner aad03e
+static int
Daniel Wagner aad03e
 disable_vport(struct fc_vport *fc_vport)
Daniel Wagner aad03e
 {
Daniel Wagner aad03e
 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
Daniel Wagner aad03e
 	struct lpfc_hba   *phba = vport->phba;
Daniel Wagner aad03e
 	struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
Daniel Wagner aad03e
-	long timeout;
Daniel Wagner aad03e
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
Daniel Wagner aad03e
 
Daniel Wagner aad03e
+	/* Can't disable during an outstanding delete. */
Daniel Wagner aad03e
+	if (vport->load_flag & FC_UNLOADING)
Daniel Wagner aad03e
+		return 0;
Daniel Wagner aad03e
+
Daniel Wagner aad03e
 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
Daniel Wagner aad03e
-	if (ndlp && phba->link_state >= LPFC_LINK_UP) {
Daniel Wagner aad03e
-		vport->unreg_vpi_cmpl = VPORT_INVAL;
Daniel Wagner aad03e
-		timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
Daniel Wagner aad03e
-		if (!lpfc_issue_els_npiv_logo(vport, ndlp))
Daniel Wagner aad03e
-			while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
Daniel Wagner aad03e
-				timeout = schedule_timeout(timeout);
Daniel Wagner aad03e
-	}
Daniel Wagner aad03e
+	if (ndlp && phba->link_state >= LPFC_LINK_UP)
Daniel Wagner aad03e
+		(void)lpfc_send_npiv_logo(vport, ndlp);
Daniel Wagner aad03e
 
Daniel Wagner aad03e
 	lpfc_sli_host_down(vport);
Daniel Wagner aad03e
 
Daniel Wagner aad03e
@@ -600,7 +645,7 @@ lpfc_vport_delete(struct fc_vport *fc_vp
Daniel Wagner aad03e
 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
Daniel Wagner aad03e
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
Daniel Wagner aad03e
 	struct lpfc_hba  *phba = vport->phba;
Daniel Wagner aad03e
-	long timeout;
Daniel Wagner aad03e
+	int rc;
Daniel Wagner aad03e
 
Daniel Wagner aad03e
 	if (vport->port_type == LPFC_PHYSICAL_PORT) {
Daniel Wagner aad03e
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
Daniel Wagner aad03e
@@ -665,15 +710,14 @@ lpfc_vport_delete(struct fc_vport *fc_vp
Daniel Wagner aad03e
 	    phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
Daniel Wagner aad03e
 		if (vport->cfg_enable_da_id) {
Daniel Wagner aad03e
 			/* Send DA_ID and wait for a completion. */
Daniel Wagner aad03e
-			timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
Daniel Wagner aad03e
-			if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
Daniel Wagner aad03e
-				while (vport->ct_flags && timeout)
Daniel Wagner aad03e
-					timeout = schedule_timeout(timeout);
Daniel Wagner aad03e
-			else
Daniel Wagner aad03e
+			rc = lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0);
Daniel Wagner aad03e
+			if (rc) {
Daniel Wagner aad03e
 				lpfc_printf_log(vport->phba, KERN_WARNING,
Daniel Wagner aad03e
 						LOG_VPORT,
Daniel Wagner aad03e
 						"1829 CT command failed to "
Daniel Wagner aad03e
-						"delete objects on fabric\n");
Daniel Wagner aad03e
+						"delete objects on fabric, "
Daniel Wagner aad03e
+						"rc %d\n", rc);
Daniel Wagner aad03e
+			}
Daniel Wagner aad03e
 		}
Daniel Wagner aad03e
 
Daniel Wagner aad03e
 		/*
Daniel Wagner aad03e
@@ -688,11 +732,10 @@ lpfc_vport_delete(struct fc_vport *fc_vp
Daniel Wagner aad03e
 		ndlp = lpfc_findnode_did(vport, Fabric_DID);
Daniel Wagner aad03e
 		if (!ndlp)
Daniel Wagner aad03e
 			goto skip_logo;
Daniel Wagner aad03e
-		vport->unreg_vpi_cmpl = VPORT_INVAL;
Daniel Wagner aad03e
-		timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
Daniel Wagner aad03e
-		if (!lpfc_issue_els_npiv_logo(vport, ndlp))
Daniel Wagner aad03e
-			while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
Daniel Wagner aad03e
-				timeout = schedule_timeout(timeout);
Daniel Wagner aad03e
+
Daniel Wagner aad03e
+		rc = lpfc_send_npiv_logo(vport, ndlp);
Daniel Wagner aad03e
+		if (rc)
Daniel Wagner aad03e
+			goto skip_logo;
Daniel Wagner aad03e
 	}
Daniel Wagner aad03e
 
Daniel Wagner aad03e
 	if (!(phba->pport->load_flag & FC_UNLOADING))