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