Daniel Wagner f13c72
From: James Smart <jsmart2021@gmail.com>
Daniel Wagner f13c72
Date: Fri, 14 May 2021 12:55:54 -0700
Daniel Wagner f13c72
Subject: scsi: lpfc: Fix node handling for Fabric Controller and Domain
Daniel Wagner f13c72
 Controller
Daniel Wagner f13c72
Patch-mainline: Queued in subsystem maintainer repository
Daniel Wagner f13c72
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
Daniel Wagner f13c72
Git-commit: fe83e3b9b422ac8ece2359c7b7290efe7f0335a2
Daniel Wagner f13c72
References: bsc#1186451
Daniel Wagner f13c72
Daniel Wagner f13c72
During link bounce testing, RPI counts were seen to differ from the number
Daniel Wagner f13c72
of nodes. For fabric and domain controllers, a temporary RPI is assigned,
Daniel Wagner f13c72
but the code isn't registering it. If the nodes do go away, such as on link
Daniel Wagner f13c72
down, the temporary RPI isn't being released.
Daniel Wagner f13c72
Daniel Wagner f13c72
Change the way these two fabric services are managed, make them behave like
Daniel Wagner f13c72
any other remote port. Register the RPI and register with the transport.
Daniel Wagner f13c72
Never leave the nodes in a NPR or UNUSED state where their RPI is in limbo.
Daniel Wagner f13c72
This allows them to follow normal dev_loss_tmo handling, RPI refcounting,
Daniel Wagner f13c72
and normal removal rules. It also allows fabric I/Os to use the RPI for
Daniel Wagner f13c72
traffic requests.
Daniel Wagner f13c72
Daniel Wagner f13c72
Note: There is some logic that still has a couple of exceptions when the
Daniel Wagner f13c72
Domain controller (0xfffcXX). There are cases where the fabric won't have a
Daniel Wagner f13c72
valid login but will send RDP. Other times, it will it send a LOGO then an
Daniel Wagner f13c72
RDP. It makes for ad-hoc behavior to manage the node. Exceptions are
Daniel Wagner f13c72
documented in the code.
Daniel Wagner f13c72
Daniel Wagner f13c72
Link: https://lore.kernel.org/r/20210514195559.119853-7-jsmart2021@gmail.com
Daniel Wagner f13c72
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner f13c72
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner f13c72
Signed-off-by: James Smart <jsmart2021@gmail.com>
Daniel Wagner f13c72
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Daniel Wagner f13c72
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner f13c72
---
Daniel Wagner f13c72
 drivers/scsi/lpfc/lpfc_crtn.h      |    1 
Daniel Wagner f13c72
 drivers/scsi/lpfc/lpfc_debugfs.c   |    4 -
Daniel Wagner f13c72
 drivers/scsi/lpfc/lpfc_disc.h      |    1 
Daniel Wagner f13c72
 drivers/scsi/lpfc/lpfc_els.c       |  137 +++++++++++++++++++++++++++++++++----
Daniel Wagner f13c72
 drivers/scsi/lpfc/lpfc_hbadisc.c   |   54 +++++++++++++-
Daniel Wagner f13c72
 drivers/scsi/lpfc/lpfc_nportdisc.c |   11 ++
Daniel Wagner f13c72
 drivers/scsi/lpfc/lpfc_sli.c       |    1 
Daniel Wagner f13c72
 7 files changed, 189 insertions(+), 20 deletions(-)
Daniel Wagner f13c72
Daniel Wagner f13c72
--- a/drivers/scsi/lpfc/lpfc_crtn.h
Daniel Wagner f13c72
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
Daniel Wagner f13c72
@@ -80,6 +80,7 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc
Daniel Wagner f13c72
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
Daniel Wagner f13c72
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
Daniel Wagner f13c72
 void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
Daniel Wagner f13c72
+void lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb);
Daniel Wagner f13c72
 void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
Daniel Wagner f13c72
 void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *);
Daniel Wagner f13c72
 void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
Daniel Wagner f13c72
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
Daniel Wagner f13c72
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
Daniel Wagner f13c72
@@ -863,10 +863,10 @@ lpfc_debugfs_nodelist_data(struct lpfc_v
Daniel Wagner f13c72
 		len += scnprintf(buf+len, size-len, "%s DID:x%06x ",
Daniel Wagner f13c72
 				statep, ndlp->nlp_DID);
Daniel Wagner f13c72
 		len += scnprintf(buf+len, size-len,
Daniel Wagner f13c72
-				"WWPN x%llx ",
Daniel Wagner f13c72
+				"WWPN x%016llx ",
Daniel Wagner f13c72
 				wwn_to_u64(ndlp->nlp_portname.u.wwn));
Daniel Wagner f13c72
 		len += scnprintf(buf+len, size-len,
Daniel Wagner f13c72
-				"WWNN x%llx ",
Daniel Wagner f13c72
+				"WWNN x%016llx ",
Daniel Wagner f13c72
 				wwn_to_u64(ndlp->nlp_nodename.u.wwn));
Daniel Wagner f13c72
 		len += scnprintf(buf+len, size-len, "RPI:x%04x ",
Daniel Wagner f13c72
 				 ndlp->nlp_rpi);
Daniel Wagner f13c72
--- a/drivers/scsi/lpfc/lpfc_disc.h
Daniel Wagner f13c72
+++ b/drivers/scsi/lpfc/lpfc_disc.h
Daniel Wagner f13c72
@@ -86,6 +86,7 @@ enum lpfc_fc4_xpt_flags {
Daniel Wagner f13c72
 
Daniel Wagner f13c72
 struct lpfc_nodelist {
Daniel Wagner f13c72
 	struct list_head nlp_listp;
Daniel Wagner f13c72
+	struct serv_parm fc_sparam;		/* buffer for service params */
Daniel Wagner f13c72
 	struct lpfc_name nlp_portname;
Daniel Wagner f13c72
 	struct lpfc_name nlp_nodename;
Daniel Wagner f13c72
 
Daniel Wagner f13c72
--- a/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner f13c72
+++ b/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner f13c72
@@ -3086,6 +3086,95 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba,
Daniel Wagner f13c72
 }
Daniel Wagner f13c72
 
Daniel Wagner f13c72
 /**
Daniel Wagner f13c72
+ * lpfc_reg_fab_ctrl_node - RPI register the fabric controller node.
Daniel Wagner f13c72
+ * @vport: pointer to lpfc_vport data structure.
Daniel Wagner f13c72
+ * @fc_ndlp: pointer to the fabric controller (0xfffffd) node.
Daniel Wagner f13c72
+ *
Daniel Wagner f13c72
+ * This routine registers the rpi assigned to the fabric controller
Daniel Wagner f13c72
+ * NPort_ID (0xfffffd) with the port and moves the node to UNMAPPED
Daniel Wagner f13c72
+ * state triggering a registration with the SCSI transport.
Daniel Wagner f13c72
+ *
Daniel Wagner f13c72
+ * This routine is single out because the fabric controller node
Daniel Wagner f13c72
+ * does not receive a PLOGI.  This routine is consumed by the
Daniel Wagner f13c72
+ * SCR and RDF ELS commands.  Callers are expected to qualify
Daniel Wagner f13c72
+ * with SLI4 first.
Daniel Wagner f13c72
+ **/
Daniel Wagner f13c72
+static int
Daniel Wagner f13c72
+lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp)
Daniel Wagner f13c72
+{
Daniel Wagner f13c72
+	int rc = 0;
Daniel Wagner f13c72
+	struct lpfc_hba *phba = vport->phba;
Daniel Wagner f13c72
+	struct lpfc_nodelist *ns_ndlp;
Daniel Wagner f13c72
+	LPFC_MBOXQ_t *mbox;
Daniel Wagner f13c72
+	struct lpfc_dmabuf *mp;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	if (fc_ndlp->nlp_flag & NLP_RPI_REGISTERED)
Daniel Wagner f13c72
+		return rc;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	ns_ndlp = lpfc_findnode_did(vport, NameServer_DID);
Daniel Wagner f13c72
+	if (!ns_ndlp)
Daniel Wagner f13c72
+		return -ENODEV;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
Daniel Wagner f13c72
+			 "0935 %s: Reg FC RPI x%x on FC DID x%x NSSte: x%x\n",
Daniel Wagner f13c72
+			 __func__, fc_ndlp->nlp_rpi, fc_ndlp->nlp_DID,
Daniel Wagner f13c72
+			 ns_ndlp->nlp_state);
Daniel Wagner f13c72
+	if (ns_ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
Daniel Wagner f13c72
+		return -ENODEV;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
Daniel Wagner f13c72
+	if (!mbox) {
Daniel Wagner f13c72
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
Daniel Wagner f13c72
+				 "0936 %s: no memory for reg_login "
Daniel Wagner f13c72
+				 "Data: x%x x%x x%x x%x\n", __func__,
Daniel Wagner f13c72
+				 fc_ndlp->nlp_DID, fc_ndlp->nlp_state,
Daniel Wagner f13c72
+				 fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi);
Daniel Wagner f13c72
+		return -ENOMEM;
Daniel Wagner f13c72
+	}
Daniel Wagner f13c72
+	rc = lpfc_reg_rpi(phba, vport->vpi, fc_ndlp->nlp_DID,
Daniel Wagner f13c72
+			  (u8 *)&vport->fc_sparam, mbox, fc_ndlp->nlp_rpi);
Daniel Wagner f13c72
+	if (rc) {
Daniel Wagner f13c72
+		rc = -EACCES;
Daniel Wagner f13c72
+		goto out;
Daniel Wagner f13c72
+	}
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	fc_ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
Daniel Wagner f13c72
+	mbox->mbox_cmpl = lpfc_mbx_cmpl_fc_reg_login;
Daniel Wagner f13c72
+	mbox->ctx_ndlp = lpfc_nlp_get(fc_ndlp);
Daniel Wagner f13c72
+	if (!mbox->ctx_ndlp) {
Daniel Wagner f13c72
+		rc = -ENOMEM;
Daniel Wagner f13c72
+		goto out_mem;
Daniel Wagner f13c72
+	}
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	mbox->vport = vport;
Daniel Wagner f13c72
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
Daniel Wagner f13c72
+	if (rc == MBX_NOT_FINISHED) {
Daniel Wagner f13c72
+		rc = -ENODEV;
Daniel Wagner f13c72
+		lpfc_nlp_put(fc_ndlp);
Daniel Wagner f13c72
+		goto out_mem;
Daniel Wagner f13c72
+	}
Daniel Wagner f13c72
+	/* Success path. Exit. */
Daniel Wagner f13c72
+	lpfc_nlp_set_state(vport, fc_ndlp,
Daniel Wagner f13c72
+			   NLP_STE_REG_LOGIN_ISSUE);
Daniel Wagner f13c72
+	return 0;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+ out_mem:
Daniel Wagner f13c72
+	fc_ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
Daniel Wagner f13c72
+	mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
Daniel Wagner f13c72
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
Daniel Wagner f13c72
+	kfree(mp);
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+ out:
Daniel Wagner f13c72
+	mempool_free(mbox, phba->mbox_mem_pool);
Daniel Wagner f13c72
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
Daniel Wagner f13c72
+			 "0938 %s: failed to format reg_login "
Daniel Wagner f13c72
+			 "Data: x%x x%x x%x x%x\n", __func__,
Daniel Wagner f13c72
+			 fc_ndlp->nlp_DID, fc_ndlp->nlp_state,
Daniel Wagner f13c72
+			 fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi);
Daniel Wagner f13c72
+	return rc;
Daniel Wagner f13c72
+}
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+/**
Daniel Wagner f13c72
  * lpfc_cmpl_els_disc_cmd - Completion callback function for Discovery ELS cmd
Daniel Wagner f13c72
  * @phba: pointer to lpfc hba data structure.
Daniel Wagner f13c72
  * @cmdiocb: pointer to lpfc command iocb data structure.
Daniel Wagner f13c72
@@ -3231,10 +3320,18 @@ lpfc_issue_els_scr(struct lpfc_vport *vp
Daniel Wagner f13c72
 
Daniel Wagner f13c72
 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
Daniel Wagner f13c72
 				     ndlp->nlp_DID, ELS_CMD_SCR);
Daniel Wagner f13c72
-
Daniel Wagner f13c72
 	if (!elsiocb)
Daniel Wagner f13c72
 		return 1;
Daniel Wagner f13c72
 
Daniel Wagner f13c72
+	if (phba->sli_rev == LPFC_SLI_REV4) {
Daniel Wagner f13c72
+		rc = lpfc_reg_fab_ctrl_node(vport, ndlp);
Daniel Wagner f13c72
+		if (rc) {
Daniel Wagner f13c72
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
Daniel Wagner f13c72
+					 "0937 %s: Failed to reg fc node, rc %d\n",
Daniel Wagner f13c72
+					 __func__, rc);
Daniel Wagner f13c72
+			return 1;
Daniel Wagner f13c72
+		}
Daniel Wagner f13c72
+	}
Daniel Wagner f13c72
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
Daniel Wagner f13c72
 
Daniel Wagner f13c72
 	*((uint32_t *) (pcmd)) = ELS_CMD_SCR;
Daniel Wagner f13c72
@@ -3522,6 +3619,17 @@ lpfc_issue_els_rdf(struct lpfc_vport *vp
Daniel Wagner f13c72
 	if (!elsiocb)
Daniel Wagner f13c72
 		return -ENOMEM;
Daniel Wagner f13c72
 
Daniel Wagner f13c72
+	if (phba->sli_rev == LPFC_SLI_REV4 &&
Daniel Wagner f13c72
+	    !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
Daniel Wagner f13c72
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
Daniel Wagner f13c72
+				 "0939 %s: FC_NODE x%x RPI x%x flag x%x "
Daniel Wagner f13c72
+				 "ste x%x type x%x Not registered\n",
Daniel Wagner f13c72
+				 __func__, ndlp->nlp_DID, ndlp->nlp_rpi,
Daniel Wagner f13c72
+				 ndlp->nlp_flag, ndlp->nlp_state,
Daniel Wagner f13c72
+				 ndlp->nlp_type);
Daniel Wagner f13c72
+		return -ENODEV;
Daniel Wagner f13c72
+	}
Daniel Wagner f13c72
+
Daniel Wagner f13c72
 	/* Configure the payload for the supported FPIN events. */
Daniel Wagner f13c72
 	prdf = (struct lpfc_els_rdf_req *)
Daniel Wagner f13c72
 		(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
Daniel Wagner f13c72
@@ -4396,7 +4504,6 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *
Daniel Wagner f13c72
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
Daniel Wagner f13c72
 	struct lpfc_vport *vport = cmdiocb->vport;
Daniel Wagner f13c72
 	IOCB_t *irsp;
Daniel Wagner f13c72
-	u32 xpt_flags = 0, did_mask = 0;
Daniel Wagner f13c72
 
Daniel Wagner f13c72
 	irsp = &rspiocb->iocb;
Daniel Wagner f13c72
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
Daniel Wagner f13c72
@@ -4409,6 +4516,15 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *
Daniel Wagner f13c72
 			 ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag,
Daniel Wagner f13c72
 			 ndlp->nlp_state, ndlp->nlp_rpi);
Daniel Wagner f13c72
 
Daniel Wagner f13c72
+	/* This clause allows the LOGO ACC to complete and free resources
Daniel Wagner f13c72
+	 * for the Fabric Domain Controller.  It does deliberately skip
Daniel Wagner f13c72
+	 * the unreg_rpi and release rpi because some fabrics send RDP
Daniel Wagner f13c72
+	 * requests after logging out from the initiator.
Daniel Wagner f13c72
+	 */
Daniel Wagner f13c72
+	if (ndlp->nlp_type & NLP_FABRIC &&
Daniel Wagner f13c72
+	    ((ndlp->nlp_DID & WELL_KNOWN_DID_MASK) != WELL_KNOWN_DID_MASK))
Daniel Wagner f13c72
+		goto out;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
 	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
Daniel Wagner f13c72
 		/* NPort Recovery mode or node is just allocated */
Daniel Wagner f13c72
 		if (!lpfc_nlp_not_used(ndlp)) {
Daniel Wagner f13c72
@@ -4416,16 +4532,11 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *
Daniel Wagner f13c72
 			 * If this a fabric node that cleared its transport
Daniel Wagner f13c72
 			 * registration, release the rpi.
Daniel Wagner f13c72
 			 */
Daniel Wagner f13c72
-			xpt_flags = SCSI_XPT_REGD | NVME_XPT_REGD;
Daniel Wagner f13c72
-			did_mask = ndlp->nlp_DID & Fabric_DID_MASK;
Daniel Wagner f13c72
-			if (did_mask == Fabric_DID_MASK &&
Daniel Wagner f13c72
-			    !(ndlp->fc4_xpt_flags & xpt_flags)) {
Daniel Wagner f13c72
-				spin_lock_irq(&ndlp->lock);
Daniel Wagner f13c72
-				ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
Daniel Wagner f13c72
-				if (phba->sli_rev == LPFC_SLI_REV4)
Daniel Wagner f13c72
-					ndlp->nlp_flag |= NLP_RELEASE_RPI;
Daniel Wagner f13c72
-				spin_unlock_irq(&ndlp->lock);
Daniel Wagner f13c72
-			}
Daniel Wagner f13c72
+			spin_lock_irq(&ndlp->lock);
Daniel Wagner f13c72
+			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
Daniel Wagner f13c72
+			if (phba->sli_rev == LPFC_SLI_REV4)
Daniel Wagner f13c72
+				ndlp->nlp_flag |= NLP_RELEASE_RPI;
Daniel Wagner f13c72
+			spin_unlock_irq(&ndlp->lock);
Daniel Wagner f13c72
 			lpfc_unreg_rpi(vport, ndlp);
Daniel Wagner f13c72
 		} else {
Daniel Wagner f13c72
 			/* Indicate the node has already released, should
Daniel Wagner f13c72
@@ -4434,7 +4545,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *
Daniel Wagner f13c72
 			cmdiocb->context1 = NULL;
Daniel Wagner f13c72
 		}
Daniel Wagner f13c72
 	}
Daniel Wagner f13c72
-
Daniel Wagner f13c72
+ out:
Daniel Wagner f13c72
 	/*
Daniel Wagner f13c72
 	 * The driver received a LOGO from the rport and has ACK'd it.
Daniel Wagner f13c72
 	 * At this point, the driver is done so release the IOCB
Daniel Wagner f13c72
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner f13c72
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner f13c72
@@ -77,9 +77,7 @@ static int
Daniel Wagner f13c72
 lpfc_valid_xpt_node(struct lpfc_nodelist *ndlp)
Daniel Wagner f13c72
 {
Daniel Wagner f13c72
 	if (ndlp->nlp_fc4_type ||
Daniel Wagner f13c72
-	    ndlp->nlp_DID == Fabric_DID ||
Daniel Wagner f13c72
-	    ndlp->nlp_DID == NameServer_DID ||
Daniel Wagner f13c72
-	    ndlp->nlp_DID == FDMI_DID)
Daniel Wagner f13c72
+	    ndlp->nlp_type & NLP_FABRIC)
Daniel Wagner f13c72
 		return 1;
Daniel Wagner f13c72
 	return 0;
Daniel Wagner f13c72
 }
Daniel Wagner f13c72
@@ -826,7 +824,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vpo
Daniel Wagner f13c72
 		if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
Daniel Wagner f13c72
 		    ((vport->port_type == LPFC_NPIV_PORT) &&
Daniel Wagner f13c72
 		     ((ndlp->nlp_DID == NameServer_DID) ||
Daniel Wagner f13c72
-		      (ndlp->nlp_DID == FDMI_DID))))
Daniel Wagner f13c72
+		      (ndlp->nlp_DID == FDMI_DID) ||
Daniel Wagner f13c72
+		      (ndlp->nlp_DID == Fabric_Cntl_DID))))
Daniel Wagner f13c72
 			lpfc_unreg_rpi(vport, ndlp);
Daniel Wagner f13c72
 
Daniel Wagner f13c72
 		/* Leave Fabric nodes alone on link down */
Daniel Wagner f13c72
@@ -4161,6 +4160,53 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_h
Daniel Wagner f13c72
 	return;
Daniel Wagner f13c72
 }
Daniel Wagner f13c72
 
Daniel Wagner f13c72
+/*
Daniel Wagner f13c72
+ * This routine handles processing a Fabric Controller REG_LOGIN mailbox
Daniel Wagner f13c72
+ * command upon completion. It is setup in the LPFC_MBOXQ
Daniel Wagner f13c72
+ * as the completion routine when the command is handed off to the SLI layer.
Daniel Wagner f13c72
+ */
Daniel Wagner f13c72
+void
Daniel Wagner f13c72
+lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
Daniel Wagner f13c72
+{
Daniel Wagner f13c72
+	struct lpfc_vport *vport = pmb->vport;
Daniel Wagner f13c72
+	MAILBOX_t *mb = &pmb->u.mb;
Daniel Wagner f13c72
+	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
Daniel Wagner f13c72
+	struct lpfc_nodelist *ndlp;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
Daniel Wagner f13c72
+	pmb->ctx_ndlp = NULL;
Daniel Wagner f13c72
+	pmb->ctx_buf = NULL;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	if (mb->mbxStatus) {
Daniel Wagner f13c72
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
Daniel Wagner f13c72
+				 "0933 %s: Register FC login error: 0x%x\n",
Daniel Wagner f13c72
+				 __func__, mb->mbxStatus);
Daniel Wagner f13c72
+		goto out;
Daniel Wagner f13c72
+	}
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	if (phba->sli_rev < LPFC_SLI_REV4)
Daniel Wagner f13c72
+		ndlp->nlp_rpi = mb->un.varWords[0];
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
Daniel Wagner f13c72
+			 "0934 %s: Complete FC x%x RegLogin rpi x%x ste x%x\n",
Daniel Wagner f13c72
+			 __func__, ndlp->nlp_DID, ndlp->nlp_rpi,
Daniel Wagner f13c72
+			 ndlp->nlp_state);
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	ndlp->nlp_flag |= NLP_RPI_REGISTERED;
Daniel Wagner f13c72
+	ndlp->nlp_type |= NLP_FABRIC;
Daniel Wagner f13c72
+	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+ out:
Daniel Wagner f13c72
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
Daniel Wagner f13c72
+	kfree(mp);
Daniel Wagner f13c72
+	mempool_free(pmb, phba->mbox_mem_pool);
Daniel Wagner f13c72
+
Daniel Wagner f13c72
+	/* Drop the reference count from the mbox at the end after
Daniel Wagner f13c72
+	 * all the current reference to the ndlp have been done.
Daniel Wagner f13c72
+	 */
Daniel Wagner f13c72
+	lpfc_nlp_put(ndlp);
Daniel Wagner f13c72
+}
Daniel Wagner f13c72
+
Daniel Wagner f13c72
 static void
Daniel Wagner f13c72
 lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
Daniel Wagner f13c72
 {
Daniel Wagner f13c72
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
Daniel Wagner f13c72
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
Daniel Wagner f13c72
@@ -785,6 +785,15 @@ lpfc_rcv_logo(struct lpfc_vport *vport,
Daniel Wagner f13c72
 	else
Daniel Wagner f13c72
 		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
Daniel Wagner f13c72
 
Daniel Wagner f13c72
+	/* This clause allows the initiator to ACC the LOGO back to the
Daniel Wagner f13c72
+	 * Fabric Domain Controller.  It does deliberately skip all other
Daniel Wagner f13c72
+	 * steps because some fabrics send RDP requests after logging out
Daniel Wagner f13c72
+	 * from the initiator.
Daniel Wagner f13c72
+	 */
Daniel Wagner f13c72
+	if (ndlp->nlp_type & NLP_FABRIC &&
Daniel Wagner f13c72
+	    ((ndlp->nlp_DID & WELL_KNOWN_DID_MASK) != WELL_KNOWN_DID_MASK))
Daniel Wagner f13c72
+		return 0;
Daniel Wagner f13c72
+
Daniel Wagner f13c72
 	/* Notify transport of connectivity loss to trigger cleanup. */
Daniel Wagner f13c72
 	if (phba->nvmet_support &&
Daniel Wagner f13c72
 	    ndlp->nlp_state == NLP_STE_UNMAPPED_NODE)
Daniel Wagner f13c72
@@ -1423,6 +1432,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_
Daniel Wagner f13c72
 		switch (ndlp->nlp_DID) {
Daniel Wagner f13c72
 		case NameServer_DID:
Daniel Wagner f13c72
 			mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
Daniel Wagner f13c72
+			/* Fabric Controller Node needs these parameters. */
Daniel Wagner f13c72
+			memcpy(&ndlp->fc_sparam, sp, sizeof(struct serv_parm));
Daniel Wagner f13c72
 			break;
Daniel Wagner f13c72
 		case FDMI_DID:
Daniel Wagner f13c72
 			mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
Daniel Wagner f13c72
--- a/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner f13c72
+++ b/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner f13c72
@@ -2755,7 +2755,6 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc
Daniel Wagner f13c72
 				} else {
Daniel Wagner f13c72
 					__lpfc_sli_rpi_release(vport, ndlp);
Daniel Wagner f13c72
 				}
Daniel Wagner f13c72
-
Daniel Wagner f13c72
 				lpfc_nlp_put(ndlp);
Daniel Wagner f13c72
 			}
Daniel Wagner f13c72
 		}