Daniel Wagner c09905
From: James Smart <jsmart2021@gmail.com>
Daniel Wagner c09905
Date: Fri, 14 May 2021 12:55:58 -0700
Daniel Wagner c09905
Subject: scsi: lpfc: Reregister FPIN types if ELS_RDF is received from fabric
Daniel Wagner c09905
 controller
Daniel Wagner c09905
Patch-mainline: Queued in subsystem maintainer repository
Daniel Wagner c09905
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
Daniel Wagner c09905
Git-commit: 8eced807077d198fc264629bd2592795d270c9f1
Daniel Wagner c09905
References: bsc#1186451
Daniel Wagner c09905
Daniel Wagner c09905
FC-LS-5 specifies that a received RDF implies a possible change to fabric
Daniel Wagner c09905
supported diagnostic functions. Endpoints are to re-perform the RDF
Daniel Wagner c09905
exchange with the fabric to enable possible new features or adapt to
Daniel Wagner c09905
changes in values.
Daniel Wagner c09905
Daniel Wagner c09905
This patch adds the logic to RDF receive to re-perform the RDF exchange
Daniel Wagner c09905
with the switch.
Daniel Wagner c09905
Daniel Wagner c09905
Link: https://lore.kernel.org/r/20210514195559.119853-11-jsmart2021@gmail.com
Daniel Wagner c09905
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner c09905
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner c09905
Signed-off-by: James Smart <jsmart2021@gmail.com>
Daniel Wagner c09905
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Daniel Wagner c09905
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner c09905
---
Daniel Wagner c09905
 drivers/scsi/lpfc/lpfc.h     |    1 
Daniel Wagner c09905
 drivers/scsi/lpfc/lpfc_els.c |   75 +++++++++++++++++++++++++++++++++++++++++++
Daniel Wagner c09905
 2 files changed, 76 insertions(+)
Daniel Wagner c09905
Daniel Wagner c09905
--- a/drivers/scsi/lpfc/lpfc.h
Daniel Wagner c09905
+++ b/drivers/scsi/lpfc/lpfc.h
Daniel Wagner c09905
@@ -266,6 +266,7 @@ struct lpfc_stats {
Daniel Wagner c09905
 	uint32_t elsRcvECHO;
Daniel Wagner c09905
 	uint32_t elsRcvLCB;
Daniel Wagner c09905
 	uint32_t elsRcvRDP;
Daniel Wagner c09905
+	uint32_t elsRcvRDF;
Daniel Wagner c09905
 	uint32_t elsXmitFLOGI;
Daniel Wagner c09905
 	uint32_t elsXmitFDISC;
Daniel Wagner c09905
 	uint32_t elsXmitPLOGI;
Daniel Wagner c09905
--- a/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner c09905
+++ b/drivers/scsi/lpfc/lpfc_els.c
Daniel Wagner c09905
@@ -3670,6 +3670,43 @@ lpfc_issue_els_rdf(struct lpfc_vport *vp
Daniel Wagner c09905
 	return 0;
Daniel Wagner c09905
 }
Daniel Wagner c09905
 
Daniel Wagner c09905
+ /**
Daniel Wagner c09905
+  * lpfc_els_rcv_rdf - Receive RDF ELS request from the fabric.
Daniel Wagner c09905
+  * @vport: pointer to a host virtual N_Port data structure.
Daniel Wagner c09905
+  * @cmdiocb: pointer to lpfc command iocb data structure.
Daniel Wagner c09905
+  * @ndlp: pointer to a node-list data structure.
Daniel Wagner c09905
+  *
Daniel Wagner c09905
+  * A received RDF implies a possible change to fabric supported diagnostic
Daniel Wagner c09905
+  * functions.  This routine sends LS_ACC and then has the Nx_Port issue a new
Daniel Wagner c09905
+  * RDF request to reregister for supported diagnostic functions.
Daniel Wagner c09905
+  *
Daniel Wagner c09905
+  * Return code
Daniel Wagner c09905
+  *   0 - Success
Daniel Wagner c09905
+  *   -EIO - Failed to process received RDF
Daniel Wagner c09905
+  **/
Daniel Wagner c09905
+static int
Daniel Wagner c09905
+lpfc_els_rcv_rdf(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
Daniel Wagner c09905
+		 struct lpfc_nodelist *ndlp)
Daniel Wagner c09905
+{
Daniel Wagner c09905
+	/* Send LS_ACC */
Daniel Wagner c09905
+	if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) {
Daniel Wagner c09905
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
Daniel Wagner c09905
+				 "1623 Failed to RDF_ACC from x%x for x%x\n",
Daniel Wagner c09905
+				 ndlp->nlp_DID, vport->fc_myDID);
Daniel Wagner c09905
+		return -EIO;
Daniel Wagner c09905
+	}
Daniel Wagner c09905
+
Daniel Wagner c09905
+	/* Issue new RDF for reregistering */
Daniel Wagner c09905
+	if (lpfc_issue_els_rdf(vport, 0)) {
Daniel Wagner c09905
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
Daniel Wagner c09905
+				 "2623 Failed to re register RDF for x%x\n",
Daniel Wagner c09905
+				 vport->fc_myDID);
Daniel Wagner c09905
+		return -EIO;
Daniel Wagner c09905
+	}
Daniel Wagner c09905
+
Daniel Wagner c09905
+	return 0;
Daniel Wagner c09905
+}
Daniel Wagner c09905
+
Daniel Wagner c09905
 /**
Daniel Wagner c09905
  * lpfc_cancel_retry_delay_tmo - Cancel the timer with delayed iocb-cmd retry
Daniel Wagner c09905
  * @vport: pointer to a host virtual N_Port data structure.
Daniel Wagner c09905
@@ -4803,6 +4840,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vpor
Daniel Wagner c09905
 	uint16_t cmdsize;
Daniel Wagner c09905
 	int rc;
Daniel Wagner c09905
 	ELS_PKT *els_pkt_ptr;
Daniel Wagner c09905
+	struct fc_els_rdf_resp *rdf_resp;
Daniel Wagner c09905
 
Daniel Wagner c09905
 	oldcmd = &oldiocb->iocb;
Daniel Wagner c09905
 
Daniel Wagner c09905
@@ -4914,6 +4952,29 @@ lpfc_els_rsp_acc(struct lpfc_vport *vpor
Daniel Wagner c09905
 			"Issue ACC PRLO:  did:x%x flg:x%x",
Daniel Wagner c09905
 			ndlp->nlp_DID, ndlp->nlp_flag, 0);
Daniel Wagner c09905
 		break;
Daniel Wagner c09905
+	case ELS_CMD_RDF:
Daniel Wagner c09905
+		cmdsize = sizeof(*rdf_resp);
Daniel Wagner c09905
+		elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
Daniel Wagner c09905
+					     ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
Daniel Wagner c09905
+		if (!elsiocb)
Daniel Wagner c09905
+			return 1;
Daniel Wagner c09905
+
Daniel Wagner c09905
+		icmd = &elsiocb->iocb;
Daniel Wagner c09905
+		icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */
Daniel Wagner c09905
+		icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
Daniel Wagner c09905
+		pcmd = (((struct lpfc_dmabuf *)elsiocb->context2)->virt);
Daniel Wagner c09905
+		rdf_resp = (struct fc_els_rdf_resp *)pcmd;
Daniel Wagner c09905
+		memset(rdf_resp, 0, sizeof(*rdf_resp));
Daniel Wagner c09905
+		rdf_resp->acc_hdr.la_cmd = ELS_LS_ACC;
Daniel Wagner c09905
+
Daniel Wagner c09905
+		/* FC-LS-5 specifies desc_list_len shall be set to 12 */
Daniel Wagner c09905
+		rdf_resp->desc_list_len = cpu_to_be32(12);
Daniel Wagner c09905
+
Daniel Wagner c09905
+		/* FC-LS-5 specifies LS REQ Information descriptor */
Daniel Wagner c09905
+		rdf_resp->lsri.desc_tag = cpu_to_be32(1);
Daniel Wagner c09905
+		rdf_resp->lsri.desc_len = cpu_to_be32(sizeof(u32));
Daniel Wagner c09905
+		rdf_resp->lsri.rqst_w0.cmd = ELS_RDF;
Daniel Wagner c09905
+		break;
Daniel Wagner c09905
 	default:
Daniel Wagner c09905
 		return 1;
Daniel Wagner c09905
 	}
Daniel Wagner c09905
@@ -9027,6 +9088,20 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p
Daniel Wagner c09905
 
Daniel Wagner c09905
 		/* There are no replies, so no rjt codes */
Daniel Wagner c09905
 		break;
Daniel Wagner c09905
+	case ELS_CMD_RDF:
Daniel Wagner c09905
+		phba->fc_stat.elsRcvRDF++;
Daniel Wagner c09905
+		/* Accept RDF only from fabric controller */
Daniel Wagner c09905
+		if (did != Fabric_Cntl_DID) {
Daniel Wagner c09905
+			lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS,
Daniel Wagner c09905
+					 "1115 Received RDF from invalid DID "
Daniel Wagner c09905
+					 "x%x\n", did);
Daniel Wagner c09905
+			rjt_err = LSRJT_PROTOCOL_ERR;
Daniel Wagner c09905
+			rjt_exp = LSEXP_NOTHING_MORE;
Daniel Wagner c09905
+			goto lsrjt;
Daniel Wagner c09905
+		}
Daniel Wagner c09905
+
Daniel Wagner c09905
+		lpfc_els_rcv_rdf(vport, elsiocb, ndlp);
Daniel Wagner c09905
+		break;
Daniel Wagner c09905
 	default:
Daniel Wagner c09905
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
Daniel Wagner c09905
 			"RCV ELS cmd:     cmd:x%x did:x%x/ste:x%x",