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