Hannes Reinecke 10fb0a
From: James Smart <jsmart2021@gmail.com>
Hannes Reinecke 10fb0a
Date: Tue, 31 Mar 2020 09:50:01 -0700
Hannes Reinecke 10fb0a
Subject: [PATCH] nvme-fcloop: add target to host LS request support
Hannes Reinecke 10fb0a
Git-commit: 6cefacbb8f87287de7450d9d0d6c764b809e576b
Hannes Reinecke 10fb0a
Git-repo: git://git.infradead.org/nvme.git
Hannes Reinecke 10fb0a
Patch-mainline: Queued in subsystem maintainer repository
Hannes Reinecke 10fb0a
References: bsc#1169045
Hannes Reinecke 10fb0a
Hannes Reinecke 10fb0a
Add support for performing LS requests from target to host.
Hannes Reinecke 10fb0a
Include sending request from targetport, reception into host,
Hannes Reinecke 10fb0a
host sending ls rsp.
Hannes Reinecke 10fb0a
Hannes Reinecke 10fb0a
Signed-off-by: James Smart <jsmart2021@gmail.com>
Hannes Reinecke 10fb0a
Reviewed-by: Hannes Reinecke <hare@suse.de>
Hannes Reinecke 10fb0a
Signed-off-by: Christoph Hellwig <hch@lst.de>
Hannes Reinecke 10fb0a
Acked-by: Hannes Reinecke <hare@suse.com>
Hannes Reinecke 10fb0a
---
Hannes Reinecke 10fb0a
 drivers/nvme/target/fcloop.c | 130 +++++++++++++++++++++++++++++++++++++++----
Hannes Reinecke 10fb0a
 1 file changed, 118 insertions(+), 12 deletions(-)
Hannes Reinecke 10fb0a
Hannes Reinecke 10fb0a
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
Hannes Reinecke 10fb0a
index fac7dbe572db..2ff1d1334a03 100644
Hannes Reinecke 10fb0a
--- a/drivers/nvme/target/fcloop.c
Hannes Reinecke 10fb0a
+++ b/drivers/nvme/target/fcloop.c
Hannes Reinecke 10fb0a
@@ -208,10 +208,13 @@ struct fcloop_rport {
Hannes Reinecke 10fb0a
 };
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
 struct fcloop_tport {
Hannes Reinecke 10fb0a
-	struct nvmet_fc_target_port *targetport;
Hannes Reinecke 10fb0a
-	struct nvme_fc_remote_port *remoteport;
Hannes Reinecke 10fb0a
-	struct fcloop_nport *nport;
Hannes Reinecke 10fb0a
-	struct fcloop_lport *lport;
Hannes Reinecke 10fb0a
+	struct nvmet_fc_target_port	*targetport;
Hannes Reinecke 10fb0a
+	struct nvme_fc_remote_port	*remoteport;
Hannes Reinecke 10fb0a
+	struct fcloop_nport		*nport;
Hannes Reinecke 10fb0a
+	struct fcloop_lport		*lport;
Hannes Reinecke 10fb0a
+	spinlock_t			lock;
Hannes Reinecke 10fb0a
+	struct list_head		ls_list;
Hannes Reinecke 10fb0a
+	struct work_struct		ls_work;
Hannes Reinecke 10fb0a
 };
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
 struct fcloop_nport {
Hannes Reinecke 10fb0a
@@ -226,11 +229,6 @@ struct fcloop_nport {
Hannes Reinecke 10fb0a
 	u32 port_id;
Hannes Reinecke 10fb0a
 };
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
-enum {
Hannes Reinecke 10fb0a
-	H2T	= 0,
Hannes Reinecke 10fb0a
-	T2H	= 1,
Hannes Reinecke 10fb0a
-};
Hannes Reinecke 10fb0a
-
Hannes Reinecke 10fb0a
 struct fcloop_lsreq {
Hannes Reinecke 10fb0a
 	struct nvmefc_ls_req		*lsreq;
Hannes Reinecke 10fb0a
 	struct nvmefc_ls_rsp		ls_rsp;
Hannes Reinecke 10fb0a
@@ -337,7 +335,6 @@ fcloop_h2t_ls_req(struct nvme_fc_local_port *localport,
Hannes Reinecke 10fb0a
 	struct fcloop_rport *rport = remoteport->private;
Hannes Reinecke 10fb0a
 	int ret = 0;
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
-	tls_req->lsdir = H2T;
Hannes Reinecke 10fb0a
 	tls_req->lsreq = lsreq;
Hannes Reinecke 10fb0a
 	INIT_LIST_HEAD(&tls_req->ls_list);
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
@@ -351,8 +348,9 @@ fcloop_h2t_ls_req(struct nvme_fc_local_port *localport,
Hannes Reinecke 10fb0a
 	}
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
 	tls_req->status = 0;
Hannes Reinecke 10fb0a
-	ret = nvmet_fc_rcv_ls_req(rport->targetport, NULL, &tls_req->ls_rsp,
Hannes Reinecke 10fb0a
-				 lsreq->rqstaddr, lsreq->rqstlen);
Hannes Reinecke 10fb0a
+	ret = nvmet_fc_rcv_ls_req(rport->targetport, rport,
Hannes Reinecke 10fb0a
+				  &tls_req->ls_rsp,
Hannes Reinecke 10fb0a
+				  lsreq->rqstaddr, lsreq->rqstlen);
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
 	return ret;
Hannes Reinecke 10fb0a
 }
Hannes Reinecke 10fb0a
@@ -384,6 +382,99 @@ fcloop_h2t_xmt_ls_rsp(struct nvmet_fc_target_port *targetport,
Hannes Reinecke 10fb0a
 	return 0;
Hannes Reinecke 10fb0a
 }
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
+static void
Hannes Reinecke 10fb0a
+fcloop_tport_lsrqst_work(struct work_struct *work)
Hannes Reinecke 10fb0a
+{
Hannes Reinecke 10fb0a
+	struct fcloop_tport *tport =
Hannes Reinecke 10fb0a
+		container_of(work, struct fcloop_tport, ls_work);
Hannes Reinecke 10fb0a
+	struct fcloop_lsreq *tls_req;
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	spin_lock(&tport->lock);
Hannes Reinecke 10fb0a
+	for (;;) {
Hannes Reinecke 10fb0a
+		tls_req = list_first_entry_or_null(&tport->ls_list,
Hannes Reinecke 10fb0a
+				struct fcloop_lsreq, ls_list);
Hannes Reinecke 10fb0a
+		if (!tls_req)
Hannes Reinecke 10fb0a
+			break;
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+		list_del(&tls_req->ls_list);
Hannes Reinecke 10fb0a
+		spin_unlock(&tport->lock);
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+		tls_req->lsreq->done(tls_req->lsreq, tls_req->status);
Hannes Reinecke 10fb0a
+		/*
Hannes Reinecke 10fb0a
+		 * callee may free memory containing tls_req.
Hannes Reinecke 10fb0a
+		 * do not reference lsreq after this.
Hannes Reinecke 10fb0a
+		 */
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+		spin_lock(&tport->lock);
Hannes Reinecke 10fb0a
+	}
Hannes Reinecke 10fb0a
+	spin_unlock(&tport->lock);
Hannes Reinecke 10fb0a
+}
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+static int
Hannes Reinecke 10fb0a
+fcloop_t2h_ls_req(struct nvmet_fc_target_port *targetport, void *hosthandle,
Hannes Reinecke 10fb0a
+			struct nvmefc_ls_req *lsreq)
Hannes Reinecke 10fb0a
+{
Hannes Reinecke 10fb0a
+	struct fcloop_lsreq *tls_req = lsreq->private;
Hannes Reinecke 10fb0a
+	struct fcloop_tport *tport = targetport->private;
Hannes Reinecke 10fb0a
+	int ret = 0;
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	/*
Hannes Reinecke 10fb0a
+	 * hosthandle should be the dst.rport value.
Hannes Reinecke 10fb0a
+	 * hosthandle ignored as fcloop currently is
Hannes Reinecke 10fb0a
+	 * 1:1 tgtport vs remoteport
Hannes Reinecke 10fb0a
+	 */
Hannes Reinecke 10fb0a
+	tls_req->lsreq = lsreq;
Hannes Reinecke 10fb0a
+	INIT_LIST_HEAD(&tls_req->ls_list);
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	if (!tport->remoteport) {
Hannes Reinecke 10fb0a
+		tls_req->status = -ECONNREFUSED;
Hannes Reinecke 10fb0a
+		spin_lock(&tport->lock);
Hannes Reinecke 10fb0a
+		list_add_tail(&tport->ls_list, &tls_req->ls_list);
Hannes Reinecke 10fb0a
+		spin_unlock(&tport->lock);
Hannes Reinecke 10fb0a
+		schedule_work(&tport->ls_work);
Hannes Reinecke 10fb0a
+		return ret;
Hannes Reinecke 10fb0a
+	}
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	tls_req->status = 0;
Hannes Reinecke 10fb0a
+	ret = nvme_fc_rcv_ls_req(tport->remoteport, &tls_req->ls_rsp,
Hannes Reinecke 10fb0a
+				 lsreq->rqstaddr, lsreq->rqstlen);
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	return ret;
Hannes Reinecke 10fb0a
+}
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+static int
Hannes Reinecke 10fb0a
+fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport,
Hannes Reinecke 10fb0a
+			struct nvme_fc_remote_port *remoteport,
Hannes Reinecke 10fb0a
+			struct nvmefc_ls_rsp *lsrsp)
Hannes Reinecke 10fb0a
+{
Hannes Reinecke 10fb0a
+	struct fcloop_lsreq *tls_req = ls_rsp_to_lsreq(lsrsp);
Hannes Reinecke 10fb0a
+	struct nvmefc_ls_req *lsreq = tls_req->lsreq;
Hannes Reinecke 10fb0a
+	struct fcloop_rport *rport = remoteport->private;
Hannes Reinecke 10fb0a
+	struct nvmet_fc_target_port *targetport = rport->targetport;
Hannes Reinecke 10fb0a
+	struct fcloop_tport *tport;
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	memcpy(lsreq->rspaddr, lsrsp->rspbuf,
Hannes Reinecke 10fb0a
+		((lsreq->rsplen < lsrsp->rsplen) ?
Hannes Reinecke 10fb0a
+				lsreq->rsplen : lsrsp->rsplen));
Hannes Reinecke 10fb0a
+	lsrsp->done(lsrsp);
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	if (targetport) {
Hannes Reinecke 10fb0a
+		tport = targetport->private;
Hannes Reinecke 10fb0a
+		spin_lock(&tport->lock);
Hannes Reinecke 10fb0a
+		list_add_tail(&tport->ls_list, &tls_req->ls_list);
Hannes Reinecke 10fb0a
+		spin_unlock(&tport->lock);
Hannes Reinecke 10fb0a
+		schedule_work(&tport->ls_work);
Hannes Reinecke 10fb0a
+	}
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+	return 0;
Hannes Reinecke 10fb0a
+}
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
+static void
Hannes Reinecke 10fb0a
+fcloop_t2h_host_release(void *hosthandle)
Hannes Reinecke 10fb0a
+{
Hannes Reinecke 10fb0a
+	/* host handle ignored for now */
Hannes Reinecke 10fb0a
+}
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
 /*
Hannes Reinecke 10fb0a
  * Simulate reception of RSCN and converting it to a initiator transport
Hannes Reinecke 10fb0a
  * call to rescan a remote port.
Hannes Reinecke 10fb0a
@@ -775,6 +866,12 @@ fcloop_h2t_ls_abort(struct nvme_fc_local_port *localport,
Hannes Reinecke 10fb0a
 {
Hannes Reinecke 10fb0a
 }
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
+static void
Hannes Reinecke 10fb0a
+fcloop_t2h_ls_abort(struct nvmet_fc_target_port *targetport,
Hannes Reinecke 10fb0a
+			void *hosthandle, struct nvmefc_ls_req *lsreq)
Hannes Reinecke 10fb0a
+{
Hannes Reinecke 10fb0a
+}
Hannes Reinecke 10fb0a
+
Hannes Reinecke 10fb0a
 static void
Hannes Reinecke 10fb0a
 fcloop_fcp_abort(struct nvme_fc_local_port *localport,
Hannes Reinecke 10fb0a
 			struct nvme_fc_remote_port *remoteport,
Hannes Reinecke 10fb0a
@@ -874,6 +971,7 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport)
Hannes Reinecke 10fb0a
 {
Hannes Reinecke 10fb0a
 	struct fcloop_tport *tport = targetport->private;
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
+	flush_work(&tport->ls_work);
Hannes Reinecke 10fb0a
 	fcloop_nport_put(tport->nport);
Hannes Reinecke 10fb0a
 }
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
@@ -890,6 +988,7 @@ static struct nvme_fc_port_template fctemplate = {
Hannes Reinecke 10fb0a
 	.fcp_io			= fcloop_fcp_req,
Hannes Reinecke 10fb0a
 	.ls_abort		= fcloop_h2t_ls_abort,
Hannes Reinecke 10fb0a
 	.fcp_abort		= fcloop_fcp_abort,
Hannes Reinecke 10fb0a
+	.xmt_ls_rsp		= fcloop_t2h_xmt_ls_rsp,
Hannes Reinecke 10fb0a
 	.max_hw_queues		= FCLOOP_HW_QUEUES,
Hannes Reinecke 10fb0a
 	.max_sgl_segments	= FCLOOP_SGL_SEGS,
Hannes Reinecke 10fb0a
 	.max_dif_sgl_segments	= FCLOOP_SGL_SEGS,
Hannes Reinecke 10fb0a
@@ -908,6 +1007,9 @@ static struct nvmet_fc_target_template tgttemplate = {
Hannes Reinecke 10fb0a
 	.fcp_abort		= fcloop_tgt_fcp_abort,
Hannes Reinecke 10fb0a
 	.fcp_req_release	= fcloop_fcp_req_release,
Hannes Reinecke 10fb0a
 	.discovery_event	= fcloop_tgt_discovery_evt,
Hannes Reinecke 10fb0a
+	.ls_req			= fcloop_t2h_ls_req,
Hannes Reinecke 10fb0a
+	.ls_abort		= fcloop_t2h_ls_abort,
Hannes Reinecke 10fb0a
+	.host_release		= fcloop_t2h_host_release,
Hannes Reinecke 10fb0a
 	.max_hw_queues		= FCLOOP_HW_QUEUES,
Hannes Reinecke 10fb0a
 	.max_sgl_segments	= FCLOOP_SGL_SEGS,
Hannes Reinecke 10fb0a
 	.max_dif_sgl_segments	= FCLOOP_SGL_SEGS,
Hannes Reinecke 10fb0a
@@ -916,6 +1018,7 @@ static struct nvmet_fc_target_template tgttemplate = {
Hannes Reinecke 10fb0a
 	.target_features	= 0,
Hannes Reinecke 10fb0a
 	/* sizes of additional private data for data structures */
Hannes Reinecke 10fb0a
 	.target_priv_sz		= sizeof(struct fcloop_tport),
Hannes Reinecke 10fb0a
+	.lsrqst_priv_sz		= sizeof(struct fcloop_lsreq),
Hannes Reinecke 10fb0a
 };
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
 static ssize_t
Hannes Reinecke 10fb0a
@@ -1265,6 +1368,9 @@ fcloop_create_target_port(struct device *dev, struct device_attribute *attr,
Hannes Reinecke 10fb0a
 	tport->nport = nport;
Hannes Reinecke 10fb0a
 	tport->lport = nport->lport;
Hannes Reinecke 10fb0a
 	nport->tport = tport;
Hannes Reinecke 10fb0a
+	spin_lock_init(&tport->lock);
Hannes Reinecke 10fb0a
+	INIT_WORK(&tport->ls_work, fcloop_tport_lsrqst_work);
Hannes Reinecke 10fb0a
+	INIT_LIST_HEAD(&tport->ls_list);
Hannes Reinecke 10fb0a
 
Hannes Reinecke 10fb0a
 	return count;
Hannes Reinecke 10fb0a
 }
Hannes Reinecke 10fb0a
-- 
Hannes Reinecke 10fb0a
2.16.4
Hannes Reinecke 10fb0a