Daniel Wagner 935719
From: James Smart <jsmart2021@gmail.com>
Daniel Wagner 935719
Date: Fri, 14 May 2021 12:55:49 -0700
Daniel Wagner 935719
Subject: scsi: lpfc: Fix unreleased RPIs when NPIV ports are created
Michal Kubecek 9a3a83
Patch-mainline: v5.14-rc1
Daniel Wagner 935719
Git-commit: 01131e7aae5d30e23e3cdd1eebe51bbc5489ae8f
Daniel Wagner 935719
References: bsc#1186451
Daniel Wagner 935719
Daniel Wagner 935719
While testing NPIV and watching logins and used RPI levels, it was seen the
Daniel Wagner 935719
used RPI count was much higher than the number of remote ports discovered.
Daniel Wagner 935719
Daniel Wagner 935719
Code inspection showed that remote port removals on any NPIV instance are
Daniel Wagner 935719
releasing the RPI, but not performing an UNREG_RPI with the adapter thus
Daniel Wagner 935719
the reference counting never fully drops and the RPI is never fully
Daniel Wagner 935719
released. This was happening on NPIV nodes due to a log of fabric ELS's to
Daniel Wagner 935719
fabric addresses. This lack of UNREG_RPI was introduced by a prior node
Daniel Wagner 935719
rework patch that performed the UNREG_RPI as part of node cleanup.
Daniel Wagner 935719
Daniel Wagner 935719
To resolve the issue, do the following:
Daniel Wagner 935719
Daniel Wagner 935719
 - Restore the RPI release code, but move the location to so that it is in
Daniel Wagner 935719
   line with the new node cleanup design.
Daniel Wagner 935719
Daniel Wagner 935719
 - NPIV ports now release the RPI and drop the node when the caller sets
Daniel Wagner 935719
   the NLP_RELEASE_RPI flag.
Daniel Wagner 935719
Daniel Wagner 935719
 - Set the NLP_RELEASE_RPI flag in node cleanup which will trigger a
Daniel Wagner 935719
   release of RPI to free pool.
Daniel Wagner 935719
Daniel Wagner 935719
 - Ensure there's an UNREG_RPI at LOGO completion so that RPI release is
Daniel Wagner 935719
   completed.
Daniel Wagner 935719
Daniel Wagner 935719
 - Stop offline_prep from skipping nodes that are UNUSED. The RPI may
Daniel Wagner 935719
   not have been released.
Daniel Wagner 935719
Daniel Wagner 935719
 - Stop the default RPI handling in lpfc_cmpl_els_rsp() for SLI4.
Daniel Wagner 935719
Daniel Wagner 935719
 - Fixed up debugfs RPI displays for better debugging.
Daniel Wagner 935719
Daniel Wagner 935719
Fixes: a70e63eee1c1 ("scsi: lpfc: Fix NPIV Fabric Node reference counting")
Daniel Wagner 935719
Link: https://lore.kernel.org/r/20210514195559.119853-2-jsmart2021@gmail.com
Daniel Wagner 935719
Cc: <stable@vger.kernel.org> # v5.11+
Daniel Wagner 935719
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner 935719
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner 935719
Signed-off-by: James Smart <jsmart2021@gmail.com>
Daniel Wagner 935719
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Daniel Wagner 935719
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner 935719
---
Daniel Wagner 935719
 drivers/scsi/lpfc/lpfc_debugfs.c   |    7 ---
Daniel Wagner 935719
 drivers/scsi/lpfc/lpfc_els.c       |   79 +++++++++++++++++++++++++++++--------
Daniel Wagner 935719
 drivers/scsi/lpfc/lpfc_hbadisc.c   |   27 +++++++++++-
Daniel Wagner 935719
 drivers/scsi/lpfc/lpfc_init.c      |    7 ---
Daniel Wagner 935719
 drivers/scsi/lpfc/lpfc_nportdisc.c |   25 +++++++----
Daniel Wagner 935719
 drivers/scsi/lpfc/lpfc_sli.c       |   10 +++-
Daniel Wagner 935719
 6 files changed, 115 insertions(+), 40 deletions(-)
Daniel Wagner 935719
Daniel Wagner 935719
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
Daniel Wagner 935719
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
Daniel Wagner 935719
@@ -868,11 +868,8 @@ lpfc_debugfs_nodelist_data(struct lpfc_v
Daniel Wagner 935719
 		len += scnprintf(buf+len, size-len,
Daniel Wagner 935719
 				"WWNN x%llx ",
Daniel Wagner 935719
 				wwn_to_u64(ndlp->nlp_nodename.u.wwn));
Daniel Wagner 935719
-		if (ndlp->nlp_flag & NLP_RPI_REGISTERED)
Daniel Wagner 935719
-			len += scnprintf(buf+len, size-len, "RPI:%04d ",
Daniel Wagner 935719
-					ndlp->nlp_rpi);
Daniel Wagner 935719
-		else
Daniel Wagner 935719
-			len += scnprintf(buf+len, size-len, "RPI:none ");
Daniel Wagner 935719
+		len += scnprintf(buf+len, size-len, "RPI:x%04x ",
Daniel Wagner 935719
+				 ndlp->nlp_rpi);
Daniel Wagner 935719
 		len +=  scnprintf(buf+len, size-len, "flag:x%08x ",
Daniel Wagner 935719
 			ndlp->nlp_flag);
Daniel Wagner 935719
 		if (!ndlp->nlp_type)
Daniel Wagner 935719
--- a/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner 935719
+++ b/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner 935719
@@ -2869,6 +2869,11 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba
Daniel Wagner 935719
 	 * log into the remote port.
Daniel Wagner 935719
 	 */
Daniel Wagner 935719
 	if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
Daniel Wagner 935719
+		spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
+		if (phba->sli_rev == LPFC_SLI_REV4)
Daniel Wagner 935719
+			ndlp->nlp_flag |= NLP_RELEASE_RPI;
Daniel Wagner 935719
+		ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
Daniel Wagner 935719
+		spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
 		lpfc_disc_state_machine(vport, ndlp, cmdiocb,
Daniel Wagner 935719
 					NLP_EVT_DEVICE_RM);
Daniel Wagner 935719
 		lpfc_els_free_iocb(phba, cmdiocb);
Daniel Wagner 935719
@@ -4371,6 +4376,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *
Daniel Wagner 935719
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
Daniel Wagner 935719
 	struct lpfc_vport *vport = cmdiocb->vport;
Daniel Wagner 935719
 	IOCB_t *irsp;
Daniel Wagner 935719
+	u32 xpt_flags = 0, did_mask = 0;
Daniel Wagner 935719
 
Daniel Wagner 935719
 	irsp = &rspiocb->iocb;
Daniel Wagner 935719
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
Daniel Wagner 935719
@@ -4386,9 +4392,20 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *
Daniel Wagner 935719
 	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
Daniel Wagner 935719
 		/* NPort Recovery mode or node is just allocated */
Daniel Wagner 935719
 		if (!lpfc_nlp_not_used(ndlp)) {
Daniel Wagner 935719
-			/* If the ndlp is being used by another discovery
Daniel Wagner 935719
-			 * thread, just unregister the RPI.
Daniel Wagner 935719
+			/* A LOGO is completing and the node is in NPR state.
Daniel Wagner 935719
+			 * If this a fabric node that cleared its transport
Daniel Wagner 935719
+			 * registration, release the rpi.
Daniel Wagner 935719
 			 */
Daniel Wagner 935719
+			xpt_flags = SCSI_XPT_REGD | NVME_XPT_REGD;
Daniel Wagner 935719
+			did_mask = ndlp->nlp_DID & Fabric_DID_MASK;
Daniel Wagner 935719
+			if (did_mask == Fabric_DID_MASK &&
Daniel Wagner 935719
+			    !(ndlp->fc4_xpt_flags & xpt_flags)) {
Daniel Wagner 935719
+				spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
+				ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
Daniel Wagner 935719
+				if (phba->sli_rev == LPFC_SLI_REV4)
Daniel Wagner 935719
+					ndlp->nlp_flag |= NLP_RELEASE_RPI;
Daniel Wagner 935719
+				spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
+			}
Daniel Wagner 935719
 			lpfc_unreg_rpi(vport, ndlp);
Daniel Wagner 935719
 		} else {
Daniel Wagner 935719
 			/* Indicate the node has already released, should
Daniel Wagner 935719
@@ -4424,28 +4441,37 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *
Daniel Wagner 935719
 {
Daniel Wagner 935719
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
Daniel Wagner 935719
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
Daniel Wagner 935719
+	u32 mbx_flag = pmb->mbox_flag;
Daniel Wagner 935719
+	u32 mbx_cmd = pmb->u.mb.mbxCommand;
Daniel Wagner 935719
 
Daniel Wagner 935719
 	pmb->ctx_buf = NULL;
Daniel Wagner 935719
 	pmb->ctx_ndlp = NULL;
Daniel Wagner 935719
 
Daniel Wagner 935719
-	lpfc_mbuf_free(phba, mp->virt, mp->phys);
Daniel Wagner 935719
-	kfree(mp);
Daniel Wagner 935719
-	mempool_free(pmb, phba->mbox_mem_pool);
Daniel Wagner 935719
 	if (ndlp) {
Daniel Wagner 935719
 		lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
Daniel Wagner 935719
-				 "0006 rpi x%x DID:%x flg:%x %d x%px\n",
Daniel Wagner 935719
+				 "0006 rpi x%x DID:%x flg:%x %d x%px "
Daniel Wagner 935719
+				 "mbx_cmd x%x mbx_flag x%x x%px\n",
Daniel Wagner 935719
 				 ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
Daniel Wagner 935719
-				 kref_read(&ndlp->kref),
Daniel Wagner 935719
-				 ndlp);
Daniel Wagner 935719
-		/* This is the end of the default RPI cleanup logic for
Daniel Wagner 935719
-		 * this ndlp and it could get released.  Clear the nlp_flags to
Daniel Wagner 935719
-		 * prevent any further processing.
Daniel Wagner 935719
+				 kref_read(&ndlp->kref), ndlp, mbx_cmd,
Daniel Wagner 935719
+				 mbx_flag, pmb);
Daniel Wagner 935719
+
Daniel Wagner 935719
+		/* This ends the default/temporary RPI cleanup logic for this
Daniel Wagner 935719
+		 * ndlp and the node and rpi needs to be released. Free the rpi
Daniel Wagner 935719
+		 * first on an UNREG_LOGIN and then release the final
Daniel Wagner 935719
+		 * references.
Daniel Wagner 935719
 		 */
Daniel Wagner 935719
+		spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
 		ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
Daniel Wagner 935719
+		if (mbx_cmd == MBX_UNREG_LOGIN)
Daniel Wagner 935719
+			ndlp->nlp_flag &= ~NLP_UNREG_INP;
Daniel Wagner 935719
+		spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
 		lpfc_nlp_put(ndlp);
Daniel Wagner 935719
-		lpfc_nlp_not_used(ndlp);
Daniel Wagner 935719
+		lpfc_drop_node(ndlp->vport, ndlp);
Daniel Wagner 935719
 	}
Daniel Wagner 935719
 
Daniel Wagner 935719
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
Daniel Wagner 935719
+	kfree(mp);
Daniel Wagner 935719
+	mempool_free(pmb, phba->mbox_mem_pool);
Daniel Wagner 935719
 	return;
Daniel Wagner 935719
 }
Daniel Wagner 935719
 
Daniel Wagner 935719
@@ -4503,11 +4529,11 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba,
Daniel Wagner 935719
 	/* ELS response tag <ulpIoTag> completes */
Daniel Wagner 935719
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
Daniel Wagner 935719
 			 "0110 ELS response tag x%x completes "
Daniel Wagner 935719
-			 "Data: x%x x%x x%x x%x x%x x%x x%x\n",
Daniel Wagner 935719
+			 "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%px\n",
Daniel Wagner 935719
 			 cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
Daniel Wagner 935719
 			 rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
Daniel Wagner 935719
 			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
Daniel Wagner 935719
-			 ndlp->nlp_rpi);
Daniel Wagner 935719
+			 ndlp->nlp_rpi, kref_read(&ndlp->kref), mbox);
Daniel Wagner 935719
 	if (mbox) {
Daniel Wagner 935719
 		if ((rspiocb->iocb.ulpStatus == 0) &&
Daniel Wagner 935719
 		    (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
Daniel Wagner 935719
@@ -4587,6 +4613,16 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba,
Daniel Wagner 935719
 		spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
 	}
Daniel Wagner 935719
 
Daniel Wagner 935719
+	/* An SLI4 NPIV instance wants to drop the node at this point under
Daniel Wagner 935719
+	 * these conditions and release the RPI.
Daniel Wagner 935719
+	 */
Daniel Wagner 935719
+	if (phba->sli_rev == LPFC_SLI_REV4 &&
Daniel Wagner 935719
+	    (vport && vport->port_type == LPFC_NPIV_PORT) &&
Daniel Wagner 935719
+	    ndlp->nlp_flag & NLP_RELEASE_RPI) {
Daniel Wagner 935719
+		lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
Daniel Wagner 935719
+		lpfc_drop_node(vport, ndlp);
Daniel Wagner 935719
+	}
Daniel Wagner 935719
+
Daniel Wagner 935719
 	/* Release the originating I/O reference. */
Daniel Wagner 935719
 	lpfc_els_free_iocb(phba, cmdiocb);
Daniel Wagner 935719
 	lpfc_nlp_put(ndlp);
Daniel Wagner 935719
@@ -4775,10 +4811,10 @@ lpfc_els_rsp_acc(struct lpfc_vport *vpor
Daniel Wagner 935719
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
Daniel Wagner 935719
 			 "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, "
Daniel Wagner 935719
 			 "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x "
Daniel Wagner 935719
-			 "RPI: x%x, fc_flag x%x\n",
Daniel Wagner 935719
+			 "RPI: x%x, fc_flag x%x refcnt %d\n",
Daniel Wagner 935719
 			 rc, elsiocb->iotag, elsiocb->sli4_xritag,
Daniel Wagner 935719
 			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
Daniel Wagner 935719
-			 ndlp->nlp_rpi, vport->fc_flag);
Daniel Wagner 935719
+			 ndlp->nlp_rpi, vport->fc_flag, kref_read(&ndlp->kref));
Daniel Wagner 935719
 	return 0;
Daniel Wagner 935719
 }
Daniel Wagner 935719
 
Daniel Wagner 935719
@@ -4856,6 +4892,17 @@ lpfc_els_rsp_reject(struct lpfc_vport *v
Daniel Wagner 935719
 		return 1;
Daniel Wagner 935719
 	}
Daniel Wagner 935719
 
Daniel Wagner 935719
+	/* The NPIV instance is rejecting this unsolicited ELS. Make sure the
Daniel Wagner 935719
+	 * node's assigned RPI needs to be released as this node will get
Daniel Wagner 935719
+	 * freed.
Daniel Wagner 935719
+	 */
Daniel Wagner 935719
+	if (phba->sli_rev == LPFC_SLI_REV4 &&
Daniel Wagner 935719
+	    vport->port_type == LPFC_NPIV_PORT) {
Daniel Wagner 935719
+		spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
+		ndlp->nlp_flag |= NLP_RELEASE_RPI;
Daniel Wagner 935719
+		spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
+	}
Daniel Wagner 935719
+
Daniel Wagner 935719
 	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
Daniel Wagner 935719
 	if (rc == IOCB_ERROR) {
Daniel Wagner 935719
 		lpfc_els_free_iocb(phba, elsiocb);
Daniel Wagner 935719
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner 935719
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner 935719
@@ -4791,12 +4791,17 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phb
Daniel Wagner 935719
 		ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
Daniel Wagner 935719
 		lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
Daniel Wagner 935719
 	} else {
Daniel Wagner 935719
+		/* NLP_RELEASE_RPI is only set for SLI4 ports. */
Daniel Wagner 935719
 		if (ndlp->nlp_flag & NLP_RELEASE_RPI) {
Daniel Wagner 935719
 			lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
Daniel Wagner 935719
+			spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
 			ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
Daniel Wagner 935719
 			ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
Daniel Wagner 935719
+			spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
 		}
Daniel Wagner 935719
+		spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
 		ndlp->nlp_flag &= ~NLP_UNREG_INP;
Daniel Wagner 935719
+		spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
 	}
Daniel Wagner 935719
 }
Daniel Wagner 935719
 
Daniel Wagner 935719
@@ -5131,8 +5136,10 @@ lpfc_cleanup_node(struct lpfc_vport *vpo
Daniel Wagner 935719
 	list_del_init(&ndlp->dev_loss_evt.evt_listp);
Daniel Wagner 935719
 	list_del_init(&ndlp->recovery_evt.evt_listp);
Daniel Wagner 935719
 	lpfc_cleanup_vports_rrqs(vport, ndlp);
Daniel Wagner 935719
+
Daniel Wagner 935719
 	if (phba->sli_rev == LPFC_SLI_REV4)
Daniel Wagner 935719
 		ndlp->nlp_flag |= NLP_RELEASE_RPI;
Daniel Wagner 935719
+
Daniel Wagner 935719
 	return 0;
Daniel Wagner 935719
 }
Daniel Wagner 935719
 
Daniel Wagner 935719
@@ -6178,8 +6185,23 @@ lpfc_nlp_release(struct kref *kref)
Daniel Wagner 935719
 	lpfc_cancel_retry_delay_tmo(vport, ndlp);
Daniel Wagner 935719
 	lpfc_cleanup_node(vport, ndlp);
Daniel Wagner 935719
 
Daniel Wagner 935719
-	/* Clear Node key fields to give other threads notice
Daniel Wagner 935719
-	 * that this node memory is not valid anymore.
Daniel Wagner 935719
+	/* Not all ELS transactions have registered the RPI with the port.
Daniel Wagner 935719
+	 * In these cases the rpi usage is temporary and the node is
Daniel Wagner 935719
+	 * released when the WQE is completed.  Catch this case to free the
Daniel Wagner 935719
+	 * RPI to the pool.  Because this node is in the release path, a lock
Daniel Wagner 935719
+	 * is unnecessary.  All references are gone and the node has been
Daniel Wagner 935719
+	 * dequeued.
Daniel Wagner 935719
+	 */
Daniel Wagner 935719
+	if (ndlp->nlp_flag & NLP_RELEASE_RPI) {
Daniel Wagner 935719
+		if (ndlp->nlp_rpi != LPFC_RPI_ALLOC_ERROR &&
Daniel Wagner 935719
+		    !(ndlp->nlp_flag & (NLP_RPI_REGISTERED | NLP_UNREG_INP))) {
Daniel Wagner 935719
+			lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
Daniel Wagner 935719
+			ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
Daniel Wagner 935719
+		}
Daniel Wagner 935719
+	}
Daniel Wagner 935719
+
Daniel Wagner 935719
+	/* The node is not freed back to memory, it is released to a pool so
Daniel Wagner 935719
+	 * the node fields need to be cleaned up.
Daniel Wagner 935719
 	 */
Daniel Wagner 935719
 	ndlp->vport = NULL;
Daniel Wagner 935719
 	ndlp->nlp_state = NLP_STE_FREED_NODE;
Daniel Wagner 935719
@@ -6259,6 +6281,7 @@ lpfc_nlp_not_used(struct lpfc_nodelist *
Daniel Wagner 935719
 		"node not used:   did:x%x flg:x%x refcnt:x%x",
Daniel Wagner 935719
 		ndlp->nlp_DID, ndlp->nlp_flag,
Daniel Wagner 935719
 		kref_read(&ndlp->kref));
Daniel Wagner 935719
+
Daniel Wagner 935719
 	if (kref_read(&ndlp->kref) == 1)
Daniel Wagner 935719
 		if (lpfc_nlp_put(ndlp))
Daniel Wagner 935719
 			return 1;
Daniel Wagner 935719
--- a/drivers/scsi/lpfc/lpfc_init.c
Daniel Wagner 935719
+++ b/drivers/scsi/lpfc/lpfc_init.c
Daniel Wagner 935719
@@ -3532,13 +3532,6 @@ lpfc_offline_prep(struct lpfc_hba *phba,
Daniel Wagner 935719
 			list_for_each_entry_safe(ndlp, next_ndlp,
Daniel Wagner 935719
 						 &vports[i]->fc_nodes,
Daniel Wagner 935719
 						 nlp_listp) {
Daniel Wagner 935719
-				if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
Daniel Wagner 935719
-					/* Driver must assume RPI is invalid for
Daniel Wagner 935719
-					 * any unused or inactive node.
Daniel Wagner 935719
-					 */
Daniel Wagner 935719
-					ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
Daniel Wagner 935719
-					continue;
Daniel Wagner 935719
-				}
Daniel Wagner 935719
 
Daniel Wagner 935719
 				spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
 				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
Daniel Wagner 935719
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
Daniel Wagner 935719
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
Daniel Wagner 935719
@@ -567,15 +567,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport,
Daniel Wagner 935719
 		/* no deferred ACC */
Daniel Wagner 935719
 		kfree(save_iocb);
Daniel Wagner 935719
 
Daniel Wagner 935719
-		/* In order to preserve RPIs, we want to cleanup
Daniel Wagner 935719
-		 * the default RPI the firmware created to rcv
Daniel Wagner 935719
-		 * this ELS request. The only way to do this is
Daniel Wagner 935719
-		 * to register, then unregister the RPI.
Daniel Wagner 935719
+		/* This is an NPIV SLI4 instance that does not need to register
Daniel Wagner 935719
+		 * a default RPI.
Daniel Wagner 935719
 		 */
Daniel Wagner 935719
-		spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
-		ndlp->nlp_flag |= (NLP_RM_DFLT_RPI | NLP_ACC_REGLOGIN |
Daniel Wagner 935719
-				   NLP_RCV_PLOGI);
Daniel Wagner 935719
-		spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
+		if (phba->sli_rev == LPFC_SLI_REV4) {
Daniel Wagner 935719
+			mempool_free(login_mbox, phba->mbox_mem_pool);
Daniel Wagner 935719
+			login_mbox = NULL;
Daniel Wagner 935719
+		} else {
Daniel Wagner 935719
+			/* In order to preserve RPIs, we want to cleanup
Daniel Wagner 935719
+			 * the default RPI the firmware created to rcv
Daniel Wagner 935719
+			 * this ELS request. The only way to do this is
Daniel Wagner 935719
+			 * to register, then unregister the RPI.
Daniel Wagner 935719
+			 */
Daniel Wagner 935719
+			spin_lock_irq(&ndlp->lock);
Daniel Wagner 935719
+			ndlp->nlp_flag |= (NLP_RM_DFLT_RPI | NLP_ACC_REGLOGIN |
Daniel Wagner 935719
+					   NLP_RCV_PLOGI);
Daniel Wagner 935719
+			spin_unlock_irq(&ndlp->lock);
Daniel Wagner 935719
+		}
Daniel Wagner 935719
+
Daniel Wagner 935719
 		stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
Daniel Wagner 935719
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
Daniel Wagner 935719
 		rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
Daniel Wagner 935719
--- a/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner 935719
+++ b/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner 935719
@@ -13625,9 +13625,15 @@ lpfc_sli4_sp_handle_mbox_event(struct lp
Daniel Wagner 935719
 		if (mcqe_status == MB_CQE_STATUS_SUCCESS) {
Daniel Wagner 935719
 			mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
Daniel Wagner 935719
 			ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
Daniel Wagner 935719
-			/* Reg_LOGIN of dflt RPI was successful. Now lets get
Daniel Wagner 935719
-			 * RID of the PPI using the same mbox buffer.
Daniel Wagner 935719
+
Daniel Wagner 935719
+			/* Reg_LOGIN of dflt RPI was successful. Mark the
Daniel Wagner 935719
+			 * node as having an UNREG_LOGIN in progress to stop
Daniel Wagner 935719
+			 * an unsolicited PLOGI from the same NPortId from
Daniel Wagner 935719
+			 * starting another mailbox transaction.
Daniel Wagner 935719
 			 */
Daniel Wagner 935719
+			spin_lock_irqsave(&ndlp->lock, iflags);
Daniel Wagner 935719
+			ndlp->nlp_flag |= NLP_UNREG_INP;
Daniel Wagner 935719
+			spin_unlock_irqrestore(&ndlp->lock, iflags);
Daniel Wagner 935719
 			lpfc_unreg_login(phba, vport->vpi,
Daniel Wagner 935719
 					 pmbox->un.varWords[0], pmb);
Daniel Wagner 935719
 			pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;