All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/40] iscsi lock and refcount fix ups
@ 2021-04-03 23:22 Mike Christie
  2021-04-03 23:22 ` [PATCH 01/40] scsi: iscsi: fix shost->max_id use Mike Christie
                   ` (40 more replies)
  0 siblings, 41 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:22 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb

The following patches apply over Linus's tree or Martin's staging branch.
They fix up the locking and refcount handling in the iscsi code so for
software iscsi we longer need a lock when going from queuecommand to the
xmit thread and no longer need a common iscsi level lock between the xmit
thread and completion paths.

For simple throughput workloads like

fio --filename=/dev/sdb --direct=1 --rw=randwrite --bs=256k \
--ioengine=libaio --iodepth=128 --numjobs=1 --time_based \
--group_reporting --name=throughput --runtime=120

I'm able to get throughput from 24 Gb/s to 28 where I then hit a
bottleneck on the target side.

IOPs might increase by around 10% in some cases with:

fio --filename=/dev/sdb --direct=1 --rw=randwrite --bs=4k \
--ioengine=libaio --iodepth=128 --numjobs=1 --time_based \
--group_reporting --name=throughput --runtime=120

I'm still debugging some target side issues.

A bigger advantage I'm seeing with the patches is that for setups where
you have software iscsi sharing CPUs with other subsystems like vhost
IOPs can increase by up to 20%.

Notes:
- I've tested iscsi_tcp, ib_iser, be2iscsi and qedi. I don't have cxgbi
or bnx2i hardware, but cxbgi changes were API only.

- Lee, the first 2 patches are new bug fixes. The first half are then
similar to what you saw before. I was not sure how far through them you
were. The second half was the part that removed the back lock and frwd
lock from iscsi_queuecommand are new.





^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 01/40] scsi: iscsi: fix shost->max_id use
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
@ 2021-04-03 23:22 ` Mike Christie
  2021-04-05 16:00   ` Lee Duncan
  2021-04-03 23:22 ` [PATCH 02/40] scsi: libiscsi: fix write starvation Mike Christie
                   ` (39 subsequent siblings)
  40 siblings, 1 reply; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:22 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The iscsi offload drivers are setting the shost->max_id to the max number
of sessions they support. The problem is that max_id is not the max number
of targets but the highest identifier the targets can have. To use it to
limit the number of targets we need to set it to max sessions - 1, or we
can end up with a session we might not have preallocated resources for.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c  | 4 ++--
 drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +-
 drivers/scsi/cxgbi/libcxgbi.c    | 4 ++--
 drivers/scsi/qedi/qedi_main.c    | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 90fcddb76f46..56bd4441a789 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -416,7 +416,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
 			"beiscsi_hba_alloc - iscsi_host_alloc failed\n");
 		return NULL;
 	}
-	shost->max_id = BE2_MAX_SESSIONS;
+	shost->max_id = BE2_MAX_SESSIONS - 1;
 	shost->max_channel = 0;
 	shost->max_cmd_len = BEISCSI_MAX_CMD_LEN;
 	shost->max_lun = BEISCSI_NUM_MAX_LUN;
@@ -5318,7 +5318,7 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba)
 	/* Re-enable UER. If different TPE occurs then it is recoverable. */
 	beiscsi_set_uer_feature(phba);
 
-	phba->shost->max_id = phba->params.cxns_per_ctrl;
+	phba->shost->max_id = phba->params.cxns_per_ctrl - 1;
 	phba->shost->can_queue = phba->params.ios_per_ctrl;
 	ret = beiscsi_init_port(phba);
 	if (ret < 0) {
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 1e6d8f62ea3c..37f5b719050e 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -791,7 +791,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
 		return NULL;
 	shost->dma_boundary = cnic->pcidev->dma_mask;
 	shost->transportt = bnx2i_scsi_xport_template;
-	shost->max_id = ISCSI_MAX_CONNS_PER_HBA;
+	shost->max_id = ISCSI_MAX_CONNS_PER_HBA - 1;
 	shost->max_channel = 0;
 	shost->max_lun = 512;
 	shost->max_cmd_len = 16;
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index f078b3c4e083..ecb134b4699f 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -337,7 +337,7 @@ void cxgbi_hbas_remove(struct cxgbi_device *cdev)
 EXPORT_SYMBOL_GPL(cxgbi_hbas_remove);
 
 int cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun,
-		unsigned int max_id, struct scsi_host_template *sht,
+		unsigned int max_conns, struct scsi_host_template *sht,
 		struct scsi_transport_template *stt)
 {
 	struct cxgbi_hba *chba;
@@ -357,7 +357,7 @@ int cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun,
 
 		shost->transportt = stt;
 		shost->max_lun = max_lun;
-		shost->max_id = max_id;
+		shost->max_id = max_conns - 1;
 		shost->max_channel = 0;
 		shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
 
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 47ad64b06623..0aa0061dad40 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -642,7 +642,7 @@ static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev)
 		goto exit_setup_shost;
 	}
 
-	shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA;
+	shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA - 1;
 	shost->max_channel = 0;
 	shost->max_lun = ~0;
 	shost->max_cmd_len = 16;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 02/40] scsi: libiscsi: fix write starvation
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
  2021-04-03 23:22 ` [PATCH 01/40] scsi: iscsi: fix shost->max_id use Mike Christie
@ 2021-04-03 23:22 ` Mike Christie
  2021-04-03 23:22 ` [PATCH 03/40] scsi: iscsi: remove unneeded task state check Mike Christie
                   ` (38 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:22 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

We currently handle R2Ts after handling new cmds. This can lead to
starving existing WRITEs waiting for R2T handling, if apps are sending
new cmds so quickly cmdqueue is never empty.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 53 ++++++++++++++++++++++++++---------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 04633e5157e9..643edc4eb6fe 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1525,7 +1525,7 @@ EXPORT_SYMBOL_GPL(iscsi_requeue_task);
 static int iscsi_data_xmit(struct iscsi_conn *conn)
 {
 	struct iscsi_task *task;
-	int rc = 0;
+	int rc = 0, cnt;
 
 	spin_lock_bh(&conn->session->frwd_lock);
 	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
@@ -1562,7 +1562,30 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
 			goto done;
 	}
 
+check_requeue:
+	while (!list_empty(&conn->requeue)) {
+		/*
+		 * we always do fastlogout - conn stop code will clean up.
+		 */
+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
+			break;
+
+		task = list_entry(conn->requeue.next, struct iscsi_task,
+				  running);
+
+		if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
+			break;
+
+		list_del_init(&task->running);
+		rc = iscsi_xmit_task(conn, task, true);
+		if (rc)
+			goto done;
+		if (!list_empty(&conn->mgmtqueue))
+			goto check_mgmt;
+	}
+
 	/* process pending command queue */
+	cnt = 0;
 	while (!list_empty(&conn->cmdqueue)) {
 		task = list_entry(conn->cmdqueue.next, struct iscsi_task,
 				  running);
@@ -1589,28 +1612,20 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
 		 */
 		if (!list_empty(&conn->mgmtqueue))
 			goto check_mgmt;
-	}
-
-	while (!list_empty(&conn->requeue)) {
 		/*
-		 * we always do fastlogout - conn stop code will clean up.
+		 * Avoid starving the requeue list if new cmds keep coming in.
+		 * Incase the app tried to batch cmds to us, we allow up to
+		 * queueing limit.
 		 */
-		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
-			break;
+		cnt++;
+		if (cnt == conn->session->host->cmd_per_lun) {
+			cnt = 0;
 
-		task = list_entry(conn->requeue.next, struct iscsi_task,
-				  running);
-
-		if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
-			break;
-
-		list_del_init(&task->running);
-		rc = iscsi_xmit_task(conn, task, true);
-		if (rc)
-			goto done;
-		if (!list_empty(&conn->mgmtqueue))
-			goto check_mgmt;
+			if (!list_empty(&conn->requeue))
+				goto check_requeue;
+		}
 	}
+
 	spin_unlock_bh(&conn->session->frwd_lock);
 	return -ENODATA;
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 03/40] scsi: iscsi: remove unneeded task state check
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
  2021-04-03 23:22 ` [PATCH 01/40] scsi: iscsi: fix shost->max_id use Mike Christie
  2021-04-03 23:22 ` [PATCH 02/40] scsi: libiscsi: fix write starvation Mike Christie
@ 2021-04-03 23:22 ` Mike Christie
  2021-04-05 16:03   ` Lee Duncan
  2021-04-03 23:22 ` [PATCH 04/40] scsi: libiscsi: drop frwd lock for session state Mike Christie
                   ` (37 subsequent siblings)
  40 siblings, 1 reply; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:22 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The patch:

commit 5923d64b7ab6 ("scsi: libiscsi: Drop taskqueuelock")

added an extra task->state because for

commit 6f8830f5bbab ("scsi: libiscsi: add lock around task lists to fix
list corruption regression")

we didn't know why we ended up with cmds on the list and thought it
might have been a bad target sending a response while we were still
sending the cmd. It turns out the bug was just a race in libiscsi/
libiscsi_tcp where

1. iscsi_tcp_r2t_rsp queues a r2t to tcp_task->r2tqueue.
2. iscsi_tcp_task_xmit runs iscsi_tcp_get_curr_r2t and sees we have a r2t.
It dequeues it and iscsi_tcp_task_xmit starts to process it.
3. iscsi_tcp_r2t_rsp runs iscsi_requeue_task and puts the task on the
requeue list.
4. iscsi_tcp_task_xmit sends the data for r2t. This is the final chunk of
data, so the cmd is done.
5. target sends the response.
6. On a different CPU from #3, iscsi_complete_task processes the response.
Since there was no common lock for the list, the lists/tasks pointers are
not fully in sync, so could end up with list corruption.

Since it was just a race on our side, this patch removes the extra check.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 643edc4eb6fe..94cb9410230a 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -562,16 +562,19 @@ static bool cleanup_queued_task(struct iscsi_task *task)
 	struct iscsi_conn *conn = task->conn;
 	bool early_complete = false;
 
-	/* Bad target might have completed task while it was still running */
+	/*
+	 * We might have raced where we handled a R2T early and got a response
+	 * but have not yet taken the task off the requeue list, then a TMF or
+	 * recovery happened and so we can still see it here.
+	 */
 	if (task->state == ISCSI_TASK_COMPLETED)
 		early_complete = true;
 
 	if (!list_empty(&task->running)) {
 		list_del_init(&task->running);
 		/*
-		 * If it's on a list but still running, this could be from
-		 * a bad target sending a rsp early, cleanup from a TMF, or
-		 * session recovery.
+		 * If it's on a list but still running this could be cleanup
+		 * from a TMF or session recovery.
 		 */
 		if (task->state == ISCSI_TASK_RUNNING ||
 		    task->state == ISCSI_TASK_COMPLETED)
@@ -1470,7 +1473,7 @@ static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
 	}
 	/* regular RX path uses back_lock */
 	spin_lock(&conn->session->back_lock);
-	if (rc && task->state == ISCSI_TASK_RUNNING) {
+	if (rc) {
 		/*
 		 * get an extra ref that is released next time we access it
 		 * as conn->task above.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 04/40] scsi: libiscsi: drop frwd lock for session state
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (2 preceding siblings ...)
  2021-04-03 23:22 ` [PATCH 03/40] scsi: iscsi: remove unneeded task state check Mike Christie
@ 2021-04-03 23:22 ` Mike Christie
  2021-04-03 23:22 ` [PATCH 05/40] scsi: iscsi: add task prealloc/free callouts Mike Christie
                   ` (36 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:22 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This drops the frwd lock for the session state checks in queuecommand.
Like with the transport class case, we only need it as a hint since when
the session is cleaned up we will block the session which flushes the
queues, and then we clean up all running IO. So the locking just prevents
cleaning up extra cmds. This patch is a prep patch and does not help perf.
This patch and the next ones are going to chip away the reasons we need
the frwd lock in the queuecommand code path until there are none left for
software iscsi.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c  |  3 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c |  3 +-
 drivers/scsi/libiscsi.c          | 86 +++++++++++++++++---------------
 drivers/scsi/qedi/qedi_iscsi.c   |  3 +-
 include/scsi/libiscsi.h          | 14 ++++--
 5 files changed, 62 insertions(+), 47 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 56bd4441a789..18d0591e4dbb 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -285,7 +285,8 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
 	session = cls_session->dd_data;
 
 	spin_lock_bh(&session->frwd_lock);
-	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) {
+	if (!session->leadconn ||
+	    READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN) {
 		spin_unlock_bh(&session->frwd_lock);
 		return FAILED;
 	}
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 37f5b719050e..48809fc8f095 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -2056,7 +2056,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
 	if (session) {
 		spin_lock_bh(&session->frwd_lock);
 		if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
-			if (session->state == ISCSI_STATE_LOGGING_OUT) {
+			if (READ_ONCE(session->state) ==
+			    ISCSI_STATE_LOGGING_OUT) {
 				if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
 					/* Logout sent, but no resp */
 					printk(KERN_ALERT "bnx2i (%s): WARNING"
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 94cb9410230a..7b83890aeb7a 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -633,7 +633,7 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
 	struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
 	uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
 
-	if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
+	if (READ_ONCE(session->state) == ISCSI_STATE_LOGGING_OUT)
 		return -ENOTCONN;
 
 	if (opcode != ISCSI_OP_LOGIN && opcode != ISCSI_OP_TEXT)
@@ -662,7 +662,7 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
 		return -EIO;
 
 	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
-		session->state = ISCSI_STATE_LOGGING_OUT;
+		WRITE_ONCE(session->state, ISCSI_STATE_LOGGING_OUT);
 
 	task->state = ISCSI_TASK_RUNNING;
 	ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x "
@@ -679,9 +679,10 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	struct iscsi_host *ihost = shost_priv(session->host);
 	uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
 	struct iscsi_task *task;
+	int sess_state = READ_ONCE(session->state);
 	itt_t itt;
 
-	if (session->state == ISCSI_STATE_TERMINATE)
+	if (sess_state == ISCSI_STATE_TERMINATE)
 		return NULL;
 
 	if (opcode == ISCSI_OP_LOGIN || opcode == ISCSI_OP_TEXT) {
@@ -704,7 +705,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
 		task = conn->login_task;
 	} else {
-		if (session->state != ISCSI_STATE_LOGGED_IN)
+		if (sess_state != ISCSI_STATE_LOGGED_IN)
 			return NULL;
 
 		if (data_size != 0) {
@@ -1368,7 +1369,7 @@ void iscsi_session_failure(struct iscsi_session *session,
 
 	spin_lock_bh(&session->frwd_lock);
 	conn = session->leadconn;
-	if (session->state == ISCSI_STATE_TERMINATE || !conn) {
+	if (READ_ONCE(session->state) == ISCSI_STATE_TERMINATE || !conn) {
 		spin_unlock_bh(&session->frwd_lock);
 		return;
 	}
@@ -1395,13 +1396,13 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
 	struct iscsi_session *session = conn->session;
 
 	spin_lock_bh(&session->frwd_lock);
-	if (session->state == ISCSI_STATE_FAILED) {
+	if (READ_ONCE(session->state) == ISCSI_STATE_FAILED) {
 		spin_unlock_bh(&session->frwd_lock);
 		return;
 	}
 
 	if (conn->stop_stage == 0)
-		session->state = ISCSI_STATE_FAILED;
+		WRITE_ONCE(session->state, ISCSI_STATE_FAILED);
 	spin_unlock_bh(&session->frwd_lock);
 
 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
@@ -1570,7 +1571,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
 		/*
 		 * we always do fastlogout - conn stop code will clean up.
 		 */
-		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
+		if (READ_ONCE(conn->session->state) == ISCSI_STATE_LOGGING_OUT)
 			break;
 
 		task = list_entry(conn->requeue.next, struct iscsi_task,
@@ -1593,7 +1594,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
 		task = list_entry(conn->cmdqueue.next, struct iscsi_task,
 				  running);
 		list_del_init(&task->running);
-		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+		if (READ_ONCE(conn->session->state) == ISCSI_STATE_LOGGING_OUT) {
 			fail_scsi_task(task, DID_IMM_RETRY);
 			continue;
 		}
@@ -1695,6 +1696,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	struct iscsi_session *session;
 	struct iscsi_conn *conn;
 	struct iscsi_task *task = NULL;
+	int sess_state;
 
 	sc->result = 0;
 	sc->SCp.ptr = NULL;
@@ -1703,7 +1705,6 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 
 	cls_session = starget_to_session(scsi_target(sc->device));
 	session = cls_session->dd_data;
-	spin_lock_bh(&session->frwd_lock);
 
 	reason = iscsi_session_chkready(cls_session);
 	if (reason) {
@@ -1711,14 +1712,15 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 		goto fault;
 	}
 
-	if (session->state != ISCSI_STATE_LOGGED_IN) {
+	sess_state = READ_ONCE(session->state);
+	if (sess_state != ISCSI_STATE_LOGGED_IN) {
 		/*
 		 * to handle the race between when we set the recovery state
 		 * and block the session we requeue here (commands could
 		 * be entering our queuecommand while a block is starting
 		 * up because the block code is not locked)
 		 */
-		switch (session->state) {
+		switch (sess_state) {
 		case ISCSI_STATE_FAILED:
 			/*
 			 * cmds should fail during shutdown, if the session
@@ -1753,26 +1755,31 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 		goto fault;
 	}
 
+	spin_lock_bh(&session->frwd_lock);
 	conn = session->leadconn;
 	if (!conn) {
+		spin_unlock_bh(&session->frwd_lock);
 		reason = FAILURE_SESSION_FREED;
 		sc->result = DID_NO_CONNECT << 16;
 		goto fault;
 	}
 
 	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
+		spin_unlock_bh(&session->frwd_lock);
 		reason = FAILURE_SESSION_IN_RECOVERY;
 		sc->result = DID_REQUEUE << 16;
 		goto fault;
 	}
 
 	if (iscsi_check_cmdsn_window_closed(conn)) {
+		spin_unlock_bh(&session->frwd_lock);
 		reason = FAILURE_WINDOW_CLOSED;
 		goto reject;
 	}
 
 	task = iscsi_alloc_task(conn, sc);
 	if (!task) {
+		spin_unlock_bh(&session->frwd_lock);
 		reason = FAILURE_OOM;
 		goto reject;
 	}
@@ -1803,21 +1810,23 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	return 0;
 
 prepd_reject:
+	spin_unlock_bh(&session->frwd_lock);
+
 	spin_lock_bh(&session->back_lock);
 	iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
 	spin_unlock_bh(&session->back_lock);
 reject:
-	spin_unlock_bh(&session->frwd_lock);
 	ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
 			  sc->cmnd[0], reason);
 	return SCSI_MLQUEUE_TARGET_BUSY;
 
 prepd_fault:
+	spin_unlock_bh(&session->frwd_lock);
+
 	spin_lock_bh(&session->back_lock);
 	iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
 	spin_unlock_bh(&session->back_lock);
 fault:
-	spin_unlock_bh(&session->frwd_lock);
 	ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
 			  sc->cmnd[0], reason);
 	scsi_set_resid(sc, scsi_bufflen(sc));
@@ -1885,8 +1894,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
 	 * given up on recovery
 	 */
 	wait_event_interruptible(conn->ehwait, age != session->age ||
-				 session->state != ISCSI_STATE_LOGGED_IN ||
-				 conn->tmf_state != TMF_QUEUED);
+			READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN ||
+			conn->tmf_state != TMF_QUEUED);
 	if (signal_pending(current))
 		flush_signals(current);
 	del_timer_sync(&conn->tmf_timer);
@@ -1895,7 +1904,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
 	spin_lock_bh(&session->frwd_lock);
 	/* if the session drops it will clean up the task */
 	if (age != session->age ||
-	    session->state != ISCSI_STATE_LOGGED_IN)
+	    READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN)
 		return -ENOTCONN;
 	return 0;
 }
@@ -2025,7 +2034,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 	__iscsi_get_task(task);
 	spin_unlock(&session->back_lock);
 
-	if (session->state != ISCSI_STATE_LOGGED_IN) {
+	if (READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN) {
 		/*
 		 * During shutdown, if session is prematurely disconnected,
 		 * recovery won't happen and there will be hung cmds. Not
@@ -2161,7 +2170,7 @@ static void iscsi_check_transport_timeouts(struct timer_list *t)
 	unsigned long recv_timeout, next_timeout = 0, last_recv;
 
 	spin_lock(&session->frwd_lock);
-	if (session->state != ISCSI_STATE_LOGGED_IN)
+	if (READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN)
 		goto done;
 
 	recv_timeout = conn->recv_timeout;
@@ -2242,7 +2251,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 	 * If we are not logged in or we have started a new session
 	 * then let the host reset code handle this
 	 */
-	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
+	if (!session->leadconn ||
+	    READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN ||
 	    sc->SCp.phase != session->age) {
 		spin_unlock_bh(&session->frwd_lock);
 		mutex_unlock(&session->eh_mutex);
@@ -2375,7 +2385,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
 	 * Just check if we are not logged in. We cannot check for
 	 * the phase because the reset could come from a ioctl.
 	 */
-	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
+	if (!session->leadconn ||
+	    READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN)
 		goto unlock;
 	conn = session->leadconn;
 
@@ -2434,8 +2445,8 @@ void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
 	struct iscsi_session *session = cls_session->dd_data;
 
 	spin_lock_bh(&session->frwd_lock);
-	if (session->state != ISCSI_STATE_LOGGED_IN) {
-		session->state = ISCSI_STATE_RECOVERY_FAILED;
+	if (READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN) {
+		WRITE_ONCE(session->state, ISCSI_STATE_RECOVERY_FAILED);
 		if (session->leadconn)
 			wake_up(&session->leadconn->ehwait);
 	}
@@ -2461,19 +2472,15 @@ int iscsi_eh_session_reset(struct scsi_cmnd *sc)
 	conn = session->leadconn;
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
-	if (session->state == ISCSI_STATE_TERMINATE) {
+	if (READ_ONCE(session->state) == ISCSI_STATE_TERMINATE) {
 failed:
 		ISCSI_DBG_EH(session,
 			     "failing session reset: Could not log back into "
 			     "%s [age %d]\n", session->targetname,
 			     session->age);
-		spin_unlock_bh(&session->frwd_lock);
 		mutex_unlock(&session->eh_mutex);
 		return FAILED;
 	}
-
-	spin_unlock_bh(&session->frwd_lock);
 	mutex_unlock(&session->eh_mutex);
 	/*
 	 * we drop the lock here but the leadconn cannot be destoyed while
@@ -2483,21 +2490,19 @@ int iscsi_eh_session_reset(struct scsi_cmnd *sc)
 
 	ISCSI_DBG_EH(session, "wait for relogin\n");
 	wait_event_interruptible(conn->ehwait,
-				 session->state == ISCSI_STATE_TERMINATE ||
-				 session->state == ISCSI_STATE_LOGGED_IN ||
-				 session->state == ISCSI_STATE_RECOVERY_FAILED);
+			READ_ONCE(session->state) == ISCSI_STATE_TERMINATE ||
+			READ_ONCE(session->state) == ISCSI_STATE_LOGGED_IN ||
+			READ_ONCE(session->state) == ISCSI_STATE_RECOVERY_FAILED);
 	if (signal_pending(current))
 		flush_signals(current);
 
 	mutex_lock(&session->eh_mutex);
-	spin_lock_bh(&session->frwd_lock);
-	if (session->state == ISCSI_STATE_LOGGED_IN) {
+	if (READ_ONCE(session->state) == ISCSI_STATE_LOGGED_IN) {
 		ISCSI_DBG_EH(session,
 			     "session reset succeeded for %s,%s\n",
 			     session->targetname, conn->persistent_address);
 	} else
 		goto failed;
-	spin_unlock_bh(&session->frwd_lock);
 	mutex_unlock(&session->eh_mutex);
 	return SUCCESS;
 }
@@ -2538,7 +2543,8 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
 	 * Just check if we are not logged in. We cannot check for
 	 * the phase because the reset could come from a ioctl.
 	 */
-	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
+	if (!session->leadconn ||
+	    READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN)
 		goto unlock;
 	conn = session->leadconn;
 
@@ -2892,7 +2898,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 	session = cls_session->dd_data;
 	session->cls_session = cls_session;
 	session->host = shost;
-	session->state = ISCSI_STATE_FREE;
+	WRITE_ONCE(session->state, ISCSI_STATE_FREE);
 	session->fast_abort = 1;
 	session->tgt_reset_timeout = 30;
 	session->lu_reset_timeout = 15;
@@ -3070,7 +3076,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 		/*
 		 * leading connection? then give up on recovery.
 		 */
-		session->state = ISCSI_STATE_TERMINATE;
+		WRITE_ONCE(session->state, ISCSI_STATE_TERMINATE);
 		wake_up(&conn->ehwait);
 	}
 	spin_unlock_bh(&session->frwd_lock);
@@ -3130,7 +3136,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
 
 	spin_lock_bh(&session->frwd_lock);
 	conn->c_stage = ISCSI_CONN_STARTED;
-	session->state = ISCSI_STATE_LOGGED_IN;
+	WRITE_ONCE(session->state, ISCSI_STATE_LOGGED_IN);
 	session->queued_cmdsn = session->cmdsn;
 
 	conn->last_recv = jiffies;
@@ -3216,9 +3222,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
 	 * the recovery state again
 	 */
 	if (flag == STOP_CONN_TERM)
-		session->state = ISCSI_STATE_TERMINATE;
+		WRITE_ONCE(session->state, ISCSI_STATE_TERMINATE);
 	else if (conn->stop_stage != STOP_CONN_RECOVER)
-		session->state = ISCSI_STATE_IN_RECOVERY;
+		WRITE_ONCE(session->state, ISCSI_STATE_IN_RECOVERY);
 
 	old_stop_stage = conn->stop_stage;
 	conn->stop_stage = flag;
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 08c05403cd72..0a85b347297c 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -1436,7 +1436,8 @@ void qedi_start_conn_recovery(struct qedi_ctx *qedi,
 		qedi_conn->abrt_conn = 1;
 		QEDI_ERR(&qedi->dbg_ctx,
 			 "Failing connection, state=0x%x, cid=0x%x\n",
-			 conn->session->state, qedi_conn->iscsi_conn_id);
+			 READ_ONCE(conn->session->state),
+			 qedi_conn->iscsi_conn_id);
 		iscsi_conn_failure(qedi_conn->cls_conn->dd_data,
 				   ISCSI_ERR_CONN_FAILED);
 	}
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 02f966e9358f..ddd4b9a809a1 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -328,15 +328,21 @@ struct iscsi_session {
 	 * can enclose the mutual exclusion zone protected by the backward lock
 	 * but not vice versa.
 	 */
-	spinlock_t		frwd_lock;	/* protects session state, *
-						 * cmdsn, queued_cmdsn     *
-						 * session resources:      *
+	spinlock_t		frwd_lock;	/* protects queued_cmdsn,  *
+						 * cmdsn, suspend_bit,     *
+						 * leadconn, _stage,       *
+						 * tmf_state and session   *
+						 * resources:              *
 						 * - cmdpool kfifo_out ,   *
 						 * - mgmtpool, queues	   */
 	spinlock_t		back_lock;	/* protects cmdsn_exp      *
 						 * cmdsn_max,              *
 						 * cmdpool kfifo_in        */
-	int			state;		/* session state           */
+	/*
+	 * frwd_lock must be held when transitioning states, but not needed
+	 * if just checking the state in the scsi-ml or iscsi callouts.
+	 */
+	int			state;
 	int			age;		/* counts session re-opens */
 
 	int			scsi_cmds_max; 	/* max scsi commands */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 05/40] scsi: iscsi: add task prealloc/free callouts
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (3 preceding siblings ...)
  2021-04-03 23:22 ` [PATCH 04/40] scsi: libiscsi: drop frwd lock for session state Mike Christie
@ 2021-04-03 23:22 ` Mike Christie
  2021-04-03 23:22 ` [PATCH 06/40] scsi: qedi: implement alloc_task_priv/free_task_priv Mike Christie
                   ` (35 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:22 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Some drivers need to allocate resources with functions like dma_alloc*
that can't be allocated with the iscsi_task struct. The next patches
have the iscsi drivers use the block/scsi mq cmd allocators for scsi
tasks and the drivers can use the init_cmd_priv callout to allocate
these extra resource for scsi tasks there. For mgmt tasks, drivers can
use the callouts added in this patch.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c             | 21 +++++++++++++++++++--
 include/scsi/scsi_transport_iscsi.h |  5 +++++
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 7b83890aeb7a..926d33b2c9c7 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2931,10 +2931,15 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 		task->itt = cmd_i;
 		task->state = ISCSI_TASK_FREE;
 		INIT_LIST_HEAD(&task->running);
+
+		if (iscsit->alloc_task_priv) {
+			if (iscsit->alloc_task_priv(session, task))
+				goto free_task_priv;
+		}
 	}
 
 	if (!try_module_get(iscsit->owner))
-		goto module_get_fail;
+		goto free_task_priv;
 
 	if (iscsi_add_session(cls_session, id))
 		goto cls_session_fail;
@@ -2943,7 +2948,12 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 
 cls_session_fail:
 	module_put(iscsit->owner);
-module_get_fail:
+free_task_priv:
+	for (cmd_i--; cmd_i >= 0; cmd_i--) {
+		if (iscsit->free_task_priv)
+			iscsit->free_task_priv(session, session->cmds[cmd_i]);
+	}
+
 	iscsi_pool_free(&session->cmdpool);
 cmdpool_alloc_fail:
 	iscsi_free_session(cls_session);
@@ -2962,6 +2972,13 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
 	struct iscsi_session *session = cls_session->dd_data;
 	struct module *owner = cls_session->transport->owner;
 	struct Scsi_Host *shost = session->host;
+	int cmd_i;
+
+	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
+		if (session->tt->free_task_priv)
+			session->tt->free_task_priv(session,
+						    session->cmds[cmd_i]);
+	}
 
 	iscsi_pool_free(&session->cmdpool);
 
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 8a26a2ffa952..cdd358e20a97 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -22,6 +22,7 @@ struct Scsi_Host;
 struct scsi_cmnd;
 struct iscsi_cls_conn;
 struct iscsi_conn;
+struct iscsi_session;
 struct iscsi_task;
 struct sockaddr;
 struct iscsi_iface;
@@ -106,6 +107,10 @@ struct iscsi_transport {
 	void (*get_stats) (struct iscsi_cls_conn *conn,
 			   struct iscsi_stats *stats);
 
+	int (*alloc_task_priv) (struct iscsi_session *session,
+				struct iscsi_task *task);
+	void (*free_task_priv) (struct iscsi_session *session,
+				struct iscsi_task *task);
 	int (*init_task) (struct iscsi_task *task);
 	int (*xmit_task) (struct iscsi_task *task);
 	void (*cleanup_task) (struct iscsi_task *task);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 06/40] scsi: qedi: implement alloc_task_priv/free_task_priv
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (4 preceding siblings ...)
  2021-04-03 23:22 ` [PATCH 05/40] scsi: iscsi: add task prealloc/free callouts Mike Christie
@ 2021-04-03 23:22 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 07/40] scsi: bnx2i: " Mike Christie
                   ` (34 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:22 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Have qedi use the alloc_task_priv/free_task_priv instead of rolling its
own loops.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_iscsi.c | 106 +++++++++++++--------------------
 1 file changed, 41 insertions(+), 65 deletions(-)

diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 0a85b347297c..54c1d0a2484c 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -160,32 +160,30 @@ static int qedi_conn_alloc_login_resources(struct qedi_ctx *qedi,
 	return -ENOMEM;
 }
 
-static void qedi_destroy_cmd_pool(struct qedi_ctx *qedi,
-				  struct iscsi_session *session)
+static void qedi_free_sget(struct qedi_ctx *qedi, struct qedi_cmd *cmd)
 {
-	int i;
+	if (!cmd->io_tbl.sge_tbl)
+		return;
 
-	for (i = 0; i < session->cmds_max; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct qedi_cmd *cmd = task->dd_data;
-
-		if (cmd->io_tbl.sge_tbl)
-			dma_free_coherent(&qedi->pdev->dev,
-					  QEDI_ISCSI_MAX_BDS_PER_CMD *
-					  sizeof(struct scsi_sge),
-					  cmd->io_tbl.sge_tbl,
-					  cmd->io_tbl.sge_tbl_dma);
-
-		if (cmd->sense_buffer)
-			dma_free_coherent(&qedi->pdev->dev,
-					  SCSI_SENSE_BUFFERSIZE,
-					  cmd->sense_buffer,
-					  cmd->sense_buffer_dma);
-	}
+	dma_free_coherent(&qedi->pdev->dev,
+			  QEDI_ISCSI_MAX_BDS_PER_CMD * sizeof(struct scsi_sge),
+			  cmd->io_tbl.sge_tbl, cmd->io_tbl.sge_tbl_dma);
 }
 
-static int qedi_alloc_sget(struct qedi_ctx *qedi, struct iscsi_session *session,
-			   struct qedi_cmd *cmd)
+static void qedi_free_task_priv(struct iscsi_session *session,
+				struct iscsi_task *task)
+{
+	struct qedi_ctx *qedi = iscsi_host_priv(session->host);
+	struct qedi_cmd *cmd = task->dd_data;
+
+	qedi_free_sget(qedi, cmd);
+
+	if (cmd->sense_buffer)
+		dma_free_coherent(&qedi->pdev->dev, SCSI_SENSE_BUFFERSIZE,
+				  cmd->sense_buffer, cmd->sense_buffer_dma);
+}
+
+static int qedi_alloc_sget(struct qedi_ctx *qedi, struct qedi_cmd *cmd)
 {
 	struct qedi_io_bdt *io = &cmd->io_tbl;
 	struct scsi_sge *sge;
@@ -195,8 +193,8 @@ static int qedi_alloc_sget(struct qedi_ctx *qedi, struct iscsi_session *session,
 					 sizeof(*sge),
 					 &io->sge_tbl_dma, GFP_KERNEL);
 	if (!io->sge_tbl) {
-		iscsi_session_printk(KERN_ERR, session,
-				     "Could not allocate BD table.\n");
+		shost_printk(KERN_ERR, qedi->shost,
+			    "Could not allocate BD table.\n");
 		return -ENOMEM;
 	}
 
@@ -204,33 +202,29 @@ static int qedi_alloc_sget(struct qedi_ctx *qedi, struct iscsi_session *session,
 	return 0;
 }
 
-static int qedi_setup_cmd_pool(struct qedi_ctx *qedi,
-			       struct iscsi_session *session)
+static int qedi_alloc_task_priv(struct iscsi_session *session,
+				struct iscsi_task *task)
 {
-	int i;
+	struct qedi_ctx *qedi = iscsi_host_priv(session->host);
+	struct qedi_cmd *cmd = task->dd_data;
 
-	for (i = 0; i < session->cmds_max; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct qedi_cmd *cmd = task->dd_data;
+	task->hdr = &cmd->hdr;
+	task->hdr_max = sizeof(struct iscsi_hdr);
 
-		task->hdr = &cmd->hdr;
-		task->hdr_max = sizeof(struct iscsi_hdr);
+	if (qedi_alloc_sget(qedi, cmd))
+		return -ENOMEM;
 
-		if (qedi_alloc_sget(qedi, session, cmd))
-			goto free_sgets;
-
-		cmd->sense_buffer = dma_alloc_coherent(&qedi->pdev->dev,
-						       SCSI_SENSE_BUFFERSIZE,
-						       &cmd->sense_buffer_dma,
-						       GFP_KERNEL);
-		if (!cmd->sense_buffer)
-			goto free_sgets;
-	}
+	cmd->sense_buffer = dma_alloc_coherent(&qedi->pdev->dev,
+					       SCSI_SENSE_BUFFERSIZE,
+					       &cmd->sense_buffer_dma,
+					       GFP_KERNEL);
+	if (!cmd->sense_buffer)
+		goto free_sgets;
 
 	return 0;
 
 free_sgets:
-	qedi_destroy_cmd_pool(qedi, session);
+	qedi_free_sget(qedi, cmd);
 	return -ENOMEM;
 }
 
@@ -264,27 +258,7 @@ qedi_session_create(struct iscsi_endpoint *ep, u16 cmds_max,
 		return NULL;
 	}
 
-	if (qedi_setup_cmd_pool(qedi, cls_session->dd_data)) {
-		QEDI_ERR(&qedi->dbg_ctx,
-			 "Failed to setup cmd pool for ep=%p\n", qedi_ep);
-		goto session_teardown;
-	}
-
 	return cls_session;
-
-session_teardown:
-	iscsi_session_teardown(cls_session);
-	return NULL;
-}
-
-static void qedi_session_destroy(struct iscsi_cls_session *cls_session)
-{
-	struct iscsi_session *session = cls_session->dd_data;
-	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
-	struct qedi_ctx *qedi = iscsi_host_priv(shost);
-
-	qedi_destroy_cmd_pool(qedi, session);
-	iscsi_session_teardown(cls_session);
 }
 
 static struct iscsi_cls_conn *
@@ -1398,7 +1372,7 @@ struct iscsi_transport qedi_iscsi_transport = {
 	.caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_MULTI_R2T | CAP_DATADGST |
 		CAP_DATA_PATH_OFFLOAD | CAP_TEXT_NEGO,
 	.create_session = qedi_session_create,
-	.destroy_session = qedi_session_destroy,
+	.destroy_session = iscsi_session_teardown,
 	.create_conn = qedi_conn_create,
 	.bind_conn = qedi_conn_bind,
 	.start_conn = qedi_conn_start,
@@ -1410,6 +1384,8 @@ struct iscsi_transport qedi_iscsi_transport = {
 	.get_session_param = iscsi_session_get_param,
 	.get_host_param = qedi_host_get_param,
 	.send_pdu = iscsi_conn_send_pdu,
+	.alloc_task_priv = qedi_alloc_task_priv,
+	.free_task_priv = qedi_free_task_priv,
 	.get_stats = qedi_conn_get_stats,
 	.xmit_task = qedi_task_xmit,
 	.cleanup_task = qedi_cleanup_task,
@@ -1626,7 +1602,7 @@ void qedi_clear_session_ctx(struct iscsi_cls_session *cls_sess)
 
 	qedi_conn_destroy(qedi_conn->cls_conn);
 
-	qedi_session_destroy(cls_sess);
+	iscsi_session_teardown(cls_sess);
 }
 
 void qedi_process_tcp_error(struct qedi_endpoint *ep,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 07/40] scsi: bnx2i: implement alloc_task_priv/free_task_priv
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (5 preceding siblings ...)
  2021-04-03 23:22 ` [PATCH 06/40] scsi: qedi: implement alloc_task_priv/free_task_priv Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 08/40] scsi: iser, be2iscsi, qla4xxx: set scsi_host_template cmd_size Mike Christie
                   ` (33 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Have bnx2i use the alloc_task_priv/free_task_priv instead of rolling its
own loops.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/bnx2i/bnx2i_iscsi.c | 107 +++++++------------------------
 1 file changed, 24 insertions(+), 83 deletions(-)

diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 48809fc8f095..ce98112799ed 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -438,11 +438,9 @@ static void bnx2i_free_ep(struct iscsi_endpoint *ep)
 /**
  * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command
  * @hba:	adapter instance pointer
- * @session:	iscsi session pointer
  * @cmd:	iscsi command structure
  */
-static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session,
-			   struct bnx2i_cmd *cmd)
+static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
 {
 	struct io_bdt *io = &cmd->io_tbl;
 	struct iscsi_bd *bd;
@@ -451,68 +449,39 @@ static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session,
 					ISCSI_MAX_BDS_PER_CMD * sizeof(*bd),
 					&io->bd_tbl_dma, GFP_KERNEL);
 	if (!io->bd_tbl) {
-		iscsi_session_printk(KERN_ERR, session, "Could not "
-				     "allocate bdt.\n");
+		shost_printk(KERN_ERR, hba->shost, "Could not allocate bdt.\n");
 		return -ENOMEM;
 	}
 	io->bd_valid = 0;
 	return 0;
 }
 
-/**
- * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table
- * @hba:	adapter instance pointer
- * @session:	iscsi session pointer
- */
-static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba,
-				   struct iscsi_session *session)
+static void bnx2i_free_task_priv(struct iscsi_session *session,
+				 struct iscsi_task *task)
 {
-	int i;
-
-	for (i = 0; i < session->cmds_max; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct bnx2i_cmd *cmd = task->dd_data;
+	struct bnx2i_hba *hba = iscsi_host_priv(session->host);
+	struct bnx2i_cmd *cmd = task->dd_data;
 
-		if (cmd->io_tbl.bd_tbl)
-			dma_free_coherent(&hba->pcidev->dev,
-					  ISCSI_MAX_BDS_PER_CMD *
-					  sizeof(struct iscsi_bd),
-					  cmd->io_tbl.bd_tbl,
-					  cmd->io_tbl.bd_tbl_dma);
-	}
+	if (!cmd->io_tbl.bd_tbl)
+		return;
 
+	dma_free_coherent(&hba->pcidev->dev,
+			  ISCSI_MAX_BDS_PER_CMD * sizeof(struct iscsi_bd),
+			  cmd->io_tbl.bd_tbl, cmd->io_tbl.bd_tbl_dma);
 }
 
-
-/**
- * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session
- * @hba:	adapter instance pointer
- * @session:	iscsi session pointer
- */
-static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba,
-				struct iscsi_session *session)
+static int bnx2i_alloc_task_priv(struct iscsi_session *session,
+				 struct iscsi_task *task)
 {
-	int i;
-
-	for (i = 0; i < session->cmds_max; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct bnx2i_cmd *cmd = task->dd_data;
-
-		task->hdr = &cmd->hdr;
-		task->hdr_max = sizeof(struct iscsi_hdr);
-
-		if (bnx2i_alloc_bdt(hba, session, cmd))
-			goto free_bdts;
-	}
+	struct bnx2i_hba *hba = iscsi_host_priv(session->host);
+	struct bnx2i_cmd *cmd = task->dd_data;
 
-	return 0;
+	task->hdr = &cmd->hdr;
+	task->hdr_max = sizeof(struct iscsi_hdr);
 
-free_bdts:
-	bnx2i_destroy_cmd_pool(hba, session);
-	return -ENOMEM;
+	return bnx2i_alloc_bdt(hba, cmd);
 }
 
-
 /**
  * bnx2i_setup_mp_bdt - allocate BD table resources
  * @hba:	pointer to adapter structure
@@ -1286,7 +1255,6 @@ bnx2i_session_create(struct iscsi_endpoint *ep,
 		     uint32_t initial_cmdsn)
 {
 	struct Scsi_Host *shost;
-	struct iscsi_cls_session *cls_session;
 	struct bnx2i_hba *hba;
 	struct bnx2i_endpoint *bnx2i_ep;
 
@@ -1310,40 +1278,11 @@ bnx2i_session_create(struct iscsi_endpoint *ep,
 	else if (cmds_max < BNX2I_SQ_WQES_MIN)
 		cmds_max = BNX2I_SQ_WQES_MIN;
 
-	cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost,
-					  cmds_max, 0, sizeof(struct bnx2i_cmd),
-					  initial_cmdsn, ISCSI_MAX_TARGET);
-	if (!cls_session)
-		return NULL;
-
-	if (bnx2i_setup_cmd_pool(hba, cls_session->dd_data))
-		goto session_teardown;
-	return cls_session;
-
-session_teardown:
-	iscsi_session_teardown(cls_session);
-	return NULL;
-}
-
-
-/**
- * bnx2i_session_destroy - destroys iscsi session
- * @cls_session:	pointer to iscsi cls session
- *
- * Destroys previously created iSCSI session instance and releases
- *	all resources held by it
- */
-static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session)
-{
-	struct iscsi_session *session = cls_session->dd_data;
-	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
-	struct bnx2i_hba *hba = iscsi_host_priv(shost);
-
-	bnx2i_destroy_cmd_pool(hba, session);
-	iscsi_session_teardown(cls_session);
+	return iscsi_session_setup(&bnx2i_iscsi_transport, shost,
+				   cmds_max, 0, sizeof(struct bnx2i_cmd),
+				   initial_cmdsn, ISCSI_MAX_TARGET);
 }
 
-
 /**
  * bnx2i_conn_create - create iscsi connection instance
  * @cls_session:	pointer to iscsi cls session
@@ -2274,7 +2213,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
 				  CAP_DATA_PATH_OFFLOAD |
 				  CAP_TEXT_NEGO,
 	.create_session		= bnx2i_session_create,
-	.destroy_session	= bnx2i_session_destroy,
+	.destroy_session	= iscsi_session_teardown,
 	.create_conn		= bnx2i_conn_create,
 	.bind_conn		= bnx2i_conn_bind,
 	.destroy_conn		= bnx2i_conn_destroy,
@@ -2286,6 +2225,8 @@ struct iscsi_transport bnx2i_iscsi_transport = {
 	.start_conn		= bnx2i_conn_start,
 	.stop_conn		= iscsi_conn_stop,
 	.send_pdu		= iscsi_conn_send_pdu,
+	.alloc_task_priv	= bnx2i_alloc_task_priv,
+	.free_task_priv		= bnx2i_free_task_priv,
 	.xmit_task		= bnx2i_task_xmit,
 	.get_stats		= bnx2i_conn_get_stats,
 	/* TCP connect - disconnect - option-2 interface calls */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 08/40] scsi: iser, be2iscsi, qla4xxx: set scsi_host_template cmd_size
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (6 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 07/40] scsi: bnx2i: " Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 09/40] scsi: bnx2i: " Mike Christie
                   ` (32 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Use scsi_host_template cmd_size so the block/scsi-ml layers allocate the
iscsi structs for the driver. This patch includes the easy drivers that
just needed to set the size and a helper to init the iscsi task.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/infiniband/ulp/iser/iscsi_iser.c |  3 +++
 drivers/scsi/be2iscsi/be_main.c          |  2 ++
 drivers/scsi/libiscsi.c                  | 17 +++++++++++++++++
 drivers/scsi/qla4xxx/ql4_os.c            |  3 +++
 include/scsi/libiscsi.h                  |  1 +
 5 files changed, 26 insertions(+)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 8fcaa1136f2c..1f8997f29516 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -990,6 +990,9 @@ static struct scsi_host_template iscsi_iser_sht = {
 	.proc_name              = "iscsi_iser",
 	.this_id                = -1,
 	.track_queue_depth	= 1,
+	.cmd_size		= sizeof(struct iscsi_iser_task) +
+				  sizeof(struct iscsi_task),
+	.init_cmd_priv		= iscsi_init_cmd_priv,
 };
 
 static struct iscsi_transport iscsi_iser_transport = {
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 18d0591e4dbb..bcb12e674795 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -402,6 +402,8 @@ static struct scsi_host_template beiscsi_sht = {
 	.cmd_per_lun = BEISCSI_CMD_PER_LUN,
 	.vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID,
 	.track_queue_depth = 1,
+	.cmd_size = sizeof(struct beiscsi_io_task) + sizeof(struct iscsi_task),
+	.init_cmd_priv = iscsi_init_cmd_priv,
 };
 
 static struct scsi_transport_template *beiscsi_scsi_transport;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 926d33b2c9c7..07b23f3967a9 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2850,6 +2850,23 @@ static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
 	scsi_host_put(shost);
 }
 
+static void iscsi_init_task(struct iscsi_task *task)
+{
+	task->dd_data = &task[1];
+	task->itt = ISCSI_RESERVED_TAG;
+	task->state = ISCSI_TASK_FREE;
+	INIT_LIST_HEAD(&task->running);
+}
+
+int iscsi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
+{
+	struct iscsi_task *task = scsi_cmd_priv(sc);
+
+	iscsi_init_task(task);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_init_cmd_priv);
+
 /**
  * iscsi_session_setup - create iscsi cls session and host and session
  * @iscsit: iscsi transport template
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 7bd9a4a04ad5..af89d39f19e5 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -239,6 +239,9 @@ static struct scsi_host_template qla4xxx_driver_template = {
 	.this_id		= -1,
 	.cmd_per_lun		= 3,
 	.sg_tablesize		= SG_ALL,
+	.cmd_size		= sizeof(struct ql4_task_data) +
+				  sizeof(struct iscsi_task),
+	.init_cmd_priv		= iscsi_init_cmd_priv,
 
 	.max_sectors		= 0xFFFF,
 	.shost_attrs		= qla4xxx_host_attrs,
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index ddd4b9a809a1..11f0dc74d4c5 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -467,6 +467,7 @@ extern void __iscsi_put_task(struct iscsi_task *task);
 extern void __iscsi_get_task(struct iscsi_task *task);
 extern void iscsi_complete_scsi_task(struct iscsi_task *task,
 				     uint32_t exp_cmdsn, uint32_t max_cmdsn);
+extern int iscsi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd);
 
 /*
  * generic helpers
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 09/40] scsi: bnx2i: set scsi_host_template cmd_size
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (7 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 08/40] scsi: iser, be2iscsi, qla4xxx: set scsi_host_template cmd_size Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 10/40] scsi: qedi: " Mike Christie
                   ` (31 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Use scsi_host_template cmd_size so the block/scsi-ml layers allocate the
iscsi structs for the driver.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/bnx2i/bnx2i_iscsi.c | 55 ++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index ce98112799ed..a964e4e81a0c 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -434,6 +434,31 @@ static void bnx2i_free_ep(struct iscsi_endpoint *ep)
 	iscsi_destroy_endpoint(ep);
 }
 
+static void __bnx2i_free_task_priv(struct Scsi_Host *shost,
+				   struct iscsi_task *task)
+{
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
+	struct bnx2i_cmd *cmd = task->dd_data;
+
+	if (!cmd->io_tbl.bd_tbl)
+		return;
+
+	dma_free_coherent(&hba->pcidev->dev,
+			  ISCSI_MAX_BDS_PER_CMD * sizeof(struct iscsi_bd),
+			  cmd->io_tbl.bd_tbl, cmd->io_tbl.bd_tbl_dma);
+}
+
+static void bnx2i_free_task_priv(struct iscsi_session *session,
+				 struct iscsi_task *task)
+{
+	__bnx2i_free_task_priv(session->host, task);
+}
+
+static int bnx2i_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
+{
+	__bnx2i_free_task_priv(shost, scsi_cmd_priv(sc));
+	return 0;
+}
 
 /**
  * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command
@@ -456,30 +481,28 @@ static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd)
 	return 0;
 }
 
-static void bnx2i_free_task_priv(struct iscsi_session *session,
-				 struct iscsi_task *task)
+static int __bnx2i_alloc_task_priv(struct Scsi_Host *shost,
+				   struct iscsi_task *task)
 {
-	struct bnx2i_hba *hba = iscsi_host_priv(session->host);
+	struct bnx2i_hba *hba = iscsi_host_priv(shost);
 	struct bnx2i_cmd *cmd = task->dd_data;
 
-	if (!cmd->io_tbl.bd_tbl)
-		return;
+	task->hdr = &cmd->hdr;
+	task->hdr_max = sizeof(struct iscsi_hdr);
 
-	dma_free_coherent(&hba->pcidev->dev,
-			  ISCSI_MAX_BDS_PER_CMD * sizeof(struct iscsi_bd),
-			  cmd->io_tbl.bd_tbl, cmd->io_tbl.bd_tbl_dma);
+	return bnx2i_alloc_bdt(hba, cmd);
 }
 
 static int bnx2i_alloc_task_priv(struct iscsi_session *session,
 				 struct iscsi_task *task)
 {
-	struct bnx2i_hba *hba = iscsi_host_priv(session->host);
-	struct bnx2i_cmd *cmd = task->dd_data;
-
-	task->hdr = &cmd->hdr;
-	task->hdr_max = sizeof(struct iscsi_hdr);
+	return __bnx2i_alloc_task_priv(session->host, task);
+}
 
-	return bnx2i_alloc_bdt(hba, cmd);
+static int bnx2i_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
+{
+	iscsi_init_cmd_priv(shost, sc);
+	return __bnx2i_alloc_task_priv(shost, scsi_cmd_priv(sc));
 }
 
 /**
@@ -2203,6 +2226,10 @@ static struct scsi_host_template bnx2i_host_template = {
 	.sg_tablesize		= ISCSI_MAX_BDS_PER_CMD,
 	.shost_attrs		= bnx2i_dev_attributes,
 	.track_queue_depth	= 1,
+	.cmd_size		= sizeof(struct bnx2i_cmd) +
+				  sizeof(struct iscsi_task),
+	.init_cmd_priv		= bnx2i_init_cmd_priv,
+	.exit_cmd_priv		= bnx2i_exit_cmd_priv,
 };
 
 struct iscsi_transport bnx2i_iscsi_transport = {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 10/40] scsi: qedi: set scsi_host_template cmd_size
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (8 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 09/40] scsi: bnx2i: " Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 11/40] scsi: iscsi_tcp, libcxgbi: use init_cmd_priv/exit_cmd_priv Mike Christie
                   ` (30 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Use scsi_host_template cmd_size so the block/scsi-ml layers allocate the
iscsi structs for the driver.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_iscsi.c | 42 +++++++++++++++++++++++++++++-----
 1 file changed, 36 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 54c1d0a2484c..36e81eb567b2 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -14,6 +14,9 @@
 #include "qedi_iscsi.h"
 #include "qedi_gbl.h"
 
+static int qedi_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc);
+static int qedi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc);
+
 int qedi_recover_all_conns(struct qedi_ctx *qedi)
 {
 	struct qedi_conn *qedi_conn;
@@ -59,6 +62,9 @@ struct scsi_host_template qedi_host_template = {
 	.dma_boundary = QEDI_HW_DMA_BOUNDARY,
 	.cmd_per_lun = 128,
 	.shost_attrs = qedi_shost_attrs,
+	.cmd_size = sizeof(struct qedi_cmd) + sizeof(struct iscsi_task),
+	.init_cmd_priv = qedi_init_cmd_priv,
+	.exit_cmd_priv = qedi_exit_cmd_priv,
 };
 
 static void qedi_conn_free_login_resources(struct qedi_ctx *qedi,
@@ -170,10 +176,10 @@ static void qedi_free_sget(struct qedi_ctx *qedi, struct qedi_cmd *cmd)
 			  cmd->io_tbl.sge_tbl, cmd->io_tbl.sge_tbl_dma);
 }
 
-static void qedi_free_task_priv(struct iscsi_session *session,
-				struct iscsi_task *task)
+static void __qedi_free_task_priv(struct Scsi_Host *shost,
+				  struct iscsi_task *task)
 {
-	struct qedi_ctx *qedi = iscsi_host_priv(session->host);
+	struct qedi_ctx *qedi = iscsi_host_priv(shost);
 	struct qedi_cmd *cmd = task->dd_data;
 
 	qedi_free_sget(qedi, cmd);
@@ -183,6 +189,18 @@ static void qedi_free_task_priv(struct iscsi_session *session,
 				  cmd->sense_buffer, cmd->sense_buffer_dma);
 }
 
+static void qedi_free_task_priv(struct iscsi_session *session,
+				struct iscsi_task *task)
+{
+	return __qedi_free_task_priv(session->host, task);
+}
+
+static int qedi_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
+{
+	__qedi_free_task_priv(shost, scsi_cmd_priv(sc));
+	return 0;
+}
+
 static int qedi_alloc_sget(struct qedi_ctx *qedi, struct qedi_cmd *cmd)
 {
 	struct qedi_io_bdt *io = &cmd->io_tbl;
@@ -202,10 +220,10 @@ static int qedi_alloc_sget(struct qedi_ctx *qedi, struct qedi_cmd *cmd)
 	return 0;
 }
 
-static int qedi_alloc_task_priv(struct iscsi_session *session,
-				struct iscsi_task *task)
+static int __qedi_alloc_task_priv(struct Scsi_Host *shost,
+				  struct iscsi_task *task)
 {
-	struct qedi_ctx *qedi = iscsi_host_priv(session->host);
+	struct qedi_ctx *qedi = iscsi_host_priv(shost);
 	struct qedi_cmd *cmd = task->dd_data;
 
 	task->hdr = &cmd->hdr;
@@ -228,6 +246,18 @@ static int qedi_alloc_task_priv(struct iscsi_session *session,
 	return -ENOMEM;
 }
 
+static int qedi_alloc_task_priv(struct iscsi_session *session,
+				struct iscsi_task *task)
+{
+	return __qedi_alloc_task_priv(session->host, task);
+}
+
+static int qedi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
+{
+	iscsi_init_cmd_priv(shost, sc);
+	return __qedi_alloc_task_priv(shost, scsi_cmd_priv(sc));
+}
+
 static struct iscsi_cls_session *
 qedi_session_create(struct iscsi_endpoint *ep, u16 cmds_max,
 		    u16 qdepth, uint32_t initial_cmdsn)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 11/40] scsi: iscsi_tcp, libcxgbi: use init_cmd_priv/exit_cmd_priv
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (9 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 10/40] scsi: qedi: " Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 12/40] scsi: libiscsi: use scsi_host_busy_iter Mike Christie
                   ` (29 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Implemet init_cmd_priv/exit_cmd_priv/cmd_size to have the block layer
allocate the iscsi structs for the driver

Note: Because for cxgbi we do not have access to the specific session we
are creating cmds for, all sessions get the max of what is on the host but
this is normally going to one so it should not be any different.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/cxgbi/cxgb3i/cxgb3i.c |   5 ++
 drivers/scsi/cxgbi/cxgb4i/cxgb4i.c |   5 ++
 drivers/scsi/cxgbi/libcxgbi.c      |  10 ---
 drivers/scsi/iscsi_tcp.c           |  11 ++--
 drivers/scsi/libiscsi_tcp.c        | 102 +++++++++++++++--------------
 include/scsi/libiscsi_tcp.h        |   5 +-
 6 files changed, 72 insertions(+), 66 deletions(-)

diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index 37d99357120f..d45babca253a 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -98,6 +98,11 @@ static struct scsi_host_template cxgb3i_host_template = {
 	.dma_boundary	= PAGE_SIZE - 1,
 	.this_id	= -1,
 	.track_queue_depth = 1,
+	.cmd_size	= sizeof(struct iscsi_tcp_task) +
+			  sizeof(struct cxgbi_task_data) +
+			  sizeof(struct iscsi_task),
+	.init_cmd_priv	= iscsi_tcp_init_cmd_priv,
+	.exit_cmd_priv	= iscsi_tcp_exit_cmd_priv,
 };
 
 static struct iscsi_transport cxgb3i_iscsi_transport = {
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 2c3491528d42..d6647fa04851 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -116,6 +116,11 @@ static struct scsi_host_template cxgb4i_host_template = {
 	.dma_boundary	= PAGE_SIZE - 1,
 	.this_id	= -1,
 	.track_queue_depth = 1,
+	.cmd_size	= sizeof(struct iscsi_tcp_task) +
+			  sizeof(struct cxgbi_task_data) +
+			  sizeof(struct iscsi_task),
+	.init_cmd_priv	= iscsi_tcp_init_cmd_priv,
+	.exit_cmd_priv	= iscsi_tcp_exit_cmd_priv,
 };
 
 static struct iscsi_transport cxgb4i_iscsi_transport = {
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index ecb134b4699f..919451810018 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -2727,7 +2727,6 @@ struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep,
 	struct cxgbi_hba *chba;
 	struct Scsi_Host *shost;
 	struct iscsi_cls_session *cls_session;
-	struct iscsi_session *session;
 
 	if (!ep) {
 		pr_err("missing endpoint.\n");
@@ -2748,17 +2747,9 @@ struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep,
 	if (!cls_session)
 		return NULL;
 
-	session = cls_session->dd_data;
-	if (iscsi_tcp_r2tpool_alloc(session))
-		goto remove_session;
-
 	log_debug(1 << CXGBI_DBG_ISCSI,
 		"ep 0x%p, cls sess 0x%p.\n", ep, cls_session);
 	return cls_session;
-
-remove_session:
-	iscsi_session_teardown(cls_session);
-	return NULL;
 }
 EXPORT_SYMBOL_GPL(cxgbi_create_session);
 
@@ -2767,7 +2758,6 @@ void cxgbi_destroy_session(struct iscsi_cls_session *cls_session)
 	log_debug(1 << CXGBI_DBG_ISCSI,
 		"cls sess 0x%p.\n", cls_session);
 
-	iscsi_tcp_r2tpool_free(cls_session->dd_data);
 	iscsi_session_teardown(cls_session);
 }
 EXPORT_SYMBOL_GPL(cxgbi_destroy_session);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index dd33ce0e3737..eff5f8456ced 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -883,13 +883,8 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
 	session = cls_session->dd_data;
 	tcp_sw_host = iscsi_host_priv(shost);
 	tcp_sw_host->session = session;
-
-	if (iscsi_tcp_r2tpool_alloc(session))
-		goto remove_session;
 	return cls_session;
 
-remove_session:
-	iscsi_session_teardown(cls_session);
 remove_host:
 	iscsi_host_remove(shost);
 free_host:
@@ -905,7 +900,6 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
 	if (WARN_ON_ONCE(session->leadconn))
 		return;
 
-	iscsi_tcp_r2tpool_free(cls_session->dd_data);
 	iscsi_session_teardown(cls_session);
 
 	iscsi_host_remove(shost);
@@ -1000,6 +994,11 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
 	.proc_name		= "iscsi_tcp",
 	.this_id		= -1,
 	.track_queue_depth	= 1,
+	.cmd_size		= sizeof(struct iscsi_tcp_task) +
+				  sizeof(struct iscsi_sw_tcp_hdrbuf) +
+				  sizeof(struct iscsi_task),
+	.init_cmd_priv		= iscsi_tcp_init_cmd_priv,
+	.exit_cmd_priv		= iscsi_tcp_exit_cmd_priv,
 };
 
 static struct iscsi_transport iscsi_sw_tcp_transport = {
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 2e9ffe3d1a55..73d4fe20ba9d 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -1147,68 +1147,75 @@ void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn)
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_conn_teardown);
 
-int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
+static int iscsi_tcp_calc_max_r2t(struct device *dev, void *data)
 {
-	int i;
-	int cmd_i;
+	struct iscsi_cls_session *cls_session;
+	struct iscsi_session *session;
+	int *max_r2t = data;
 
-	/*
-	 * initialize per-task: R2T pool and xmit queue
-	 */
-	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
-	        struct iscsi_task *task = session->cmds[cmd_i];
-		struct iscsi_tcp_task *tcp_task = task->dd_data;
+	if (!iscsi_is_session_dev(dev))
+		return 0;
 
-		/*
-		 * pre-allocated x2 as much r2ts to handle race when
-		 * target acks DataOut faster than we data_xmit() queues
-		 * could replenish r2tqueue.
-		 */
+	cls_session = iscsi_dev_to_session(dev);
+	session = cls_session->dd_data;
+	if (session->max_r2t > *max_r2t)
+		*max_r2t = session->max_r2t;
+	return 0;
+}
 
-		/* R2T pool */
-		if (iscsi_pool_init(&tcp_task->r2tpool,
-				    session->max_r2t * 2, NULL,
-				    sizeof(struct iscsi_r2t_info))) {
-			goto r2t_alloc_fail;
-		}
+int iscsi_tcp_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
+{
+	struct iscsi_task *task;
+	struct iscsi_tcp_task *tcp_task;
+	int max_r2t = 1;
 
-		/* R2T xmit queue */
-		if (kfifo_alloc(&tcp_task->r2tqueue,
-		      session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
-			iscsi_pool_free(&tcp_task->r2tpool);
-			goto r2t_alloc_fail;
-		}
-		spin_lock_init(&tcp_task->pool2queue);
-		spin_lock_init(&tcp_task->queue2pool);
-	}
+	iscsi_init_cmd_priv(shost, sc);
 
-	return 0;
+	/*
+	 * cxgbi does not have access to the session so we use the max of all
+	 * sessions on the host.
+	 */
+	device_for_each_child(&shost->shost_gendev, &max_r2t,
+			      iscsi_tcp_calc_max_r2t);
 
-r2t_alloc_fail:
-	for (i = 0; i < cmd_i; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct iscsi_tcp_task *tcp_task = task->dd_data;
+	task = scsi_cmd_priv(sc);
+	tcp_task = task->dd_data;
 
-		kfifo_free(&tcp_task->r2tqueue);
+	/*
+	 * pre-allocated x2 as much r2ts to handle race when
+	 * target acks DataOut faster than we data_xmit() queues
+	 * could replenish r2tqueue.
+	 */
+	if (iscsi_pool_init(&tcp_task->r2tpool, max_r2t * 2, NULL,
+			    sizeof(struct iscsi_r2t_info)))
+		return -ENOMEM;
+
+	/* R2T xmit queue */
+	if (kfifo_alloc(&tcp_task->r2tqueue, max_r2t * 4 * sizeof(void *),
+			GFP_KERNEL)) {
 		iscsi_pool_free(&tcp_task->r2tpool);
+		goto r2t_queue_alloc_fail;
 	}
+	spin_lock_init(&tcp_task->pool2queue);
+	spin_lock_init(&tcp_task->queue2pool);
+	return 0;
+
+r2t_queue_alloc_fail:
+	iscsi_pool_free(&tcp_task->r2tpool);
 	return -ENOMEM;
 }
-EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_alloc);
+EXPORT_SYMBOL_GPL(iscsi_tcp_init_cmd_priv);
 
-void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
+int iscsi_tcp_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
 {
-	int i;
-
-	for (i = 0; i < session->cmds_max; i++) {
-		struct iscsi_task *task = session->cmds[i];
-		struct iscsi_tcp_task *tcp_task = task->dd_data;
+	struct iscsi_task *task = scsi_cmd_priv(sc);
+	struct iscsi_tcp_task *tcp_task = task->dd_data;
 
-		kfifo_free(&tcp_task->r2tqueue);
-		iscsi_pool_free(&tcp_task->r2tpool);
-	}
+	kfifo_free(&tcp_task->r2tqueue);
+	iscsi_pool_free(&tcp_task->r2tpool);
+	return 0;
 }
-EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
+EXPORT_SYMBOL_GPL(iscsi_tcp_exit_cmd_priv);
 
 int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf)
 {
@@ -1223,8 +1230,7 @@ int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf)
 		return -EINVAL;
 
 	session->max_r2t = r2ts;
-	iscsi_tcp_r2tpool_free(session);
-	return iscsi_tcp_r2tpool_alloc(session);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t);
 
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index 7c8ba9d7378b..4d502f61a948 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -89,6 +89,9 @@ extern int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
 extern void iscsi_tcp_cleanup_task(struct iscsi_task *task);
 extern int iscsi_tcp_task_init(struct iscsi_task *task);
 extern int iscsi_tcp_task_xmit(struct iscsi_task *task);
+extern int iscsi_tcp_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc);
+extern int iscsi_tcp_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc);
+
 
 /* segment helpers */
 extern int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn);
@@ -118,8 +121,6 @@ iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size,
 extern void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn);
 
 /* misc helpers */
-extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
-extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
 extern int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf);
 extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
 				     struct iscsi_stats *stats);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 12/40] scsi: libiscsi: use scsi_host_busy_iter
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (10 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 11/40] scsi: iscsi_tcp, libcxgbi: use init_cmd_priv/exit_cmd_priv Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 13/40] scsi: be2iscsi: " Mike Christie
                   ` (28 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The next patches remove the session->cmds array for the scsi_cmnd iscsi
tasks. This patch has us use scsi_host_busy_iter instead of looping over
that array for the scsi_cmnd case, so we can remove it in the next patches
when we also switch over to using the blk layer cmd allocators.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 160 ++++++++++++++++++++++++----------------
 include/scsi/libiscsi.h |  12 +++
 2 files changed, 110 insertions(+), 62 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 07b23f3967a9..8a9a9f5801e3 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1909,41 +1909,69 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
 	return 0;
 }
 
-/*
- * Fail commands. session frwd lock held and xmit thread flushed.
- */
-static void fail_scsi_tasks(struct iscsi_conn *conn, u64 lun, int error)
+static bool fail_scsi_task_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
 {
+	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_sc_iter_data *iter_data = data;
+	struct iscsi_conn *conn = iter_data->conn;
 	struct iscsi_session *session = conn->session;
-	struct iscsi_task *task;
-	int i;
+
+	ISCSI_DBG_SESSION(session, "failing sc %p itt 0x%x state %d\n",
+			  task->sc, task->itt, task->state);
+	__iscsi_get_task(task);
+	spin_unlock_bh(&session->back_lock);
+
+	fail_scsi_task(task, *(int *)iter_data->data);
+
+	spin_unlock_bh(&session->frwd_lock);
+	iscsi_put_task(task);
+	spin_lock_bh(&session->frwd_lock);
 
 	spin_lock_bh(&session->back_lock);
-	for (i = 0; i < session->cmds_max; i++) {
-		task = session->cmds[i];
-		if (!task->sc || task->state == ISCSI_TASK_FREE)
-			continue;
+	return true;
+}
 
-		if (lun != -1 && lun != task->sc->device->lun)
-			continue;
+static bool iscsi_sc_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
+{
+	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_sc_iter_data *iter_data = data;
 
-		__iscsi_get_task(task);
-		spin_unlock_bh(&session->back_lock);
+	if (!task || !task->sc || task->state == ISCSI_TASK_FREE ||
+	    task->conn != iter_data->conn)
+		return true;
 
-		ISCSI_DBG_SESSION(session,
-				  "failing sc %p itt 0x%x state %d\n",
-				  task->sc, task->itt, task->state);
-		fail_scsi_task(task, error);
+	if (iter_data->lun != -1 && iter_data->lun != task->sc->device->lun)
+		return true;
 
-		spin_unlock_bh(&session->frwd_lock);
-		iscsi_put_task(task);
-		spin_lock_bh(&session->frwd_lock);
+	return iter_data->fn(sc, iter_data, rsvd);
+}
 
-		spin_lock_bh(&session->back_lock);
-	}
+void iscsi_conn_for_each_sc(struct iscsi_conn *conn,
+			    struct iscsi_sc_iter_data *iter_data)
+{
+	struct iscsi_session *session = conn->session;
+	struct Scsi_Host *shost = session->host;
 
+	iter_data->conn = conn;
+	spin_lock_bh(&session->back_lock);
+	scsi_host_busy_iter(shost, iscsi_sc_iter, iter_data);
 	spin_unlock_bh(&session->back_lock);
 }
+EXPORT_SYMBOL_GPL(iscsi_conn_for_each_sc);
+
+/*
+ * Fail commands. session frwd lock held and xmit thread flushed.
+ */
+static void fail_scsi_tasks(struct iscsi_conn *conn, u64 lun, int error)
+{
+	struct iscsi_sc_iter_data iter_data = {
+		.lun = lun,
+		.fn = fail_scsi_task_iter,
+		.data = &error,
+	};
+
+	iscsi_conn_for_each_sc(conn, &iter_data);
+}
 
 /**
  * iscsi_suspend_queue - suspend iscsi_queuecommand
@@ -2005,14 +2033,51 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
 		return 0;
 }
 
+static bool check_scsi_task_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
+{
+	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_sc_iter_data *iter_data = data;
+	struct iscsi_task *timed_out_task = iter_data->data;
+
+	if (task == timed_out_task)
+		return true;
+	/*
+	 * Only check if cmds started before this one have made
+	 * progress, or this could never fail
+	 */
+	if (time_after(task->sc->jiffies_at_alloc,
+		       timed_out_task->sc->jiffies_at_alloc))
+		return true;
+
+	if (time_after(task->last_xfer, timed_out_task->last_timeout)) {
+		/*
+		 * The timed out task has not made progress, but a task
+		 * started before us has transferred data since we
+		 * started/last-checked. We could be queueing too many tasks
+		 * or the LU is bad.
+		 *
+		 * If the device is bad the cmds ahead of us on other devs will
+		 * complete, and this loop will eventually fail starting the
+		 * scsi eh.
+		 */
+		ISCSI_DBG_EH(task->conn->session,
+			     "Command has not made progress but commands ahead of it have. Asking scsi-ml for more time to complete. Our last xfer vs running task last xfer %lu/%lu. Last check %lu.\n",
+			     timed_out_task->last_xfer, task->last_xfer,
+			     timed_out_task->last_timeout);
+		iter_data->rc = BLK_EH_RESET_TIMER;
+		return false;
+	}
+	return true;
+}
+
 enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 {
 	enum blk_eh_timer_return rc = BLK_EH_DONE;
-	struct iscsi_task *task = NULL, *running_task;
+	struct iscsi_task *task;
 	struct iscsi_cls_session *cls_session;
+	struct iscsi_sc_iter_data iter_data;
 	struct iscsi_session *session;
 	struct iscsi_conn *conn;
-	int i;
 
 	cls_session = starget_to_session(scsi_target(sc->device));
 	session = cls_session->dd_data;
@@ -2091,45 +2156,16 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 		goto done;
 	}
 
-	spin_lock(&session->back_lock);
-	for (i = 0; i < conn->session->cmds_max; i++) {
-		running_task = conn->session->cmds[i];
-		if (!running_task->sc || running_task == task ||
-		     running_task->state != ISCSI_TASK_RUNNING)
-			continue;
-
-		/*
-		 * Only check if cmds started before this one have made
-		 * progress, or this could never fail
-		 */
-		if (time_after(running_task->sc->jiffies_at_alloc,
-			       task->sc->jiffies_at_alloc))
-			continue;
+	iter_data.data = task;
+	iter_data.rc = BLK_EH_DONE;
+	iter_data.fn = check_scsi_task_iter;
+	iter_data.lun = -1;
 
-		if (time_after(running_task->last_xfer, task->last_timeout)) {
-			/*
-			 * This task has not made progress, but a task
-			 * started before us has transferred data since
-			 * we started/last-checked. We could be queueing
-			 * too many tasks or the LU is bad.
-			 *
-			 * If the device is bad the cmds ahead of us on
-			 * other devs will complete, and this loop will
-			 * eventually fail starting the scsi eh.
-			 */
-			ISCSI_DBG_EH(session, "Command has not made progress "
-				     "but commands ahead of it have. "
-				     "Asking scsi-ml for more time to "
-				     "complete. Our last xfer vs running task "
-				     "last xfer %lu/%lu. Last check %lu.\n",
-				     task->last_xfer, running_task->last_xfer,
-				     task->last_timeout);
-			spin_unlock(&session->back_lock);
-			rc = BLK_EH_RESET_TIMER;
-			goto done;
-		}
+	iscsi_conn_for_each_sc(conn, &iter_data);
+	if (iter_data.rc != BLK_EH_DONE) {
+		rc = iter_data.rc;
+		goto done;
 	}
-	spin_unlock(&session->back_lock);
 
 	/* Assumes nop timeout is shorter than scsi cmd timeout */
 	if (task->have_checked_conn)
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 11f0dc74d4c5..5a5f76adbca3 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -469,6 +469,18 @@ extern void iscsi_complete_scsi_task(struct iscsi_task *task,
 				     uint32_t exp_cmdsn, uint32_t max_cmdsn);
 extern int iscsi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd);
 
+struct iscsi_sc_iter_data {
+	struct iscsi_conn *conn;
+	/* optional: if set to -1. It will be ignored */
+	u64 lun;
+	void *data;
+	int rc;
+	bool (*fn)(struct scsi_cmnd *sc, void *data, bool rsvd);
+};
+
+extern void iscsi_conn_for_each_sc(struct iscsi_conn *conn,
+				   struct iscsi_sc_iter_data *iter_data);
+
 /*
  * generic helpers
  */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 13/40] scsi: be2iscsi: use scsi_host_busy_iter
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (11 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 12/40] scsi: libiscsi: use scsi_host_busy_iter Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 14/40] scsi: libiscsi rename iscsi_complete_task Mike Christie
                   ` (27 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Use the iscsi scsi_host_busy_iter helper so we are not digging into
libiscsi structs and because the session cmds array is being removed.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c | 108 ++++++++++++++++++--------------
 1 file changed, 61 insertions(+), 47 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index bcb12e674795..4d4e3d606e25 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -265,21 +265,63 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
 	return iscsi_eh_abort(sc);
 }
 
+struct beiscsi_invldt_cmd_tbl {
+	struct invldt_cmd_tbl tbl[BE_INVLDT_CMD_TBL_SZ];
+	struct iscsi_task *task[BE_INVLDT_CMD_TBL_SZ];
+};
+
+static bool beiscsi_dev_reset_sc_iter(struct scsi_cmnd *sc, void *data,
+				      bool rsvd)
+{
+	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_sc_iter_data *iter_data = data;
+	struct beiscsi_invldt_cmd_tbl *inv_tbl = iter_data->data;
+	struct beiscsi_conn *beiscsi_conn = iter_data->conn->dd_data;
+	struct beiscsi_hba *phba = beiscsi_conn->phba;
+	int nents = iter_data->rc;
+	struct beiscsi_io_task *io_task;
+
+	/*
+	 * Can't fit in more cmds? Normally this won't happen b'coz
+	 * BEISCSI_CMD_PER_LUN is same as BE_INVLDT_CMD_TBL_SZ.
+	 */
+	if (iter_data->rc == BE_INVLDT_CMD_TBL_SZ) {
+		iter_data->rc = BE_INVLDT_CMD_TBL_SZ + 1;
+		return false;
+	}
+
+	/* get a task ref till FW processes the req for the ICD used */
+	__iscsi_get_task(task);
+	io_task = task->dd_data;
+	/* mark WRB invalid which have been not processed by FW yet */
+	if (is_chip_be2_be3r(phba)) {
+		AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
+			      io_task->pwrb_handle->pwrb, 1);
+	} else {
+		AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld,
+			      io_task->pwrb_handle->pwrb, 1);
+	}
+
+	inv_tbl->tbl[nents].cid = beiscsi_conn->beiscsi_conn_cid;
+	inv_tbl->tbl[nents].icd = io_task->psgl_handle->sgl_index;
+	inv_tbl->task[nents] = task;
+	nents++;
+
+	iter_data->rc = nents;
+	return true;
+}
+
 static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
 {
-	struct beiscsi_invldt_cmd_tbl {
-		struct invldt_cmd_tbl tbl[BE_INVLDT_CMD_TBL_SZ];
-		struct iscsi_task *task[BE_INVLDT_CMD_TBL_SZ];
-	} *inv_tbl;
+	struct iscsi_sc_iter_data iter_data;
+	struct beiscsi_invldt_cmd_tbl *inv_tbl;
 	struct iscsi_cls_session *cls_session;
 	struct beiscsi_conn *beiscsi_conn;
-	struct beiscsi_io_task *io_task;
 	struct iscsi_session *session;
 	struct beiscsi_hba *phba;
 	struct iscsi_conn *conn;
-	struct iscsi_task *task;
 	unsigned int i, nents;
-	int rc, more = 0;
+	int rc;
 
 	cls_session = starget_to_session(scsi_target(sc->device));
 	session = cls_session->dd_data;
@@ -302,56 +344,28 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
 			    "BM_%d : invldt_cmd_tbl alloc failed\n");
 		return FAILED;
 	}
-	nents = 0;
-	/* take back_lock to prevent task from getting cleaned up under us */
-	spin_lock(&session->back_lock);
-	for (i = 0; i < conn->session->cmds_max; i++) {
-		task = conn->session->cmds[i];
-		if (!task->sc)
-			continue;
 
-		if (sc->device->lun != task->sc->device->lun)
-			continue;
-		/**
-		 * Can't fit in more cmds? Normally this won't happen b'coz
-		 * BEISCSI_CMD_PER_LUN is same as BE_INVLDT_CMD_TBL_SZ.
-		 */
-		if (nents == BE_INVLDT_CMD_TBL_SZ) {
-			more = 1;
-			break;
-		}
-
-		/* get a task ref till FW processes the req for the ICD used */
-		__iscsi_get_task(task);
-		io_task = task->dd_data;
-		/* mark WRB invalid which have been not processed by FW yet */
-		if (is_chip_be2_be3r(phba)) {
-			AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
-				      io_task->pwrb_handle->pwrb, 1);
-		} else {
-			AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld,
-				      io_task->pwrb_handle->pwrb, 1);
-		}
+	iter_data.data = inv_tbl;
+	iter_data.lun = sc->device->lun;
+	iter_data.rc = 0;
+	iter_data.fn = beiscsi_dev_reset_sc_iter;
 
-		inv_tbl->tbl[nents].cid = beiscsi_conn->beiscsi_conn_cid;
-		inv_tbl->tbl[nents].icd = io_task->psgl_handle->sgl_index;
-		inv_tbl->task[nents] = task;
-		nents++;
-	}
-	spin_unlock(&session->back_lock);
+	iscsi_conn_for_each_sc(conn, &iter_data);
 	spin_unlock_bh(&session->frwd_lock);
 
-	rc = SUCCESS;
-	if (!nents)
-		goto end_reset;
-
-	if (more) {
+	nents = iter_data.rc;
+	if (nents > BE_INVLDT_CMD_TBL_SZ) {
 		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH,
 			    "BM_%d : number of cmds exceeds size of invalidation table\n");
+		nents = BE_INVLDT_CMD_TBL_SZ;
 		rc = FAILED;
 		goto end_reset;
 	}
 
+	rc = SUCCESS;
+	if (!nents)
+		goto end_reset;
+
 	if (beiscsi_mgmt_invalidate_icds(phba, &inv_tbl->tbl[0], nents)) {
 		beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH,
 			    "BM_%d : cid %u scmds invalidation failed\n",
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 14/40] scsi: libiscsi rename iscsi_complete_task
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (12 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 13/40] scsi: be2iscsi: " Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 15/40] scsi: libiscsi: add helper to complete a iscsi task Mike Christie
                   ` (26 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The next patch adds a helper that allows drivers like be2iscsi and qedi to
complete a iscsi_task and a iscsi_hdr struct that was setup by libscsi and
the driver. This allows drivers that do not use the libiscsi itt to fake
it.

To match the naming of the other exported completion functions this patch
renames iscsi_complete_task to iscsi_finish_task so we can use the
iscsi_complete prefix for the new function, iscsi_complete_task, to match
iscsi_complete_pdu which is exported for completing pdus.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8a9a9f5801e3..768b6cefd067 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -502,13 +502,13 @@ void iscsi_put_task(struct iscsi_task *task)
 EXPORT_SYMBOL_GPL(iscsi_put_task);
 
 /**
- * iscsi_complete_task - finish a task
+ * iscsi_finish_task - finish a task
  * @task: iscsi cmd task
  * @state: state to complete task with
  *
  * Must be called with session back_lock.
  */
-static void iscsi_complete_task(struct iscsi_task *task, int state)
+static void iscsi_finish_task(struct iscsi_task *task, int state)
 {
 	struct iscsi_conn *conn = task->conn;
 
@@ -550,7 +550,7 @@ void iscsi_complete_scsi_task(struct iscsi_task *task,
 
 	conn->last_recv = jiffies;
 	__iscsi_update_cmdsn(conn->session, exp_cmdsn, max_cmdsn);
-	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 }
 EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
 
@@ -621,7 +621,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
 	sc = task->sc;
 	sc->result = err << 16;
 	scsi_set_resid(sc, scsi_bufflen(sc));
-	iscsi_complete_task(task, state);
+	iscsi_finish_task(task, state);
 	spin_unlock_bh(&conn->session->back_lock);
 }
 
@@ -893,7 +893,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n",
 			  sc, sc->result, task->itt);
 	conn->scsirsp_pdus_cnt++;
-	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 }
 
 /**
@@ -934,7 +934,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			  "[sc %p res %d itt 0x%x]\n",
 			  sc, sc->result, task->itt);
 	conn->scsirsp_pdus_cnt++;
-	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 }
 
 static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -1018,7 +1018,7 @@ static int iscsi_nop_out_rsp(struct iscsi_task *task,
 			rc = ISCSI_ERR_CONN_FAILED;
 	} else
 		mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
-	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 	return rc;
 }
 
@@ -1258,7 +1258,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		}
 
 		iscsi_tmf_rsp(conn, hdr);
-		iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+		iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 		break;
 	case ISCSI_OP_NOOP_IN:
 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
@@ -1281,7 +1281,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 recv_pdu:
 	if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
 		rc = ISCSI_ERR_CONN_FAILED;
-	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
+	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
@@ -1813,7 +1813,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	spin_unlock_bh(&session->frwd_lock);
 
 	spin_lock_bh(&session->back_lock);
-	iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
+	iscsi_finish_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
 	spin_unlock_bh(&session->back_lock);
 reject:
 	ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
@@ -1824,7 +1824,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	spin_unlock_bh(&session->frwd_lock);
 
 	spin_lock_bh(&session->back_lock);
-	iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
+	iscsi_finish_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
 	spin_unlock_bh(&session->back_lock);
 fault:
 	ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
@@ -3268,7 +3268,7 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
 		state = ISCSI_TASK_ABRT_SESS_RECOV;
 		if (task->state == ISCSI_TASK_PENDING)
 			state = ISCSI_TASK_COMPLETED;
-		iscsi_complete_task(task, state);
+		iscsi_finish_task(task, state);
 		spin_unlock_bh(&session->back_lock);
 	}
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 15/40] scsi: libiscsi: add helper to complete a iscsi task
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (13 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 14/40] scsi: libiscsi rename iscsi_complete_task Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 16/40] scsi: be2iscsi: switch to iscsi_complete_task Mike Christie
                   ` (25 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

We export functions to complete a pdu and a scsi task, but for mgmt tasks
the driver has to fake the itt for drivers like qedi, qla4xxx and be2iscsi
which don't have direct access to the PDU that was put on the wire.
This adds a helper to allow those drivers to complete a task directly.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 86 +++++++++++++++++++++++++++--------------
 include/scsi/libiscsi.h |  2 +
 2 files changed, 59 insertions(+), 29 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 768b6cefd067..cadbe1d19344 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1148,9 +1148,8 @@ EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
 int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			 char *data, int datalen)
 {
-	struct iscsi_session *session = conn->session;
 	int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
-	struct iscsi_task *task;
+	struct iscsi_task *task = NULL;
 	uint32_t itt;
 
 	conn->last_recv = jiffies;
@@ -1163,10 +1162,60 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	else
 		itt = ~0U;
 
+	if (itt == ~0U)
+		return iscsi_complete_task(conn, NULL, hdr, data, datalen);
+
+	switch (opcode) {
+	case ISCSI_OP_SCSI_CMD_RSP:
+	case ISCSI_OP_SCSI_DATA_IN:
+		task = iscsi_itt_to_ctask(conn, hdr->itt);
+		break;
+	case ISCSI_OP_R2T:
+		/* LLD handles R2Ts if they need to. */
+		return 0;
+	case ISCSI_OP_LOGOUT_RSP:
+	case ISCSI_OP_LOGIN_RSP:
+	case ISCSI_OP_TEXT_RSP:
+	case ISCSI_OP_SCSI_TMFUNC_RSP:
+	case ISCSI_OP_NOOP_IN:
+		task = iscsi_itt_to_task(conn, hdr->itt);
+		break;
+	}
+
+	if (!task)
+		return ISCSI_ERR_BAD_OPCODE;
+
+	return iscsi_complete_task(conn, task, hdr, data, datalen);
+}
+EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
+
+/**
+ * iscsi_complete_task - complete iscsi task
+ * @conn: iscsi conn
+ * @task: iscsi task
+ * @hdr: iscsi response header with all fields set except the itt
+ * @data: data buffer
+ * @datalen: len of data buffer
+ *
+ * Completes task processing by freeing any resources allocated at
+ * queuecommand or send generic.
+ *
+ * This function should be used by drivers that do not use the libiscsi
+ * itt for the PDU that was sent to the target and has access to the
+ * iscsi_task struct directly.
+ *
+ * Session back_lock must be held.
+ */
+int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
+			struct iscsi_hdr *hdr, char *data, int datalen)
+{
+	struct iscsi_session *session = conn->session;
+	int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
+
 	ISCSI_DBG_SESSION(session, "[op 0x%x cid %d itt 0x%x len %d]\n",
-			  opcode, conn->id, itt, datalen);
+			  opcode, conn->id, task ? task->itt : ~0U, datalen);
 
-	if (itt == ~0U) {
+	if (!task) {
 		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
 
 		switch(opcode) {
@@ -1201,33 +1250,12 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		goto out;
 	}
 
+	task->last_xfer = jiffies;
+
 	switch(opcode) {
-	case ISCSI_OP_SCSI_CMD_RSP:
-	case ISCSI_OP_SCSI_DATA_IN:
-		task = iscsi_itt_to_ctask(conn, hdr->itt);
-		if (!task)
-			return ISCSI_ERR_BAD_ITT;
-		task->last_xfer = jiffies;
-		break;
 	case ISCSI_OP_R2T:
-		/*
-		 * LLD handles R2Ts if they need to.
-		 */
-		return 0;
-	case ISCSI_OP_LOGOUT_RSP:
-	case ISCSI_OP_LOGIN_RSP:
-	case ISCSI_OP_TEXT_RSP:
-	case ISCSI_OP_SCSI_TMFUNC_RSP:
-	case ISCSI_OP_NOOP_IN:
-		task = iscsi_itt_to_task(conn, hdr->itt);
-		if (!task)
-			return ISCSI_ERR_BAD_ITT;
+		/* LLD handles R2Ts if they need to. */
 		break;
-	default:
-		return ISCSI_ERR_BAD_OPCODE;
-	}
-
-	switch(opcode) {
 	case ISCSI_OP_SCSI_CMD_RSP:
 		iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen);
 		break;
@@ -1284,7 +1312,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
+EXPORT_SYMBOL_GPL(iscsi_complete_task);
 
 int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		       char *data, int datalen)
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 5a5f76adbca3..8e01beba62f1 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -467,6 +467,8 @@ extern void __iscsi_put_task(struct iscsi_task *task);
 extern void __iscsi_get_task(struct iscsi_task *task);
 extern void iscsi_complete_scsi_task(struct iscsi_task *task,
 				     uint32_t exp_cmdsn, uint32_t max_cmdsn);
+extern int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
+			       struct iscsi_hdr *hdr, char *data, int datalen);
 extern int iscsi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd);
 
 struct iscsi_sc_iter_data {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 16/40] scsi: be2iscsi: switch to iscsi_complete_task
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (14 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 15/40] scsi: libiscsi: add helper to complete a iscsi task Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 17/40] scsi: qedi: cleanup abort handling Mike Christie
                   ` (24 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This has be2iscsi use iscsi_complete_task. It then does not need to do any
itt hacks and can completely ignore the libiscsi itt.

Note: parse_pdu_itt is now just used to tell libiscsi we don't use it's itt.
In a future patchset this will be removed.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c | 30 ++++++++----------------------
 drivers/scsi/be2iscsi/be_main.h |  1 -
 2 files changed, 8 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 4d4e3d606e25..99eae2add8da 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1187,7 +1187,6 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
 		    struct common_sol_cqe *csol_cqe)
 {
 	struct iscsi_logout_rsp *hdr;
-	struct beiscsi_io_task *io_task = task->dd_data;
 	struct iscsi_conn *conn = beiscsi_conn->conn;
 
 	hdr = (struct iscsi_logout_rsp *)task->hdr;
@@ -1204,8 +1203,7 @@ be_complete_logout(struct beiscsi_conn *beiscsi_conn,
 	hdr->dlength[1] = 0;
 	hdr->dlength[2] = 0;
 	hdr->hlength = 0;
-	hdr->itt = io_task->libiscsi_itt;
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)hdr, NULL, 0);
 }
 
 static void
@@ -1215,7 +1213,6 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
 {
 	struct iscsi_tm_rsp *hdr;
 	struct iscsi_conn *conn = beiscsi_conn->conn;
-	struct beiscsi_io_task *io_task = task->dd_data;
 
 	hdr = (struct iscsi_tm_rsp *)task->hdr;
 	hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP;
@@ -1224,9 +1221,7 @@ be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
 	hdr->exp_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn);
 	hdr->max_cmdsn = cpu_to_be32(csol_cqe->exp_cmdsn +
 				     csol_cqe->cmd_wnd - 1);
-
-	hdr->itt = io_task->libiscsi_itt;
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)hdr, NULL, 0);
 }
 
 static void
@@ -1271,7 +1266,6 @@ be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn,
 {
 	struct iscsi_nopin *hdr;
 	struct iscsi_conn *conn = beiscsi_conn->conn;
-	struct beiscsi_io_task *io_task = task->dd_data;
 
 	hdr = (struct iscsi_nopin *)task->hdr;
 	hdr->flags = csol_cqe->i_flags;
@@ -1280,8 +1274,7 @@ be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn,
 				     csol_cqe->cmd_wnd - 1);
 
 	hdr->opcode = ISCSI_OP_NOOP_IN;
-	hdr->itt = io_task->libiscsi_itt;
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)hdr, NULL, 0);
 }
 
 static void adapter_get_sol_cqe(struct beiscsi_hba *phba,
@@ -1426,9 +1419,7 @@ beiscsi_complete_pdu(struct beiscsi_conn *beiscsi_conn,
 {
 	struct beiscsi_hba *phba = beiscsi_conn->phba;
 	struct iscsi_conn *conn = beiscsi_conn->conn;
-	struct beiscsi_io_task *io_task;
-	struct iscsi_hdr *login_hdr;
-	struct iscsi_task *task;
+	struct iscsi_task *task = NULL;
 	u8 code;
 
 	code = AMAP_GET_BITS(struct amap_pdu_base, opcode, phdr);
@@ -1449,9 +1440,6 @@ beiscsi_complete_pdu(struct beiscsi_conn *beiscsi_conn,
 	case ISCSI_OP_LOGIN_RSP:
 	case ISCSI_OP_TEXT_RSP:
 		task = conn->login_task;
-		io_task = task->dd_data;
-		login_hdr = (struct iscsi_hdr *)phdr;
-		login_hdr->itt = io_task->libiscsi_itt;
 		break;
 	default:
 		beiscsi_log(phba, KERN_WARNING,
@@ -1460,7 +1448,7 @@ beiscsi_complete_pdu(struct beiscsi_conn *beiscsi_conn,
 			    code);
 		return 1;
 	}
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)phdr, pdata, dlen);
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)phdr, pdata, dlen);
 	return 0;
 }
 
@@ -4384,8 +4372,7 @@ static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt,
  *
  * This is called with the session lock held. It will allocate
  * the wrb and sgl if needed for the command. And it will prep
- * the pdu's itt. beiscsi_parse_pdu will later translate
- * the pdu itt to the libiscsi task itt.
+ * the pdu's itt.
  */
 static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
 {
@@ -4405,7 +4392,6 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
 	if (!io_task->cmd_bhs)
 		return -ENOMEM;
 	io_task->bhs_pa.u.a64.address = paddr;
-	io_task->libiscsi_itt = (itt_t)task->itt;
 	io_task->conn = beiscsi_conn;
 
 	task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
@@ -4803,9 +4789,9 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
 		beiscsi_log(phba, KERN_ERR,
 			    BEISCSI_LOG_IO | BEISCSI_LOG_ISCSI,
 			    "BM_%d : scsi_dma_map Failed "
-			    "Driver_ITT : 0x%x ITT : 0x%x Xferlen : 0x%x\n",
+			    "Driver_ITT : 0x%x Xferlen : 0x%x\n",
 			    be32_to_cpu(io_task->cmd_bhs->iscsi_hdr.itt),
-			    io_task->libiscsi_itt, scsi_bufflen(sc));
+			    scsi_bufflen(sc));
 
 		return num_sg;
 	}
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 98977c0700f1..ccfdec3ccf21 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -461,7 +461,6 @@ struct beiscsi_io_task {
 	struct scsi_cmnd *scsi_cmnd;
 	int num_sg;
 	struct hwi_wrb_context *pwrb_context;
-	itt_t libiscsi_itt;
 	struct be_cmd_bhs *cmd_bhs;
 	struct be_bus_address bhs_pa;
 	unsigned short bhs_len;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 17/40] scsi: qedi: cleanup abort handling
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (15 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 16/40] scsi: be2iscsi: switch to iscsi_complete_task Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 18/40] scsi: qedi: misc cleanup Mike Christie
                   ` (23 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This has qedi do it's fw cleanup from the eh abort callout then call into
libiscsi to do the protocol/libiscsi cleanup.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_fw.c    | 216 ++++++++++-----------------------
 drivers/scsi/qedi/qedi_gbl.h   |   4 +-
 drivers/scsi/qedi/qedi_iscsi.c |  48 +++++++-
 drivers/scsi/qedi/qedi_iscsi.h |   1 +
 4 files changed, 113 insertions(+), 156 deletions(-)

diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index 440ddd2309f1..d8e10e8d3d08 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -14,9 +14,6 @@
 #include "qedi_fw_iscsi.h"
 #include "qedi_fw_scsi.h"
 
-static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
-			       struct iscsi_task *mtask);
-
 void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd)
 {
 	struct scsi_cmnd *sc = cmd->scsi_cmd;
@@ -739,7 +736,6 @@ static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi,
 
 static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 					  struct iscsi_cqe_solicited *cqe,
-					  struct iscsi_task *task,
 					  struct iscsi_conn *conn)
 {
 	struct qedi_work_map *work, *work_tmp;
@@ -752,8 +748,7 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 	u32 iscsi_cid;
 	struct qedi_conn *qedi_conn;
 	struct qedi_cmd *dbg_cmd;
-	struct iscsi_task *mtask;
-	struct iscsi_tm *tmf_hdr = NULL;
+	struct iscsi_task *task;
 
 	iscsi_cid = cqe->conn_id;
 	qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
@@ -777,8 +772,7 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 				WARN_ON(1);
 			}
 			found = 1;
-			mtask = qedi_cmd->task;
-			tmf_hdr = (struct iscsi_tm *)mtask->hdr;
+			task = work->task;
 			rtid = work->rtid;
 
 			list_del_init(&work->list);
@@ -790,49 +784,30 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 
 	if (found) {
 		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
-			  "TMF work, cqe->tid=0x%x, tmf flags=0x%x, cid=0x%x\n",
-			  proto_itt, tmf_hdr->flags, qedi_conn->iscsi_conn_id);
-
-		if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
-		    ISCSI_TM_FUNC_ABORT_TASK) {
-			spin_lock_bh(&conn->session->back_lock);
-
-			protoitt = build_itt(get_itt(tmf_hdr->rtt),
-					     conn->session->age);
-			task = iscsi_itt_to_task(conn, protoitt);
+			  "TMF work, cqe->tid=0x%x, cid=0x%x\n",
+			  proto_itt, qedi_conn->iscsi_conn_id);
 
-			spin_unlock_bh(&conn->session->back_lock);
+		dbg_cmd = task->dd_data;
 
-			if (!task) {
-				QEDI_NOTICE(&qedi->dbg_ctx,
-					    "IO task completed, tmf rtt=0x%x, cid=0x%x\n",
-					    get_itt(tmf_hdr->rtt),
-					    qedi_conn->iscsi_conn_id);
-				return;
-			}
-
-			dbg_cmd = task->dd_data;
-
-			QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
-				  "Abort tmf rtt=0x%x, i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n",
-				  get_itt(tmf_hdr->rtt), get_itt(task->itt),
-				  dbg_cmd->task_id, qedi_conn->iscsi_conn_id);
+		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
+			  "Abort i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n",
+			  get_itt(task->itt), dbg_cmd->task_id,
+			  qedi_conn->iscsi_conn_id);
 
-			if (qedi_cmd->state == CLEANUP_WAIT_FAILED)
-				qedi_cmd->state = CLEANUP_RECV;
+		if (qedi_cmd->state == CLEANUP_WAIT_FAILED)
+			qedi_cmd->state = CLEANUP_RECV;
 
-			qedi_clear_task_idx(qedi_conn->qedi, rtid);
+		qedi_clear_task_idx(qedi_conn->qedi, rtid);
 
-			spin_lock(&qedi_conn->list_lock);
-			if (likely(dbg_cmd->io_cmd_in_list)) {
-				dbg_cmd->io_cmd_in_list = false;
-				list_del_init(&dbg_cmd->io_cmd);
-				qedi_conn->active_cmd_count--;
-			}
-			spin_unlock(&qedi_conn->list_lock);
-			qedi_cmd->state = CLEANUP_RECV;
-			wake_up_interruptible(&qedi_conn->wait_queue);
+		spin_lock(&qedi_conn->list_lock);
+		if (likely(dbg_cmd->io_cmd_in_list)) {
+			dbg_cmd->io_cmd_in_list = false;
+			list_del_init(&dbg_cmd->io_cmd);
+			qedi_conn->active_cmd_count--;
 		}
+		spin_unlock(&qedi_conn->list_lock);
+		qedi_cmd->state = CLEANUP_RECV;
+		wake_up_interruptible(&qedi_conn->wait_queue);
 	} else if (qedi_conn->cmd_cleanup_req > 0) {
 		spin_lock_bh(&conn->session->back_lock);
 		qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt);
@@ -959,8 +934,7 @@ void qedi_fp_process_cqes(struct qedi_work *work)
 		goto exit_fp_process;
 	case ISCSI_CQE_TYPE_TASK_CLEANUP:
 		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "CleanUp CqE\n");
-		qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, task,
-					      conn);
+		qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, conn);
 		goto exit_fp_process;
 	default:
 		QEDI_ERR(&qedi->dbg_ctx, "Error cqe.\n");
@@ -1368,59 +1342,41 @@ static int qedi_wait_for_cleanup_request(struct qedi_ctx *qedi,
 	return 0;
 }
 
-static void qedi_tmf_work(struct work_struct *work)
+int qedi_fw_cleanup_cmd(struct iscsi_task *ctask)
 {
-	struct qedi_cmd *qedi_cmd =
-		container_of(work, struct qedi_cmd, tmf_work);
-	struct qedi_conn *qedi_conn = qedi_cmd->conn;
+	struct iscsi_conn *conn = ctask->conn;
+	struct qedi_conn *qedi_conn = conn->dd_data;
 	struct qedi_ctx *qedi = qedi_conn->qedi;
-	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct qedi_work_map *list_work = NULL;
-	struct iscsi_task *mtask;
-	struct qedi_cmd *cmd;
-	struct iscsi_task *ctask;
-	struct iscsi_tm *tmf_hdr;
+	struct qedi_work_map *list_work;
+	struct qedi_cmd *cmd, qedi_cmd;
 	s16 rval = 0;
-	s16 tid = 0;
-
-	mtask = qedi_cmd->task;
-	tmf_hdr = (struct iscsi_tm *)mtask->hdr;
-	set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
-
-	ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt);
-	if (!ctask || !ctask->sc) {
-		QEDI_ERR(&qedi->dbg_ctx, "Task already completed\n");
-		goto abort_ret;
-	}
 
-	cmd = (struct qedi_cmd *)ctask->dd_data;
+	cmd = ctask->dd_data;
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
-		  "Abort tmf rtt=0x%x, cmd itt=0x%x, cmd tid=0x%x, cid=0x%x\n",
-		  get_itt(tmf_hdr->rtt), get_itt(ctask->itt), cmd->task_id,
-		  qedi_conn->iscsi_conn_id);
+		  "abort tmf cmd itt=0x%x, cmd tid=0x%x, cid=0x%x\n",
+		  get_itt(ctask->itt), cmd->task_id, qedi_conn->iscsi_conn_id);
 
-	if (qedi_do_not_recover) {
-		QEDI_ERR(&qedi->dbg_ctx, "DONT SEND CLEANUP/ABORT %d\n",
-			 qedi_do_not_recover);
-		goto abort_ret;
-	}
-
-	list_work = kzalloc(sizeof(*list_work), GFP_ATOMIC);
+	list_work = kzalloc(sizeof(*list_work), GFP_NOIO);
 	if (!list_work) {
-		QEDI_ERR(&qedi->dbg_ctx, "Memory allocation failed\n");
-		goto abort_ret;
+		QEDI_ERR(&qedi->dbg_ctx, "memory allocation failed\n");
+		return -ENOMEM;
 	}
 
-	qedi_cmd->type = TYPEIO;
-	list_work->qedi_cmd = qedi_cmd;
+	memset(&qedi_cmd, 0, sizeof(struct qedi_cmd));
+	qedi_cmd.conn = qedi_conn;
+	qedi_cmd.type = TYPEIO;
+	qedi_cmd.list_tmf_work = list_work;
+	qedi_cmd.state = CLEANUP_WAIT;
+
+	INIT_LIST_HEAD(&list_work->list);
+	list_work->task = ctask;
+	list_work->qedi_cmd = &qedi_cmd;
 	list_work->rtid = cmd->task_id;
 	list_work->state = QEDI_WORK_SCHEDULED;
-	qedi_cmd->list_tmf_work = list_work;
 
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
-		  "Queue tmf work=%p, list node=%p, cid=0x%x, tmf flags=0x%x\n",
-		  list_work->ptr_tmf_work, list_work, qedi_conn->iscsi_conn_id,
-		  tmf_hdr->flags);
+		  "queue tmf work=%p, list node=%p, cid=0x%x\n",
+		  list_work->ptr_tmf_work, list_work, qedi_conn->iscsi_conn_id);
 
 	spin_lock_bh(&qedi_conn->tmf_work_lock);
 	list_add_tail(&list_work->list, &qedi_conn->tmf_work_list);
@@ -1428,34 +1384,21 @@ static void qedi_tmf_work(struct work_struct *work)
 
 	qedi_iscsi_cleanup_task(ctask, false);
 
-	rval = qedi_wait_for_cleanup_request(qedi, qedi_conn, ctask, qedi_cmd,
+	rval = qedi_wait_for_cleanup_request(qedi, qedi_conn, ctask, &qedi_cmd,
 					     list_work);
 	if (rval == -1) {
 		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
-			  "FW cleanup got escalated, cid=0x%x\n",
+			  "fw cleanup got escalated, cid=0x%x\n",
 			  qedi_conn->iscsi_conn_id);
-		goto ldel_exit;
+		goto force_cleanup;
 	}
 
-	tid = qedi_get_task_idx(qedi);
-	if (tid == -1) {
-		QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n",
-			 qedi_conn->iscsi_conn_id);
-		goto ldel_exit;
-	}
-
-	qedi_cmd->task_id = tid;
-	qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task);
-
-abort_ret:
-	clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
-	return;
+	return 0;
 
-ldel_exit:
+force_cleanup:
 	spin_lock_bh(&qedi_conn->tmf_work_lock);
-	if (!qedi_cmd->list_tmf_work) {
+	if (!qedi_cmd.list_tmf_work) {
 		list_del_init(&list_work->list);
-		qedi_cmd->list_tmf_work = NULL;
 		kfree(list_work);
 	}
 	spin_unlock_bh(&qedi_conn->tmf_work_lock);
@@ -1468,11 +1411,10 @@ static void qedi_tmf_work(struct work_struct *work)
 	}
 	spin_unlock(&qedi_conn->list_lock);
 
-	clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
+	return -1;
 }
 
-static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
-			       struct iscsi_task *mtask)
+int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask)
 {
 	struct iscsi_tmf_request_hdr tmf_pdu_header;
 	struct iscsi_task_params task_params;
@@ -1491,6 +1433,19 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
 
 	tmf_hdr = (struct iscsi_tm *)mtask->hdr;
 	qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
+
+	switch (tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) {
+	case ISCSI_TM_FUNC_ABORT_TASK:
+	case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
+	case ISCSI_TM_FUNC_TARGET_WARM_RESET:
+	case ISCSI_TM_FUNC_TARGET_COLD_RESET:
+		break;
+	default:
+		QEDI_ERR(&qedi->dbg_ctx, "Invalid tmf, cid=0x%x\n",
+			 qedi_conn->iscsi_conn_id);
+		return -EINVAL;
+	}
+
 	ep = qedi_conn->ep;
 	if (!ep)
 		return -ENODEV;
@@ -1566,49 +1521,6 @@ static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
 	return 0;
 }
 
-int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn,
-			  struct iscsi_task *mtask)
-{
-	struct qedi_ctx *qedi = qedi_conn->qedi;
-	struct iscsi_tm *tmf_hdr;
-	struct qedi_cmd *qedi_cmd = (struct qedi_cmd *)mtask->dd_data;
-	s16 tid = 0;
-
-	tmf_hdr = (struct iscsi_tm *)mtask->hdr;
-	qedi_cmd->task = mtask;
-
-	/* If abort task then schedule the work and return */
-	if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
-	    ISCSI_TM_FUNC_ABORT_TASK) {
-		qedi_cmd->state = CLEANUP_WAIT;
-		INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_work);
-		queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work);
-
-	} else if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
-		    ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) ||
-		   ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
-		    ISCSI_TM_FUNC_TARGET_WARM_RESET) ||
-		   ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
-		    ISCSI_TM_FUNC_TARGET_COLD_RESET)) {
-		tid = qedi_get_task_idx(qedi);
-		if (tid == -1) {
-			QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n",
-				 qedi_conn->iscsi_conn_id);
-			return -1;
-		}
-		qedi_cmd->task_id = tid;
-
-		qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task);
-
-	} else {
-		QEDI_ERR(&qedi->dbg_ctx, "Invalid tmf, cid=0x%x\n",
-			 qedi_conn->iscsi_conn_id);
-		return -1;
-	}
-
-	return 0;
-}
-
 int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
 			 struct iscsi_task *task)
 {
diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h
index 116645c08c71..a3b72e7ff9d9 100644
--- a/drivers/scsi/qedi/qedi_gbl.h
+++ b/drivers/scsi/qedi/qedi_gbl.h
@@ -31,8 +31,7 @@ int qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
 			  struct iscsi_task *task);
 int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
 			   struct iscsi_task *task);
-int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn,
-			  struct iscsi_task *mtask);
+int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask);
 int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
 			 struct iscsi_task *task);
 int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
@@ -60,6 +59,7 @@ void qedi_mark_device_available(struct iscsi_cls_session *cls_session);
 void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu);
 int qedi_recover_all_conns(struct qedi_ctx *qedi);
 void qedi_fp_process_cqes(struct qedi_work *work);
+int qedi_fw_cleanup_cmd(struct iscsi_task *ctask);
 int qedi_cleanup_all_io(struct qedi_ctx *qedi,
 			struct qedi_conn *qedi_conn,
 			struct iscsi_task *task, bool in_recovery);
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 36e81eb567b2..0f3704c4c985 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -43,13 +43,57 @@ static int qedi_eh_host_reset(struct scsi_cmnd *cmd)
 	return qedi_recover_all_conns(qedi);
 }
 
+static int qedi_eh_abort(struct scsi_cmnd *cmd)
+{
+	struct Scsi_Host *shost = cmd->device->host;
+	struct qedi_ctx *qedi = iscsi_host_priv(shost);
+	struct iscsi_cls_session *cls_session;
+	struct iscsi_session *session;
+	struct qedi_conn *qedi_conn;
+	struct iscsi_task *task;
+	int rc;
+
+	cls_session = starget_to_session(scsi_target(cmd->device));
+	session = cls_session->dd_data;
+
+	if (qedi_do_not_recover) {
+		QEDI_ERR(&qedi->dbg_ctx, "dont send cleanup/abort %d\n",
+			 qedi_do_not_recover);
+		return FAILED;
+	}
+
+	/* check if we raced, task just got cleaned up under us */
+	spin_lock_bh(&session->back_lock);
+	task = (struct iscsi_task *)cmd->SCp.ptr;
+	if (!task || !task->sc) {
+		spin_unlock_bh(&session->back_lock);
+		return SUCCESS;
+	}
+
+	__iscsi_get_task(task);
+	spin_unlock_bh(&session->back_lock);
+
+	qedi_conn = task->conn->dd_data;
+	set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
+
+	rc = qedi_fw_cleanup_cmd(task);
+
+	iscsi_put_task(task);
+	clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
+
+	if (rc)
+		return FAILED;
+
+	return iscsi_eh_abort(cmd);
+}
+
 struct scsi_host_template qedi_host_template = {
 	.module = THIS_MODULE,
 	.name = "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver",
 	.proc_name = QEDI_MODULE_NAME,
 	.queuecommand = iscsi_queuecommand,
 	.eh_timed_out = iscsi_eh_cmd_timed_out,
-	.eh_abort_handler = iscsi_eh_abort,
+	.eh_abort_handler = qedi_eh_abort,
 	.eh_device_reset_handler = iscsi_eh_device_reset,
 	.eh_target_reset_handler = iscsi_eh_recover_target,
 	.eh_host_reset_handler = qedi_eh_host_reset,
@@ -746,7 +790,7 @@ static int qedi_iscsi_send_generic_request(struct iscsi_task *task)
 		rc = qedi_send_iscsi_logout(qedi_conn, task);
 		break;
 	case ISCSI_OP_SCSI_TMFUNC:
-		rc = qedi_iscsi_abort_work(qedi_conn, task);
+		rc = qedi_send_iscsi_tmf(qedi_conn, task);
 		break;
 	case ISCSI_OP_TEXT:
 		rc = qedi_send_iscsi_text(qedi_conn, task);
diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h
index 39dc27c85e3c..8a96c1fde630 100644
--- a/drivers/scsi/qedi/qedi_iscsi.h
+++ b/drivers/scsi/qedi/qedi_iscsi.h
@@ -212,6 +212,7 @@ struct qedi_cmd {
 struct qedi_work_map {
 	struct list_head list;
 	struct qedi_cmd *qedi_cmd;
+	struct iscsi_task *task;
 	int rtid;
 
 	int state;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 18/40] scsi: qedi: misc cleanup
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (16 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 17/40] scsi: qedi: cleanup abort handling Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 19/40] scsi: qedi: drop libiscsi itt use Mike Christie
                   ` (22 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Remove some fields/args that are not used.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_fw.c    | 11 +++++------
 drivers/scsi/qedi/qedi_gbl.h   |  3 +--
 drivers/scsi/qedi/qedi_iscsi.h |  2 --
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index d8e10e8d3d08..3357b0ff7dba 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -1218,7 +1218,7 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
 			}
 		}
 		qedi_conn->cmd_cleanup_req++;
-		qedi_iscsi_cleanup_task(ctask, true);
+		qedi_iscsi_cleanup_task(ctask);
 
 		cmd->io_cmd_in_list = false;
 		list_del_init(&cmd->io_cmd);
@@ -1374,15 +1374,14 @@ int qedi_fw_cleanup_cmd(struct iscsi_task *ctask)
 	list_work->rtid = cmd->task_id;
 	list_work->state = QEDI_WORK_SCHEDULED;
 
-	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
-		  "queue tmf work=%p, list node=%p, cid=0x%x\n",
-		  list_work->ptr_tmf_work, list_work, qedi_conn->iscsi_conn_id);
+	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "list node=%p, cid=0x%x\n",
+		  list_work, qedi_conn->iscsi_conn_id);
 
 	spin_lock_bh(&qedi_conn->tmf_work_lock);
 	list_add_tail(&list_work->list, &qedi_conn->tmf_work_list);
 	spin_unlock_bh(&qedi_conn->tmf_work_lock);
 
-	qedi_iscsi_cleanup_task(ctask, false);
+	qedi_iscsi_cleanup_task(ctask);
 
 	rval = qedi_wait_for_cleanup_request(qedi, qedi_conn, ctask, &qedi_cmd,
 					     list_work);
@@ -2114,7 +2113,7 @@ int qedi_iscsi_send_ioreq(struct iscsi_task *task)
 	return 0;
 }
 
-int qedi_iscsi_cleanup_task(struct iscsi_task *task, bool mark_cmd_node_deleted)
+int qedi_iscsi_cleanup_task(struct iscsi_task *task)
 {
 	struct iscsi_task_params task_params;
 	struct qedi_endpoint *ep;
diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h
index a3b72e7ff9d9..098982e6f8a2 100644
--- a/drivers/scsi/qedi/qedi_gbl.h
+++ b/drivers/scsi/qedi/qedi_gbl.h
@@ -40,8 +40,7 @@ int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
 int qedi_iscsi_send_ioreq(struct iscsi_task *task);
 int qedi_get_task_idx(struct qedi_ctx *qedi);
 void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx);
-int qedi_iscsi_cleanup_task(struct iscsi_task *task,
-			    bool mark_cmd_node_deleted);
+int qedi_iscsi_cleanup_task(struct iscsi_task *task);
 void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd);
 void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt,
 			 struct qedi_cmd *qedi_cmd);
diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h
index 8a96c1fde630..5522df952c30 100644
--- a/drivers/scsi/qedi/qedi_iscsi.h
+++ b/drivers/scsi/qedi/qedi_iscsi.h
@@ -219,8 +219,6 @@ struct qedi_work_map {
 #define QEDI_WORK_QUEUED	1
 #define QEDI_WORK_SCHEDULED	2
 #define QEDI_WORK_EXIT		3
-
-	struct work_struct *ptr_tmf_work;
 };
 
 struct qedi_boot_target {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 19/40] scsi: qedi: drop libiscsi itt use
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (17 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 18/40] scsi: qedi: misc cleanup Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 20/40] scsi: qedi: rm unused nr_hw_queues Mike Christie
                   ` (21 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

qedi has several tags:

1. 16 bit hw/fw tag for each low level cq/sq entry.
2. libiscsi itt/tag which comes from libiscsi for each cmd/task.
3. 32 bit iscsi itt/tag used for each iscsi PDU. The driver combines 1
and 2 to form this.

This patch simplifies the driver so we only have #1. Note that in a
future patchset for qedi only we can go further and remove #1 and use
the blk tag.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_fw.c    | 127 ++++++++++++++++-----------------
 drivers/scsi/qedi/qedi_gbl.h   |   4 +-
 drivers/scsi/qedi/qedi_iscsi.h |   3 -
 drivers/scsi/qedi/qedi_main.c  |  22 ++----
 4 files changed, 70 insertions(+), 86 deletions(-)

diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index 3357b0ff7dba..217291e81cdb 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -44,7 +44,6 @@ static void qedi_process_logout_resp(struct qedi_ctx *qedi,
 	resp_hdr->flags = cqe_logout_response->flags;
 	resp_hdr->hlength = 0;
 
-	resp_hdr->itt = build_itt(cqe->cqe_solicited.itid, conn->session->age);
 	resp_hdr->statsn = cpu_to_be32(cqe_logout_response->stat_sn);
 	resp_hdr->exp_cmdsn = cpu_to_be32(cqe_logout_response->exp_cmd_sn);
 	resp_hdr->max_cmdsn = cpu_to_be32(cqe_logout_response->max_cmd_sn);
@@ -71,7 +70,7 @@ static void qedi_process_logout_resp(struct qedi_ctx *qedi,
 
 	cmd->state = RESPONSE_RECEIVED;
 	qedi_clear_task_idx(qedi, cmd->task_id);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)resp_hdr, NULL, 0);
 
 	spin_unlock(&session->back_lock);
 }
@@ -104,8 +103,6 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
 	       (cqe_text_response->hdr_second_dword &
 		ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK));
 
-	resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
-				      conn->session->age);
 	resp_hdr_ptr->ttt = cqe_text_response->ttt;
 	resp_hdr_ptr->statsn = cpu_to_be32(cqe_text_response->stat_sn);
 	resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_text_response->exp_cmd_sn);
@@ -137,10 +134,10 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
 	cmd->state = RESPONSE_RECEIVED;
 	qedi_clear_task_idx(qedi, cmd->task_id);
 
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
-			     qedi_conn->gen_pdu.resp_buf,
-			     (qedi_conn->gen_pdu.resp_wr_ptr -
-			      qedi_conn->gen_pdu.resp_buf));
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)resp_hdr_ptr,
+			    qedi_conn->gen_pdu.resp_buf,
+			    (qedi_conn->gen_pdu.resp_wr_ptr -
+			     qedi_conn->gen_pdu.resp_buf));
 	spin_unlock(&session->back_lock);
 }
 
@@ -170,7 +167,8 @@ static void qedi_tmf_resp_work(struct work_struct *work)
 	qedi_clear_task_idx(qedi, qedi_cmd->task_id);
 
 	spin_lock(&session->back_lock);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
+	iscsi_complete_task(conn, qedi_cmd->task,
+			    (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
 	spin_unlock(&session->back_lock);
 
 exit_tmf_resp:
@@ -215,8 +213,6 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
 	hton24(resp_hdr_ptr->dlength,
 	       (cqe_tmp_response->hdr_second_dword &
 		ISCSI_TMF_RESPONSE_HDR_DATA_SEG_LEN_MASK));
-	resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
-				      conn->session->age);
 	resp_hdr_ptr->statsn = cpu_to_be32(cqe_tmp_response->stat_sn);
 	resp_hdr_ptr->exp_cmdsn  = cpu_to_be32(cqe_tmp_response->exp_cmd_sn);
 	resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_tmp_response->max_cmd_sn);
@@ -244,7 +240,8 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
 
 	qedi_clear_task_idx(qedi, qedi_cmd->task_id);
 
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
+	iscsi_complete_task(conn, qedi_cmd->task,
+			    (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
 	kfree(resp_hdr_ptr);
 
 unblock_sess:
@@ -279,8 +276,6 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
 	hton24(resp_hdr_ptr->dlength,
 	       (cqe_login_response->hdr_second_dword &
 		ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK));
-	resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
-				      conn->session->age);
 	resp_hdr_ptr->tsih = cqe_login_response->tsih;
 	resp_hdr_ptr->statsn = cpu_to_be32(cqe_login_response->stat_sn);
 	resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_login_response->exp_cmd_sn);
@@ -301,9 +296,9 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
 
 	memset(task_ctx, '\0', sizeof(*task_ctx));
 
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
-			     qedi_conn->gen_pdu.resp_buf,
-			     (qedi_conn->gen_pdu.resp_wr_ptr -
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)resp_hdr_ptr,
+			    qedi_conn->gen_pdu.resp_buf,
+			    (qedi_conn->gen_pdu.resp_wr_ptr -
 			     qedi_conn->gen_pdu.resp_buf));
 
 	spin_unlock(&session->back_lock);
@@ -448,8 +443,6 @@ static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
 	if (task) {
 		cmd = task->dd_data;
 		hdr->flags = ISCSI_FLAG_CMD_FINAL;
-		hdr->itt = build_itt(cqe->cqe_solicited.itid,
-				     conn->session->age);
 		lun[0] = 0xffffffff;
 		lun[1] = 0xffffffff;
 		memcpy(&hdr->lun, lun, sizeof(struct scsi_lun));
@@ -469,7 +462,8 @@ static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
 	}
 
 done:
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, bdq_data, pdu_len);
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)hdr, bdq_data,
+			    pdu_len);
 
 	spin_unlock_bh(&session->back_lock);
 	return tgt_async_nop;
@@ -477,7 +471,6 @@ static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
 
 static void qedi_process_async_mesg(struct qedi_ctx *qedi,
 				    union iscsi_cqe *cqe,
-				    struct iscsi_task *task,
 				    struct qedi_conn *qedi_conn,
 				    u16 que_idx)
 {
@@ -523,15 +516,14 @@ static void qedi_process_async_mesg(struct qedi_ctx *qedi,
 	resp_hdr->param2 = cpu_to_be16(cqe_async_msg->param2_rsrv);
 	resp_hdr->param3 = cpu_to_be16(cqe_async_msg->param3_rsrv);
 
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, bdq_data,
-			     pdu_len);
+	iscsi_complete_task(conn, NULL, (struct iscsi_hdr *)resp_hdr, bdq_data,
+			    pdu_len);
 
 	spin_unlock_bh(&session->back_lock);
 }
 
 static void qedi_process_reject_mesg(struct qedi_ctx *qedi,
 				     union iscsi_cqe *cqe,
-				     struct iscsi_task *task,
 				     struct qedi_conn *qedi_conn,
 				     uint16_t que_idx)
 {
@@ -566,8 +558,8 @@ static void qedi_process_reject_mesg(struct qedi_ctx *qedi,
 	hdr->statsn = cpu_to_be32(cqe_reject->stat_sn);
 	hdr->ffffffff = cpu_to_be32(0xffffffff);
 
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
-			     conn->data, pld_len);
+	iscsi_complete_task(conn, NULL, (struct iscsi_hdr *)hdr, conn->data,
+			    pld_len);
 	spin_unlock_bh(&session->back_lock);
 }
 
@@ -628,7 +620,6 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 	hdr->opcode = cqe_data_in->opcode;
 	hdr->max_cmdsn = cpu_to_be32(cqe_data_in->max_cmd_sn);
 	hdr->exp_cmdsn = cpu_to_be32(cqe_data_in->exp_cmd_sn);
-	hdr->itt = build_itt(cqe->cqe_solicited.itid, conn->session->age);
 	hdr->response = cqe_data_in->reserved1;
 	hdr->cmd_status = cqe_data_in->status_rsvd;
 	hdr->flags = cqe_data_in->flags;
@@ -647,7 +638,7 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 		     GET_FIELD(cqe_err_bits, CQE_ERROR_BITMAP_UNDER_RUN_ERR))) {
 		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
 			  "Under flow itt=0x%x proto flags=0x%x tid=0x%x cid 0x%x fw resid 0x%x sc dlen 0x%x\n",
-			  hdr->itt, cqe_data_in->flags, cmd->task_id,
+			  task->itt, cqe_data_in->flags, cmd->task_id,
 			  qedi_conn->iscsi_conn_id, hdr->residual_count,
 			  scsi_bufflen(sc_cmd));
 		hdr->residual_count = cpu_to_be32(scsi_bufflen(sc_cmd));
@@ -671,8 +662,8 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 		qedi_trace_io(qedi, task, cmd->task_id, QEDI_IO_TRACE_RSP);
 
 	qedi_clear_task_idx(qedi, cmd->task_id);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
-			     conn->data, datalen);
+	iscsi_complete_task(conn, task, (struct iscsi_hdr *)hdr, conn->data,
+			    datalen);
 error:
 	spin_unlock_bh(&session->back_lock);
 }
@@ -740,15 +731,13 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 {
 	struct qedi_work_map *work, *work_tmp;
 	u32 proto_itt = cqe->itid;
-	u32 ptmp_itt = 0;
-	itt_t protoitt = 0;
 	int found = 0;
 	struct qedi_cmd *qedi_cmd = NULL;
 	u32 rtid = 0;
 	u32 iscsi_cid;
 	struct qedi_conn *qedi_conn;
 	struct qedi_cmd *dbg_cmd;
-	struct iscsi_task *task;
+	struct iscsi_task *task = NULL;
 
 	iscsi_cid = cqe->conn_id;
 	qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
@@ -809,16 +798,20 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 		qedi_cmd->state = CLEANUP_RECV;
 		wake_up_interruptible(&qedi_conn->wait_queue);
 	} else if (qedi_conn->cmd_cleanup_req > 0) {
-		spin_lock_bh(&conn->session->back_lock);
-		qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt);
-		protoitt = build_itt(ptmp_itt, conn->session->age);
-		task = iscsi_itt_to_task(conn, protoitt);
+		dbg_cmd = qedi_get_cmd_from_tid(qedi, cqe->itid, true);
+		if (dbg_cmd) {
+			/*
+			 * We don't have a ref to the task so this is just used
+			 * as a hint.
+			 */
+			task = dbg_cmd->task;
+		}
+
 		QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
-			  "cleanup io itid=0x%x, protoitt=0x%x, cmd_cleanup_cmpl=%d, cid=0x%x\n",
-			  cqe->itid, protoitt, qedi_conn->cmd_cleanup_cmpl,
+			  "cleanup io itid=0x%x, cmd_cleanup_cmpl=%d, cid=0x%x\n",
+			  cqe->itid, qedi_conn->cmd_cleanup_cmpl,
 			  qedi_conn->iscsi_conn_id);
 
-		spin_unlock_bh(&conn->session->back_lock);
 		if (!task) {
 			QEDI_NOTICE(&qedi->dbg_ctx,
 				    "task is null, itid=0x%x, cid=0x%x\n",
@@ -834,12 +827,18 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 		qedi_clear_task_idx(qedi_conn->qedi, cqe->itid);
 
 	} else {
-		qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt);
-		protoitt = build_itt(ptmp_itt, conn->session->age);
-		task = iscsi_itt_to_task(conn, protoitt);
+		dbg_cmd = qedi_get_cmd_from_tid(qedi, cqe->itid, false);
+		if (dbg_cmd) {
+			/*
+			 * We don't have a ref to the task so this is just used
+			 * for debugging.
+			 */
+			task = dbg_cmd->task;
+		}
+
 		QEDI_ERR(&qedi->dbg_ctx,
-			 "Delayed or untracked cleanup response, itt=0x%x, tid=0x%x, cid=0x%x, task=%p\n",
-			 protoitt, cqe->itid, qedi_conn->iscsi_conn_id, task);
+			 "Delayed or untracked cleanup response, tid=0x%x, cid=0x%x, task=%p\n",
+			 cqe->itid, qedi_conn->iscsi_conn_id, task);
 	}
 }
 
@@ -907,8 +906,6 @@ void qedi_fp_process_cqes(struct qedi_work *work)
 			qedi_process_nopin_local_cmpl(qedi, &cqe->cqe_solicited,
 						      task, q_conn);
 		} else {
-			cqe->cqe_solicited.itid =
-					       qedi_get_itt(cqe->cqe_solicited);
 			/* Process other solicited responses */
 			qedi_mtask_completion(qedi, cqe, task, q_conn, que_idx);
 		}
@@ -916,16 +913,14 @@ void qedi_fp_process_cqes(struct qedi_work *work)
 	case ISCSI_CQE_TYPE_UNSOLICITED:
 		switch (hdr_opcode) {
 		case ISCSI_OPCODE_NOP_IN:
-			qedi_process_nopin_mesg(qedi, cqe, task, q_conn,
+			qedi_process_nopin_mesg(qedi, cqe, NULL, q_conn,
 						que_idx);
 			break;
 		case ISCSI_OPCODE_ASYNC_MSG:
-			qedi_process_async_mesg(qedi, cqe, task, q_conn,
-						que_idx);
+			qedi_process_async_mesg(qedi, cqe, q_conn, que_idx);
 			break;
 		case ISCSI_OPCODE_REJECT:
-			qedi_process_reject_mesg(qedi, cqe, task, q_conn,
-						 que_idx);
+			qedi_process_reject_mesg(qedi, cqe, q_conn, que_idx);
 			break;
 		}
 		goto exit_fp_process;
@@ -1035,8 +1030,8 @@ int qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
 	login_req_pdu_header.tsih = login_hdr->tsih;
 	login_req_pdu_header.hdr_second_dword = ntoh24(login_hdr->dlength);
 
-	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
-	login_req_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
+	qedi_update_itt_map(qedi, tid, qedi_cmd);
+	login_req_pdu_header.itt = tid;
 	login_req_pdu_header.cid = qedi_conn->iscsi_conn_id;
 	login_req_pdu_header.cmd_sn = be32_to_cpu(login_hdr->cmdsn);
 	login_req_pdu_header.exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
@@ -1129,8 +1124,8 @@ int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
 	/* Update header info */
 	logout_pdu_header.opcode = logout_hdr->opcode;
 	logout_pdu_header.reason_code = 0x80 | logout_hdr->flags;
-	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
-	logout_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
+	qedi_update_itt_map(qedi, tid, qedi_cmd);
+	logout_pdu_header.itt = tid;
 	logout_pdu_header.exp_stat_sn = be32_to_cpu(logout_hdr->exp_statsn);
 	logout_pdu_header.cmd_sn = be32_to_cpu(logout_hdr->cmdsn);
 	logout_pdu_header.cid = qedi_conn->iscsi_conn_id;
@@ -1464,8 +1459,8 @@ int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask)
 	memset(&tmf_pdu_header, 0, sizeof(tmf_pdu_header));
 
 	/* Update header info */
-	qedi_update_itt_map(qedi, tid, mtask->itt, qedi_cmd);
-	tmf_pdu_header.itt = qedi_set_itt(tid, get_itt(mtask->itt));
+	qedi_update_itt_map(qedi, tid, qedi_cmd);
+	tmf_pdu_header.itt = tid;
 	tmf_pdu_header.cmd_sn = be32_to_cpu(tmf_hdr->cmdsn);
 
 	memcpy(scsi_lun, &tmf_hdr->lun, sizeof(struct scsi_lun));
@@ -1481,9 +1476,7 @@ int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask)
 			return 0;
 		}
 		cmd = (struct qedi_cmd *)ctask->dd_data;
-		tmf_pdu_header.rtt =
-				qedi_set_itt(cmd->task_id,
-					     get_itt(tmf_hdr->rtt));
+		tmf_pdu_header.rtt = cmd->task_id;
 	} else {
 		tmf_pdu_header.rtt = ISCSI_RESERVED_TAG;
 	}
@@ -1564,8 +1557,8 @@ int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
 	text_request_pdu_header.opcode = text_hdr->opcode;
 	text_request_pdu_header.flags_attr = text_hdr->flags;
 
-	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
-	text_request_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
+	qedi_update_itt_map(qedi, tid, qedi_cmd);
+	text_request_pdu_header.itt = tid;
 	text_request_pdu_header.ttt = text_hdr->ttt;
 	text_request_pdu_header.cmd_sn = be32_to_cpu(text_hdr->cmdsn);
 	text_request_pdu_header.exp_stat_sn = be32_to_cpu(text_hdr->exp_statsn);
@@ -1670,13 +1663,13 @@ int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
 	nop_out_pdu_header.cmd_sn = be32_to_cpu(nopout_hdr->cmdsn);
 	nop_out_pdu_header.exp_stat_sn = be32_to_cpu(nopout_hdr->exp_statsn);
 
-	qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd);
+	qedi_update_itt_map(qedi, tid, qedi_cmd);
 
 	if (nopout_hdr->ttt != ISCSI_TTT_ALL_ONES) {
 		nop_out_pdu_header.itt = be32_to_cpu(nopout_hdr->itt);
 		nop_out_pdu_header.ttt = be32_to_cpu(nopout_hdr->ttt);
 	} else {
-		nop_out_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
+		nop_out_pdu_header.itt = tid;
 		nop_out_pdu_header.ttt = ISCSI_TTT_ALL_ONES;
 
 		spin_lock(&qedi_conn->list_lock);
@@ -2025,8 +2018,8 @@ int qedi_iscsi_send_ioreq(struct iscsi_task *task)
 	cmd_pdu_header.lun.lo = be32_to_cpu(scsi_lun[0]);
 	cmd_pdu_header.lun.hi = be32_to_cpu(scsi_lun[1]);
 
-	qedi_update_itt_map(qedi, tid, task->itt, cmd);
-	cmd_pdu_header.itt = qedi_set_itt(tid, get_itt(task->itt));
+	qedi_update_itt_map(qedi, tid, cmd);
+	cmd_pdu_header.itt = tid;
 	cmd_pdu_header.expected_transfer_length = cpu_to_be32(hdr->data_length);
 	cmd_pdu_header.hdr_second_dword = ntoh24(hdr->dlength);
 	cmd_pdu_header.cmd_sn = be32_to_cpu(hdr->cmdsn);
diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h
index 098982e6f8a2..4222d693c095 100644
--- a/drivers/scsi/qedi/qedi_gbl.h
+++ b/drivers/scsi/qedi/qedi_gbl.h
@@ -38,11 +38,13 @@ int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
 			   struct iscsi_task *task,
 			   char *datap, int data_len, int unsol);
 int qedi_iscsi_send_ioreq(struct iscsi_task *task);
+struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid,
+				       bool clear_mapping);
 int qedi_get_task_idx(struct qedi_ctx *qedi);
 void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx);
 int qedi_iscsi_cleanup_task(struct iscsi_task *task);
 void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd);
-void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt,
+void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid,
 			 struct qedi_cmd *qedi_cmd);
 void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt);
 void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, int16_t *tid);
diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h
index 5522df952c30..662e7380a14c 100644
--- a/drivers/scsi/qedi/qedi_iscsi.h
+++ b/drivers/scsi/qedi/qedi_iscsi.h
@@ -227,9 +227,6 @@ struct qedi_boot_target {
 	u32 ipv6_en;
 };
 
-#define qedi_set_itt(task_id, itt) ((u32)(((task_id) & 0xffff) | ((itt) << 16)))
-#define qedi_get_itt(cqe) (cqe.iscsi_hdr.cmd.itt >> 16)
-
 #define QEDI_OFLD_WAIT_STATE(q) ((q)->state == EP_STATE_OFLDCONN_FAILED || \
 				(q)->state == EP_STATE_OFLDCONN_COMPL)
 
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 0aa0061dad40..f10739148080 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -62,7 +62,6 @@ static LIST_HEAD(qedi_udev_list);
 /* Static function declaration */
 static int qedi_alloc_global_queues(struct qedi_ctx *qedi);
 static void qedi_free_global_queues(struct qedi_ctx *qedi);
-static struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid);
 static void qedi_reset_uio_rings(struct qedi_uio_dev *udev);
 static void qedi_ll2_free_skbs(struct qedi_ctx *qedi);
 static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi);
@@ -1223,7 +1222,8 @@ static int qedi_queue_cqe(struct qedi_ctx *qedi, union iscsi_cqe *cqe,
 	switch (cqe->cqe_common.cqe_type) {
 	case ISCSI_CQE_TYPE_SOLICITED:
 	case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE:
-		qedi_cmd = qedi_get_cmd_from_tid(qedi, cqe->cqe_solicited.itid);
+		qedi_cmd = qedi_get_cmd_from_tid(qedi, cqe->cqe_solicited.itid,
+						 true);
 		if (!qedi_cmd) {
 			rc = -1;
 			break;
@@ -1850,10 +1850,8 @@ void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx)
 			 "FW task context, already cleared, tid=0x%x\n", idx);
 }
 
-void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt,
-			 struct qedi_cmd *cmd)
+void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, struct qedi_cmd *cmd)
 {
-	qedi->itt_map[tid].itt = proto_itt;
 	qedi->itt_map[tid].p_cmd = cmd;
 
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
@@ -1878,15 +1876,8 @@ void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid)
 	WARN_ON(1);
 }
 
-void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt)
-{
-	*proto_itt = qedi->itt_map[tid].itt;
-	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
-		  "Get itt map tid [0x%x with proto itt[0x%x]",
-		  tid, *proto_itt);
-}
-
-struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid)
+struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid,
+				       bool clear_mapping)
 {
 	struct qedi_cmd *cmd = NULL;
 
@@ -1897,7 +1888,8 @@ struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid)
 	if (cmd->task_id != tid)
 		return NULL;
 
-	qedi->itt_map[tid].p_cmd = NULL;
+	if (clear_mapping)
+		qedi->itt_map[tid].p_cmd = NULL;
 
 	return cmd;
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 20/40] scsi: qedi: rm unused nr_hw_queues
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (18 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 19/40] scsi: qedi: drop libiscsi itt use Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 21/40] scsi: iscsi: use blk/scsi-ml mq cmd pre-allocator Mike Christie
                   ` (20 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

nr_hw_queues is always 1, because qedi set the num cqs after
qedi_host_alloc. It's a simple change to move this to before we do
scsi_add_host, but setting it seems to drop performance. It looks like the
problem is that there 3 locks in the main IO path, so we bash on them even
when nr_hw_queues > 1.

This patch just drops it for now why we work on removing those locks.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_main.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index f10739148080..cb792020b8be 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -656,8 +656,6 @@ static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev)
 	qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA;
 	qedi->max_sqes = QEDI_SQ_SIZE;
 
-	shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi);
-
 	pci_set_drvdata(pdev, qedi);
 
 exit_setup_shost:
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 21/40] scsi: iscsi: use blk/scsi-ml mq cmd pre-allocator
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (19 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 20/40] scsi: qedi: rm unused nr_hw_queues Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 22/40] scsi: libiscsi: remove ISCSI_TASK_ABRT_SESS_RECOV Mike Christie
                   ` (19 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This has us use the blk/scsi-ml mq cmd pre-allocator and blk tags for scsi
tasks. We now do not need the back/frwd locks for scsi task allocation.
We still need it for mgmt tasks, but that will be fixed in the next patches.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/cxgbi/libcxgbi.c |   2 +-
 drivers/scsi/libiscsi.c       | 151 +++++++++++++++++++---------------
 include/scsi/libiscsi.h       |  46 +++++++----
 3 files changed, 116 insertions(+), 83 deletions(-)

diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 919451810018..cdaa67fd8c2e 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -366,7 +366,7 @@ int cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun,
 		chba->ndev = cdev->ports[i];
 		chba->shost = shost;
 
-		shost->can_queue = sht->can_queue - ISCSI_MGMT_CMDS_MAX;
+		shost->can_queue = sht->can_queue - ISCSI_INFLIGHT_MGMT_MAX;
 
 		log_debug(1 << CXGBI_DBG_DEV,
 			"cdev 0x%p, p#%d %s: chba 0x%p.\n",
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index cadbe1d19344..46ab51e5a87b 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -463,9 +463,9 @@ static void iscsi_free_task(struct iscsi_task *task)
 	if (conn->login_task == task)
 		return;
 
-	kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
-
-	if (sc) {
+	if (!sc) {
+		kfifo_in(&session->mgmt_pool.queue, (void *)&task, sizeof(void *));
+	} else {
 		/* SCSI eh reuses commands to verify us */
 		sc->SCp.ptr = NULL;
 		/*
@@ -716,8 +716,8 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
 		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
-		if (!kfifo_out(&session->cmdpool.queue,
-				 (void*)&task, sizeof(void*)))
+		if (!kfifo_out(&session->mgmt_pool.queue, (void *)&task,
+			       sizeof(void *)))
 			return NULL;
 	}
 	/*
@@ -1118,7 +1118,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 {
 	struct iscsi_session *session = conn->session;
-	int i;
+	uint32_t i;
 
 	if (itt == RESERVED_ITT)
 		return NULL;
@@ -1127,10 +1127,17 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 		session->tt->parse_pdu_itt(conn, itt, &i, NULL);
 	else
 		i = get_itt(itt);
-	if (i >= session->cmds_max)
-		return NULL;
 
-	return session->cmds[i];
+	if (i & ISCSI_TASK_TYPE_MGMT) {
+		i &= ~ISCSI_TASK_TYPE_MGMT;
+
+		if (i >= ISCSI_MGMT_CMDS_MAX)
+			return NULL;
+
+		return session->mgmt_cmds[i];
+	} else {
+		return iscsi_itt_to_ctask(conn, itt);
+	}
 }
 EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
 
@@ -1348,12 +1355,6 @@ int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
 		return ISCSI_ERR_BAD_ITT;
 	}
 
-	if (i >= session->cmds_max) {
-		iscsi_conn_printk(KERN_ERR, conn,
-				  "received invalid itt index %u (max cmds "
-				   "%u.\n", i, session->cmds_max);
-		return ISCSI_ERR_BAD_ITT;
-	}
 	return 0;
 }
 EXPORT_SYMBOL_GPL(iscsi_verify_itt);
@@ -1369,19 +1370,30 @@ EXPORT_SYMBOL_GPL(iscsi_verify_itt);
  */
 struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
 {
+	struct iscsi_session *session = conn->session;
 	struct iscsi_task *task;
+	struct scsi_cmnd *sc;
+	int tag;
 
 	if (iscsi_verify_itt(conn, itt))
 		return NULL;
 
-	task = iscsi_itt_to_task(conn, itt);
-	if (!task || !task->sc)
+	if (session->tt->parse_pdu_itt)
+		session->tt->parse_pdu_itt(conn, itt, &tag, NULL);
+	else
+		tag = get_itt(itt);
+	sc = scsi_host_find_tag(session->host, tag);
+	if (!sc)
 		return NULL;
 
-	if (task->sc->SCp.phase != conn->session->age) {
+	task = scsi_cmd_priv(sc);
+	if (!task->sc)
+		return NULL;
+
+	if (task->sc->SCp.phase != session->age) {
 		iscsi_session_printk(KERN_ERR, conn->session,
 				  "task's session age %d, expected %d\n",
-				  task->sc->SCp.phase, conn->session->age);
+				  task->sc->SCp.phase, session->age);
 		return NULL;
 	}
 
@@ -1679,19 +1691,16 @@ static void iscsi_xmitworker(struct work_struct *work)
 	} while (rc >= 0 || rc == -EAGAIN);
 }
 
-static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
-						  struct scsi_cmnd *sc)
+static struct iscsi_task *iscsi_init_scsi_task(struct iscsi_conn *conn,
+					       struct scsi_cmnd *sc)
 {
-	struct iscsi_task *task;
-
-	if (!kfifo_out(&conn->session->cmdpool.queue,
-			 (void *) &task, sizeof(void *)))
-		return NULL;
+	struct iscsi_task *task = scsi_cmd_priv(sc);
 
 	sc->SCp.phase = conn->session->age;
 	sc->SCp.ptr = (char *) task;
 
 	refcount_set(&task->refcount, 1);
+	task->itt = blk_mq_unique_tag(sc->request);
 	task->state = ISCSI_TASK_PENDING;
 	task->conn = conn;
 	task->sc = sc;
@@ -1805,12 +1814,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 		goto reject;
 	}
 
-	task = iscsi_alloc_task(conn, sc);
-	if (!task) {
-		spin_unlock_bh(&session->frwd_lock);
-		reason = FAILURE_OOM;
-		goto reject;
-	}
+	task = iscsi_init_scsi_task(conn, sc);
 
 	if (!ihost->workq) {
 		reason = iscsi_prep_scsi_cmd_pdu(task);
@@ -2745,9 +2749,8 @@ int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,
 	if (!total_cmds)
 		total_cmds = ISCSI_DEF_XMIT_CMDS_MAX;
 	/*
-	 * The iscsi layer needs some tasks for nop handling and tmfs,
-	 * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX
-	 * + 1 command for scsi IO.
+	 * The iscsi layer needs some tasks for nop handling and tmfs, so the
+	 * cmds_max must at least be greater than ISCSI_INFLIGHT_MGMT_MAX
 	 */
 	if (total_cmds < ISCSI_TOTAL_CMDS_MIN) {
 		printk(KERN_ERR "iscsi: invalid max cmds of %d. Must be a power of two that is at least %d.\n",
@@ -2773,7 +2776,7 @@ int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,
 		       requested_cmds_max, total_cmds);
 	}
 
-	scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
+	scsi_cmds = total_cmds - ISCSI_INFLIGHT_MGMT_MAX;
 	if (shost->can_queue && scsi_cmds > shost->can_queue) {
 		total_cmds = shost->can_queue;
 
@@ -2799,9 +2802,25 @@ int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
 	if (!shost->can_queue)
 		shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
 
+	if (shost->can_queue > ISCSI_TOTAL_CMDS_MAX) {
+		shost_printk(KERN_INFO, shost,
+			     "Requested scsi host can_queue was %u. Limiting to %u\n",
+			     shost->can_queue, ISCSI_TOTAL_CMDS_MAX);
+		shost->can_queue = ISCSI_TOTAL_CMDS_MAX;
+	}
+
 	if (!shost->cmd_per_lun)
 		shost->cmd_per_lun = ISCSI_DEF_CMD_PER_LUN;
 
+	shost->host_tagset = 1;
+	/*
+	 * We currently do not support nr_hw_queues >  1 because the iscsi spec
+	 * itt is limited to 32 bits, and for drivers that support it, libiscsi
+	 * uses some of the bits past BLK_MQ_UNIQUE_TAG_BITS for target sanity
+	 * checks. Plus other drivers/fw can limit the itt to less than 16 bits.
+	 */
+	BUG_ON(shost->nr_hw_queues > 1);
+
 	return scsi_add_host(shost, pdev);
 }
 EXPORT_SYMBOL_GPL(iscsi_host_add);
@@ -2914,9 +2933,11 @@ static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
 	scsi_host_put(shost);
 }
 
-static void iscsi_init_task(struct iscsi_task *task)
+static void iscsi_init_task(struct iscsi_task *task, int dd_task_size)
 {
 	task->dd_data = &task[1];
+	if (dd_task_size > 0)
+		memset(task->dd_data, 0, dd_task_size);
 	task->itt = ISCSI_RESERVED_TAG;
 	task->state = ISCSI_TASK_FREE;
 	INIT_LIST_HEAD(&task->running);
@@ -2926,7 +2947,7 @@ int iscsi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
 {
 	struct iscsi_task *task = scsi_cmd_priv(sc);
 
-	iscsi_init_task(task);
+	iscsi_init_task(task, shost->hostt->cmd_size - sizeof(*task));
 	return 0;
 }
 EXPORT_SYMBOL_GPL(iscsi_init_cmd_priv);
@@ -2945,8 +2966,8 @@ EXPORT_SYMBOL_GPL(iscsi_init_cmd_priv);
  * a session per scsi host.
  *
  * Callers should set cmds_max to the largest total numer (mgmt + scsi) of
- * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks
- * for nop handling and login/logout requests.
+ * tasks they support. The iscsi layer reserves ISCSI_INFLIGHT_MGMT_MAX
+ * tasks for nop handling and login/logout requests.
  */
 struct iscsi_cls_session *
 iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
@@ -2985,7 +3006,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 	session->lu_reset_timeout = 15;
 	session->abort_timeout = 10;
 	session->scsi_cmds_max = scsi_cmds;
-	session->cmds_max = scsi_cmds + ISCSI_MGMT_CMDS_MAX;
+	session->cmds_max = scsi_cmds + ISCSI_INFLIGHT_MGMT_MAX;
 	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
 	session->exp_cmdsn = initial_cmdsn + 1;
 	session->max_cmdsn = initial_cmdsn + 1;
@@ -2997,21 +3018,18 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 	spin_lock_init(&session->frwd_lock);
 	spin_lock_init(&session->back_lock);
 
-	/* initialize SCSI PDU commands pool */
-	if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
-			    (void***)&session->cmds,
+	/* initialize mgmt task pool */
+	if (iscsi_pool_init(&session->mgmt_pool, ISCSI_MGMT_CMDS_MAX,
+			    (void ***)&session->mgmt_cmds,
 			    cmd_task_size + sizeof(struct iscsi_task)))
-		goto cmdpool_alloc_fail;
+		goto mgmt_pool_alloc_fail;
 
 	/* pre-format cmds pool with ITT */
-	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
-		struct iscsi_task *task = session->cmds[cmd_i];
+	for (cmd_i = 0; cmd_i < ISCSI_MGMT_CMDS_MAX; cmd_i++) {
+		struct iscsi_task *task = session->mgmt_cmds[cmd_i];
 
-		if (cmd_task_size)
-			task->dd_data = &task[1];
-		task->itt = cmd_i;
-		task->state = ISCSI_TASK_FREE;
-		INIT_LIST_HEAD(&task->running);
+		iscsi_init_task(task, cmd_task_size);
+		task->itt = cmd_i | ISCSI_TASK_TYPE_MGMT;
 
 		if (iscsit->alloc_task_priv) {
 			if (iscsit->alloc_task_priv(session, task))
@@ -3032,11 +3050,11 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 free_task_priv:
 	for (cmd_i--; cmd_i >= 0; cmd_i--) {
 		if (iscsit->free_task_priv)
-			iscsit->free_task_priv(session, session->cmds[cmd_i]);
+			iscsit->free_task_priv(session, session->mgmt_cmds[cmd_i]);
 	}
 
-	iscsi_pool_free(&session->cmdpool);
-cmdpool_alloc_fail:
+	iscsi_pool_free(&session->mgmt_pool);
+mgmt_pool_alloc_fail:
 	iscsi_free_session(cls_session);
 dec_session_count:
 	iscsi_host_dec_session_cnt(shost);
@@ -3055,13 +3073,13 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
 	struct Scsi_Host *shost = session->host;
 	int cmd_i;
 
-	for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
+	for (cmd_i = 0; cmd_i < ISCSI_MGMT_CMDS_MAX; cmd_i++) {
 		if (session->tt->free_task_priv)
 			session->tt->free_task_priv(session,
-						    session->cmds[cmd_i]);
+						    session->mgmt_cmds[cmd_i]);
 	}
 
-	iscsi_pool_free(&session->cmdpool);
+	iscsi_pool_free(&session->mgmt_pool);
 
 	iscsi_remove_session(cls_session);
 
@@ -3125,9 +3143,8 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
 
 	/* allocate login_task used for the login/text sequences */
 	spin_lock_bh(&session->frwd_lock);
-	if (!kfifo_out(&session->cmdpool.queue,
-                         (void*)&conn->login_task,
-			 sizeof(void*))) {
+	if (!kfifo_out(&session->mgmt_pool.queue, (void *)&conn->login_task,
+		       sizeof(void *))) {
 		spin_unlock_bh(&session->frwd_lock);
 		goto login_task_alloc_fail;
 	}
@@ -3145,8 +3162,8 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
 	return cls_conn;
 
 login_task_data_alloc_fail:
-	kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-		    sizeof(void*));
+	kfifo_in(&session->mgmt_pool.queue, (void *)&conn->login_task,
+		 sizeof(void *));
 login_task_alloc_fail:
 	iscsi_destroy_conn(cls_conn);
 	return NULL;
@@ -3189,8 +3206,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 	kfree(conn->local_ipaddr);
 	/* regular RX path uses back_lock */
 	spin_lock_bh(&session->back_lock);
-	kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
-		    sizeof(void*));
+	kfifo_in(&session->mgmt_pool.queue, (void *)&conn->login_task,
+		 sizeof(void *));
 	spin_unlock_bh(&session->back_lock);
 	if (session->leadconn == conn)
 		session->leadconn = NULL;
@@ -3275,8 +3292,8 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
 	struct iscsi_task *task;
 	int i, state;
 
-	for (i = 0; i < conn->session->cmds_max; i++) {
-		task = conn->session->cmds[i];
+	for (i = 0; i < ISCSI_MGMT_CMDS_MAX; i++) {
+		task = conn->session->mgmt_cmds[i];
 		if (task->sc)
 			continue;
 
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 8e01beba62f1..7a78f8c5d670 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -35,8 +35,18 @@ struct iscsi_session;
 struct iscsi_nopin;
 struct device;
 
-#define ISCSI_DEF_XMIT_CMDS_MAX	128	/* must be power of 2 */
-#define ISCSI_MGMT_CMDS_MAX	15
+#define ISCSI_DEF_XMIT_CMDS_MAX		128
+/*
+ * Max number of mgmt cmds we will preallocate and add to our mgmt fifo.
+ * This must be a pow of 2 due to the kfifo use.
+ */
+#define ISCSI_MGMT_CMDS_MAX		16
+/*
+ * For userspace compat we must allow at least 16 total cmds, so we have the
+ * the mgmt allocation limit above and this limit is the number of mgmt cmds
+ * that can be running.
+ */
+#define ISCSI_INFLIGHT_MGMT_MAX		15
 
 #define ISCSI_DEF_CMD_PER_LUN	32
 
@@ -55,10 +65,19 @@ enum {
 /* Connection suspend "bit" */
 #define ISCSI_SUSPEND_BIT		1
 
-#define ISCSI_ITT_MASK			0x1fff
-#define ISCSI_TOTAL_CMDS_MAX		4096
-/* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */
-#define ISCSI_TOTAL_CMDS_MIN		16
+/*
+ * Note:
+ * - bnx2i needs the tag to be <= 0x3fff to fit in its fw req, and has a
+ *   different itt space for scsi and mgmt cmds.
+ * - cxgbi assumes the tag will be at most 0x7fff.
+ * - iser needs the total cmds to be a pow of 2.
+ * - qedi, qla4xxx and be2iscsi ignore or pass through the libiscsi itt.
+ */
+#define ISCSI_ITT_MASK			0x3fff
+#define ISCSI_TOTAL_CMDS_MAX		8192
+/* bit 14 is set for MGMT tasks and cleared for scsi cmds */
+#define ISCSI_TASK_TYPE_MGMT		0x2000
+#define ISCSI_TOTAL_CMDS_MIN		(ISCSI_INFLIGHT_MGMT_MAX + 1)
 #define ISCSI_AGE_SHIFT			28
 #define ISCSI_AGE_MASK			0xf
 
@@ -331,13 +350,10 @@ struct iscsi_session {
 	spinlock_t		frwd_lock;	/* protects queued_cmdsn,  *
 						 * cmdsn, suspend_bit,     *
 						 * leadconn, _stage,       *
-						 * tmf_state and session   *
-						 * resources:              *
-						 * - cmdpool kfifo_out ,   *
-						 * - mgmtpool, queues	   */
+						 * tmf_state and mgmt      *
+						 * queues                  */
 	spinlock_t		back_lock;	/* protects cmdsn_exp      *
-						 * cmdsn_max,              *
-						 * cmdpool kfifo_in        */
+						 * cmdsn_max, mgmt queues  */
 	/*
 	 * frwd_lock must be held when transitioning states, but not needed
 	 * if just checking the state in the scsi-ml or iscsi callouts.
@@ -346,9 +362,9 @@ struct iscsi_session {
 	int			age;		/* counts session re-opens */
 
 	int			scsi_cmds_max; 	/* max scsi commands */
-	int			cmds_max;	/* size of cmds array */
-	struct iscsi_task	**cmds;		/* Original Cmds arr */
-	struct iscsi_pool	cmdpool;	/* PDU's pool */
+	int			cmds_max;	/* Total number of tasks */
+	struct iscsi_task	**mgmt_cmds;
+	struct iscsi_pool	mgmt_pool;	/* mgmt task pool */
 	void			*dd_data;	/* LLD private data */
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 22/40] scsi: libiscsi: remove ISCSI_TASK_ABRT_SESS_RECOV
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (20 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 21/40] scsi: iscsi: use blk/scsi-ml mq cmd pre-allocator Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 23/40] scsi: libiscsi: remove ISCSI_TASK_REQUEUE_SCSIQ Mike Christie
                   ` (18 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The next patches simplfy the task state, so we can more easily use it to
detect if a command completed without the back lock becuase that is being
removed. This patch removes ISCSI_TASK_ABRT_SESS_RECOV since no one checks
for it and only cares if the command has completed.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 5 ++---
 include/scsi/libiscsi.h | 1 -
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 46ab51e5a87b..e2f3217afdc9 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -517,7 +517,6 @@ static void iscsi_finish_task(struct iscsi_task *task, int state)
 			  task->itt, task->state, task->sc);
 	if (task->state == ISCSI_TASK_COMPLETED ||
 	    task->state == ISCSI_TASK_ABRT_TMF ||
-	    task->state == ISCSI_TASK_ABRT_SESS_RECOV ||
 	    task->state == ISCSI_TASK_REQUEUE_SCSIQ)
 		return;
 	WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
@@ -614,7 +613,7 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
 		/* it was never sent so just complete like normal */
 		state = ISCSI_TASK_COMPLETED;
 	} else if (err == DID_TRANSPORT_DISRUPTED)
-		state = ISCSI_TASK_ABRT_SESS_RECOV;
+		state = ISCSI_TASK_COMPLETED;
 	else
 		state = ISCSI_TASK_ABRT_TMF;
 
@@ -3310,7 +3309,7 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
 			continue;
 		}
 
-		state = ISCSI_TASK_ABRT_SESS_RECOV;
+		state = ISCSI_TASK_COMPLETED;
 		if (task->state == ISCSI_TASK_PENDING)
 			state = ISCSI_TASK_COMPLETED;
 		iscsi_finish_task(task, state);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 7a78f8c5d670..589acc1d420d 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -97,7 +97,6 @@ enum {
 	ISCSI_TASK_PENDING,
 	ISCSI_TASK_RUNNING,
 	ISCSI_TASK_ABRT_TMF,		/* aborted due to TMF */
-	ISCSI_TASK_ABRT_SESS_RECOV,	/* aborted due to session recovery */
 	ISCSI_TASK_REQUEUE_SCSIQ,	/* qcmd requeueing to scsi-ml */
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 23/40] scsi: libiscsi: remove ISCSI_TASK_REQUEUE_SCSIQ
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (21 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 22/40] scsi: libiscsi: remove ISCSI_TASK_ABRT_SESS_RECOV Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 24/40] scsi: be2iscsi: check for running task under back_lock Mike Christie
                   ` (17 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

ISCSI_TASK_REQUEUE_SCSIQ is just kind of awkward and it's wrong. If in
queuecommand we are going to return SCSI_MLQUEUE_TARGET_BUSY then we
must have finished up cleaning up the cmd when queuecommand returns.
This has us call the final cleanup code directly. Because the cmd was
allocated by the block/scsi layer and we've been under the frwd lock the
entire time, we know that nothing else has a ref to the cmd and we can
just call the free function directly.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 39 +++++++++++++++++++++------------------
 include/scsi/libiscsi.h |  1 -
 2 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e2f3217afdc9..00a25af9eb98 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -437,19 +437,18 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 }
 
 /**
- * iscsi_free_task - free a task
+ * __iscsi_free_task - free a task
  * @task: iscsi cmd task
  *
  * Must be called with session back_lock.
  * This function returns the scsi command to scsi-ml or cleans
  * up mgmt tasks then returns the task to the pool.
  */
-static void iscsi_free_task(struct iscsi_task *task)
+static void __iscsi_free_task(struct iscsi_task *task)
 {
 	struct iscsi_conn *conn = task->conn;
 	struct iscsi_session *session = conn->session;
 	struct scsi_cmnd *sc = task->sc;
-	int oldstate = task->state;
 
 	ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n",
 			  task->itt, task->state, task->sc);
@@ -463,18 +462,21 @@ static void iscsi_free_task(struct iscsi_task *task)
 	if (conn->login_task == task)
 		return;
 
-	if (!sc) {
+	if (!sc)
 		kfifo_in(&session->mgmt_pool.queue, (void *)&task, sizeof(void *));
-	} else {
-		/* SCSI eh reuses commands to verify us */
-		sc->SCp.ptr = NULL;
-		/*
-		 * queue command may call this to free the task, so
-		 * it will decide how to return sc to scsi-ml.
-		 */
-		if (oldstate != ISCSI_TASK_REQUEUE_SCSIQ)
-			sc->scsi_done(sc);
-	}
+}
+
+static void iscsi_free_task(struct iscsi_task *task)
+{
+	struct scsi_cmnd *sc = task->sc;
+
+	__iscsi_free_task(task);
+	if (!sc)
+		return;
+
+	/* SCSI eh reuses commands to verify us */
+	sc->SCp.ptr = NULL;
+	sc->scsi_done(sc);
 }
 
 void __iscsi_get_task(struct iscsi_task *task)
@@ -516,8 +518,7 @@ static void iscsi_finish_task(struct iscsi_task *task, int state)
 			  "complete task itt 0x%x state %d sc %p\n",
 			  task->itt, task->state, task->sc);
 	if (task->state == ISCSI_TASK_COMPLETED ||
-	    task->state == ISCSI_TASK_ABRT_TMF ||
-	    task->state == ISCSI_TASK_REQUEUE_SCSIQ)
+	    task->state == ISCSI_TASK_ABRT_TMF)
 		return;
 	WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
 	task->state = state;
@@ -1844,7 +1845,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	spin_unlock_bh(&session->frwd_lock);
 
 	spin_lock_bh(&session->back_lock);
-	iscsi_finish_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
+	__iscsi_free_task(task);
 	spin_unlock_bh(&session->back_lock);
 reject:
 	ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
@@ -1855,8 +1856,10 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	spin_unlock_bh(&session->frwd_lock);
 
 	spin_lock_bh(&session->back_lock);
-	iscsi_finish_task(task, ISCSI_TASK_REQUEUE_SCSIQ);
+	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 	spin_unlock_bh(&session->back_lock);
+	return 0;
+
 fault:
 	ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n",
 			  sc->cmnd[0], reason);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 589acc1d420d..ceb01ef12002 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -97,7 +97,6 @@ enum {
 	ISCSI_TASK_PENDING,
 	ISCSI_TASK_RUNNING,
 	ISCSI_TASK_ABRT_TMF,		/* aborted due to TMF */
-	ISCSI_TASK_REQUEUE_SCSIQ,	/* qcmd requeueing to scsi-ml */
 };
 
 struct iscsi_r2t_info {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 24/40] scsi: be2iscsi: check for running task under back_lock
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (22 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 23/40] scsi: libiscsi: remove ISCSI_TASK_REQUEUE_SCSIQ Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 25/40] scsi: iscsi: add mgmt lock Mike Christie
                   ` (16 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The tasks's sc is cleared when it's going to be sent back to scsi-ml.
This is done under the back block in __iscsi_free_task, so we must set
and check this under the same lock.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 99eae2add8da..4181769d7303 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -216,12 +216,12 @@ static char const *cqe_desc[] = {
 
 static int beiscsi_eh_abort(struct scsi_cmnd *sc)
 {
-	struct iscsi_task *abrt_task = (struct iscsi_task *)sc->SCp.ptr;
 	struct iscsi_cls_session *cls_session;
 	struct beiscsi_io_task *abrt_io_task;
 	struct beiscsi_conn *beiscsi_conn;
 	struct iscsi_session *session;
 	struct invldt_cmd_tbl inv_tbl;
+	struct iscsi_task *abrt_task;
 	struct beiscsi_hba *phba;
 	struct iscsi_conn *conn;
 	int rc;
@@ -231,7 +231,8 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
 
 	/* check if we raced, task just got cleaned up under us */
 	spin_lock_bh(&session->back_lock);
-	if (!abrt_task || !abrt_task->sc) {
+	abrt_task = scsi_cmd_priv(sc);
+	if (!abrt_task->sc) {
 		spin_unlock_bh(&session->back_lock);
 		return SUCCESS;
 	}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 25/40] scsi: iscsi: add mgmt lock
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (23 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 24/40] scsi: be2iscsi: check for running task under back_lock Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 26/40] scsi: iscsi: replace back_lock with task lock for lookup Mike Christie
                   ` (15 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This patch adds a new lock around the mgmt pool, so we only need the back
lock for the task state which will be fixed in the next patches.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 30 +++++++++++++++++++++---------
 include/scsi/libiscsi.h |  8 ++++----
 2 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 00a25af9eb98..f822c0cd5927 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -462,8 +462,12 @@ static void __iscsi_free_task(struct iscsi_task *task)
 	if (conn->login_task == task)
 		return;
 
-	if (!sc)
-		kfifo_in(&session->mgmt_pool.queue, (void *)&task, sizeof(void *));
+	if (sc)
+		return;
+
+	spin_lock_bh(&session->mgmt_lock);
+	kfifo_in(&session->mgmt_pool.queue, (void *)&task, sizeof(void *));
+	spin_unlock_bh(&session->mgmt_lock);
 }
 
 static void iscsi_free_task(struct iscsi_task *task)
@@ -716,9 +720,13 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
 		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
+		spin_lock_bh(&session->mgmt_lock);
 		if (!kfifo_out(&session->mgmt_pool.queue, (void *)&task,
-			       sizeof(void *)))
+			       sizeof(void *))) {
+			spin_unlock_bh(&session->mgmt_lock);
 			return NULL;
+		}
+		spin_unlock_bh(&session->mgmt_lock);
 	}
 	/*
 	 * released in complete pdu for task we expect a response for, and
@@ -3017,6 +3025,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 	session->dd_data = cls_session->dd_data + sizeof(*session);
 
 	mutex_init(&session->eh_mutex);
+	spin_lock_init(&session->mgmt_lock);
 	spin_lock_init(&session->frwd_lock);
 	spin_lock_init(&session->back_lock);
 
@@ -3144,13 +3153,13 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
 	/* allocate login_task used for the login/text sequences */
-	spin_lock_bh(&session->frwd_lock);
+	spin_lock_bh(&session->mgmt_lock);
 	if (!kfifo_out(&session->mgmt_pool.queue, (void *)&conn->login_task,
 		       sizeof(void *))) {
-		spin_unlock_bh(&session->frwd_lock);
+		spin_unlock_bh(&session->mgmt_lock);
 		goto login_task_alloc_fail;
 	}
-	spin_unlock_bh(&session->frwd_lock);
+	spin_unlock_bh(&session->mgmt_lock);
 
 	data = (char *) __get_free_pages(GFP_KERNEL,
 					 get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
@@ -3164,8 +3173,10 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
 	return cls_conn;
 
 login_task_data_alloc_fail:
+	spin_lock_bh(&session->mgmt_lock);
 	kfifo_in(&session->mgmt_pool.queue, (void *)&conn->login_task,
 		 sizeof(void *));
+	spin_unlock_bh(&session->mgmt_lock);
 login_task_alloc_fail:
 	iscsi_destroy_conn(cls_conn);
 	return NULL;
@@ -3206,11 +3217,12 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 		   get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
 	kfree(conn->persistent_address);
 	kfree(conn->local_ipaddr);
-	/* regular RX path uses back_lock */
-	spin_lock_bh(&session->back_lock);
+
+	spin_lock_bh(&session->mgmt_lock);
 	kfifo_in(&session->mgmt_pool.queue, (void *)&conn->login_task,
 		 sizeof(void *));
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&session->mgmt_lock);
+
 	if (session->leadconn == conn)
 		session->leadconn = NULL;
 	spin_unlock_bh(&session->frwd_lock);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index ceb01ef12002..8d1918590aa6 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -348,10 +348,9 @@ struct iscsi_session {
 	spinlock_t		frwd_lock;	/* protects queued_cmdsn,  *
 						 * cmdsn, suspend_bit,     *
 						 * leadconn, _stage,       *
-						 * tmf_state and mgmt      *
-						 * queues                  */
-	spinlock_t		back_lock;	/* protects cmdsn_exp      *
-						 * cmdsn_max, mgmt queues  */
+						 * tmf_state and queues    */
+	spinlock_t		back_lock;	/* protects cmdsn_exp and  *
+						 * cmdsn_max               */
 	/*
 	 * frwd_lock must be held when transitioning states, but not needed
 	 * if just checking the state in the scsi-ml or iscsi callouts.
@@ -363,6 +362,7 @@ struct iscsi_session {
 	int			cmds_max;	/* Total number of tasks */
 	struct iscsi_task	**mgmt_cmds;
 	struct iscsi_pool	mgmt_pool;	/* mgmt task pool */
+	spinlock_t		mgmt_lock;	/* protects mgmt pool/arr */
 	void			*dd_data;	/* LLD private data */
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 26/40] scsi: iscsi: replace back_lock with task lock for lookup
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (24 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 25/40] scsi: iscsi: add mgmt lock Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 27/40] scsi: qedi: use task lock when checking task state Mike Christie
                   ` (14 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

We hold the back lock during completion to make sure commands do not
complete from another thread but for drivers that can complete from
multiple threads/isrs this adds a bottleneck. We also do not want to
have to hold the back_lock while calling iscsi_put_task from the xmit
path.

This patch adds a per task lock which is used to test if a command has
completed and can be used to get a ref to the task so it can't complete
from under us in the recv paths. The next patch will convert the eh
paths.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/infiniband/ulp/iser/iser_initiator.c |  9 ++-
 drivers/scsi/bnx2i/bnx2i_hwi.c               | 63 +++++++++++---------
 drivers/scsi/cxgbi/libcxgbi.c                |  3 +-
 drivers/scsi/libiscsi.c                      | 42 ++++++++++---
 drivers/scsi/libiscsi_tcp.c                  | 18 +++---
 drivers/scsi/qedi/qedi_fw.c                  |  6 +-
 drivers/scsi/qla4xxx/ql4_isr.c               |  4 +-
 drivers/scsi/qla4xxx/ql4_os.c                |  3 +-
 include/scsi/libiscsi.h                      | 12 +++-
 9 files changed, 104 insertions(+), 56 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 27a6f75a9912..43757b312006 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -632,15 +632,20 @@ iser_check_remote_inv(struct iser_conn *iser_conn,
 
 			if (iser_task->dir[ISER_DIR_IN]) {
 				desc = iser_task->rdma_reg[ISER_DIR_IN].mem_h;
-				if (unlikely(iser_inv_desc(desc, rkey)))
+				if (unlikely(iser_inv_desc(desc, rkey))) {
+					iscsi_put_task(task);
 					return -EINVAL;
+				}
 			}
 
 			if (iser_task->dir[ISER_DIR_OUT]) {
 				desc = iser_task->rdma_reg[ISER_DIR_OUT].mem_h;
-				if (unlikely(iser_inv_desc(desc, rkey)))
+				if (unlikely(iser_inv_desc(desc, rkey))) {
+					iscsi_put_task(task);
 					return -EINVAL;
+				}
 			}
+			iscsi_put_task(task);
 		} else {
 			iser_err("failed to get task for itt=%d\n", hdr->itt);
 			return -EINVAL;
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index bad396e5c601..af03ad7bc941 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -404,8 +404,8 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
 	switch (tmfabort_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) {
 	case ISCSI_TM_FUNC_ABORT_TASK:
 	case ISCSI_TM_FUNC_TASK_REASSIGN:
-		ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt);
-		if (!ctask || !ctask->sc)
+		ctask = iscsi_itt_to_ctask(conn, tmfabort_hdr->rtt);
+		if (!ctask) {
 			/*
 			 * the iscsi layer must have completed the cmd while
 			 * was starting up.
@@ -415,6 +415,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
 			 *       In this case, the task must be aborted
 			 */
 			return 0;
+		}
 
 		ref_sc = ctask->sc;
 		if (ref_sc->sc_data_direction == DMA_TO_DEVICE)
@@ -425,6 +426,7 @@ int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn,
 				 ISCSI_CMD_REQUEST_TYPE_SHIFT);
 		tmfabort_wqe->ref_itt = (dword |
 					(tmfabort_hdr->rtt & ISCSI_ITT_MASK));
+		iscsi_put_task(ctask);
 		break;
 	default:
 		tmfabort_wqe->ref_itt = RESERVED_ITT;
@@ -1346,7 +1348,6 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
 	u32 datalen = 0;
 
 	resp_cqe = (struct bnx2i_cmd_response *)cqe;
-	spin_lock_bh(&session->back_lock);
 	task = iscsi_itt_to_task(conn,
 				 resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
 	if (!task)
@@ -1414,10 +1415,12 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
 	}
 
 done:
+	spin_lock_bh(&session->back_lock);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
 			     conn->data, datalen);
-fail:
 	spin_unlock_bh(&session->back_lock);
+	iscsi_put_task(task);
+fail:
 	return 0;
 }
 
@@ -1442,7 +1445,6 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
 	int pad_len;
 
 	login = (struct bnx2i_login_response *) cqe;
-	spin_lock(&session->back_lock);
 	task = iscsi_itt_to_task(conn,
 				 login->itt & ISCSI_LOGIN_RESPONSE_INDEX);
 	if (!task)
@@ -1481,11 +1483,13 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
 		}
 	}
 
+	spin_lock(&session->back_lock);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
 		bnx2i_conn->gen_pdu.resp_buf,
 		bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
-done:
 	spin_unlock(&session->back_lock);
+	iscsi_put_task(task);
+done:
 	return 0;
 }
 
@@ -1510,7 +1514,6 @@ static int bnx2i_process_text_resp(struct iscsi_session *session,
 	int pad_len;
 
 	text = (struct bnx2i_text_response *) cqe;
-	spin_lock(&session->back_lock);
 	task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX);
 	if (!task)
 		goto done;
@@ -1541,12 +1544,14 @@ static int bnx2i_process_text_resp(struct iscsi_session *session,
 			bnx2i_conn->gen_pdu.resp_wr_ptr++;
 		}
 	}
+	spin_lock(&session->back_lock);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
 			     bnx2i_conn->gen_pdu.resp_buf,
 			     bnx2i_conn->gen_pdu.resp_wr_ptr -
 			     bnx2i_conn->gen_pdu.resp_buf);
-done:
 	spin_unlock(&session->back_lock);
+	iscsi_put_task(task);
+done:
 	return 0;
 }
 
@@ -1569,7 +1574,6 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
 	struct iscsi_tm_rsp *resp_hdr;
 
 	tmf_cqe = (struct bnx2i_tmf_response *)cqe;
-	spin_lock(&session->back_lock);
 	task = iscsi_itt_to_task(conn,
 				 tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX);
 	if (!task)
@@ -1583,9 +1587,11 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
 	resp_hdr->itt = task->hdr->itt;
 	resp_hdr->response = tmf_cqe->response;
 
+	spin_lock(&session->back_lock);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
-done:
 	spin_unlock(&session->back_lock);
+	iscsi_put_task(task);
+done:
 	return 0;
 }
 
@@ -1608,7 +1614,6 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
 	struct iscsi_logout_rsp *resp_hdr;
 
 	logout = (struct bnx2i_logout_response *) cqe;
-	spin_lock(&session->back_lock);
 	task = iscsi_itt_to_task(conn,
 				 logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX);
 	if (!task)
@@ -1628,11 +1633,14 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
 	resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait);
 	resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
 
+	spin_lock(&session->back_lock);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+	spin_unlock(&session->back_lock);
+
+	iscsi_put_task(task);
 
 	bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
 done:
-	spin_unlock(&session->back_lock);
 	return 0;
 }
 
@@ -1653,12 +1661,10 @@ static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session,
 	struct iscsi_task *task;
 
 	nop_in = (struct bnx2i_nop_in_msg *)cqe;
-	spin_lock(&session->back_lock);
 	task = iscsi_itt_to_task(conn,
 				 nop_in->itt & ISCSI_NOP_IN_MSG_INDEX);
 	if (task)
-		__iscsi_put_task(task);
-	spin_unlock(&session->back_lock);
+		iscsi_put_task(task);
 }
 
 /**
@@ -1690,14 +1696,13 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
 				     struct cqe *cqe)
 {
 	struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
-	struct iscsi_task *task;
+	struct iscsi_task *task = NULL;
 	struct bnx2i_nop_in_msg *nop_in;
 	struct iscsi_nopin *hdr;
 	int tgt_async_nop = 0;
 
 	nop_in = (struct bnx2i_nop_in_msg *)cqe;
 
-	spin_lock(&session->back_lock);
 	hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr;
 	memset(hdr, 0, sizeof(struct iscsi_hdr));
 	hdr->opcode = nop_in->op_code;
@@ -1722,9 +1727,13 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
 		memcpy(&hdr->lun, nop_in->lun, 8);
 	}
 done:
+	spin_lock(&session->back_lock);
 	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
 	spin_unlock(&session->back_lock);
 
+	if (task)
+		iscsi_put_task(task);
+
 	return tgt_async_nop;
 }
 
@@ -1833,13 +1842,14 @@ static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session,
 	struct iscsi_task *task;
 
 	cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe;
-	spin_lock(&session->back_lock);
 	task = iscsi_itt_to_task(conn,
 			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
-	if (!task)
+	if (!task) {
 		printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n",
 			cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX);
-	spin_unlock(&session->back_lock);
+	} else {
+		iscsi_put_task(task);
+	}
 	complete(&bnx2i_conn->cmd_cleanup_cmpl);
 }
 
@@ -1907,18 +1917,15 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
 	struct scsi_cmnd *sc;
 	int rc = 0;
 
-	spin_lock(&session->back_lock);
-	task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
-				 cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
-	if (!task || !task->sc) {
-		spin_unlock(&session->back_lock);
+	task = iscsi_itt_to_ctask(bnx2i_conn->cls_conn->dd_data,
+				  cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
+	if (!task)
 		return -EINVAL;
-	}
 	sc = task->sc;
 
-	spin_unlock(&session->back_lock);
-
 	p = &per_cpu(bnx2i_percpu, blk_mq_rq_cpu(sc->request));
+	iscsi_put_task(task);
+
 	spin_lock(&p->p_work_lock);
 	if (unlikely(!p->iothread)) {
 		rc = -EINVAL;
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index cdaa67fd8c2e..b3960e0b341a 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -1540,10 +1540,11 @@ skb_read_pdu_bhs(struct cxgbi_sock *csk, struct iscsi_conn *conn,
 		struct iscsi_task *task = iscsi_itt_to_ctask(conn, itt);
 		u32 data_sn = be32_to_cpu(((struct iscsi_data *)
 							skb->data)->datasn);
-		if (task && task->sc) {
+		if (task) {
 			struct iscsi_tcp_task *tcp_task = task->dd_data;
 
 			tcp_task->exp_datasn = data_sn;
+			iscsi_put_task(task);
 		}
 	}
 
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index f822c0cd5927..955ca15ecf5f 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -454,8 +454,11 @@ static void __iscsi_free_task(struct iscsi_task *task)
 			  task->itt, task->state, task->sc);
 
 	session->tt->cleanup_task(task);
+
+	spin_lock_bh(&task->lock);
 	task->state = ISCSI_TASK_FREE;
 	task->sc = NULL;
+	spin_unlock_bh(&task->lock);
 	/*
 	 * login task is preallocated so do not free
 	 */
@@ -1097,10 +1100,12 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 						 "Invalid pdu reject. Could "
 						 "not lookup rejected task.\n");
 				rc = ISCSI_ERR_BAD_ITT;
-			} else
+			} else {
 				rc = iscsi_nop_out_rsp(task,
 					(struct iscsi_nopin*)&rejected_pdu,
 					NULL, 0);
+				iscsi_put_task(task);
+			}
 		}
 		break;
 	default:
@@ -1121,11 +1126,13 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
  * This should be used for mgmt tasks like login and nops, or if
  * the LDD's itt space does not include the session age.
  *
- * The session back_lock must be held.
+ * If the itt is valid a task will be returned with the reference held. The
+ * caller must call iscsi_put_task.
  */
 struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 {
 	struct iscsi_session *session = conn->session;
+	struct iscsi_task *task;
 	uint32_t i;
 
 	if (itt == RESERVED_ITT)
@@ -1142,7 +1149,12 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 		if (i >= ISCSI_MGMT_CMDS_MAX)
 			return NULL;
 
-		return session->mgmt_cmds[i];
+		task = session->mgmt_cmds[i];
+		if (iscsi_task_is_completed(task))
+			return NULL;
+
+		__iscsi_get_task(task);
+		return task;
 	} else {
 		return iscsi_itt_to_ctask(conn, itt);
 	}
@@ -1200,7 +1212,9 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	if (!task)
 		return ISCSI_ERR_BAD_OPCODE;
 
-	return iscsi_complete_task(conn, task, hdr, data, datalen);
+	rc = iscsi_complete_task(conn, task, hdr, data, datalen);
+	iscsi_put_task(task);
+	return rc;
 }
 EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
 
@@ -1374,7 +1388,8 @@ EXPORT_SYMBOL_GPL(iscsi_verify_itt);
  *
  * This should be used for cmd tasks.
  *
- * The session back_lock must be held.
+ * If the itt is valid a task will be returned with the reference held. The
+ * caller must call iscsi_put_task.
  */
 struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
 {
@@ -1395,15 +1410,21 @@ struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
 		return NULL;
 
 	task = scsi_cmd_priv(sc);
-	if (!task->sc)
+	spin_lock_bh(&task->lock);
+	if (!task->sc || iscsi_task_is_completed(task)) {
+		spin_unlock_bh(&task->lock);
 		return NULL;
+	}
 
 	if (task->sc->SCp.phase != session->age) {
 		iscsi_session_printk(KERN_ERR, conn->session,
 				  "task's session age %d, expected %d\n",
 				  task->sc->SCp.phase, session->age);
+		spin_unlock_bh(&task->lock);
 		return NULL;
 	}
+	__iscsi_get_task(task);
+	spin_unlock_bh(&task->lock);
 
 	return task;
 }
@@ -1709,14 +1730,18 @@ static struct iscsi_task *iscsi_init_scsi_task(struct iscsi_conn *conn,
 
 	refcount_set(&task->refcount, 1);
 	task->itt = blk_mq_unique_tag(sc->request);
-	task->state = ISCSI_TASK_PENDING;
 	task->conn = conn;
-	task->sc = sc;
 	task->have_checked_conn = false;
 	task->last_timeout = jiffies;
 	task->last_xfer = jiffies;
 	task->protected = false;
 	INIT_LIST_HEAD(&task->running);
+
+	spin_lock_bh(&task->lock);
+	task->state = ISCSI_TASK_PENDING;
+	task->sc = sc;
+	spin_unlock_bh(&task->lock);
+
 	return task;
 }
 
@@ -2951,6 +2976,7 @@ static void iscsi_init_task(struct iscsi_task *task, int dd_task_size)
 	task->itt = ISCSI_RESERVED_TAG;
 	task->state = ISCSI_TASK_FREE;
 	INIT_LIST_HEAD(&task->running);
+	spin_lock_init(&task->lock);
 }
 
 int iscsi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *sc)
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 73d4fe20ba9d..b1399ff5ca9e 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -539,13 +539,11 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 	int r2tsn;
 	int rc;
 
-	spin_lock(&session->back_lock);
 	task = iscsi_itt_to_ctask(conn, hdr->itt);
 	if (!task) {
-		spin_unlock(&session->back_lock);
 		return ISCSI_ERR_BAD_ITT;
 	} else if (task->sc->sc_data_direction != DMA_TO_DEVICE) {
-		spin_unlock(&session->back_lock);
+		iscsi_put_task(task);
 		return ISCSI_ERR_PROTO;
 	}
 	/*
@@ -553,16 +551,15 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 	 * so get a ref to the task that will be dropped in the xmit path.
 	 */
 	if (task->state != ISCSI_TASK_RUNNING) {
-		spin_unlock(&session->back_lock);
 		/* Let the path that got the early rsp complete it */
 		return 0;
 	}
 	task->last_xfer = jiffies;
-	__iscsi_get_task(task);
 
 	tcp_conn = conn->dd_data;
 	rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
 	/* fill-in new R2T associated with the task */
+	spin_lock(&session->back_lock);
 	iscsi_update_cmdsn(session, (struct iscsi_nopin *)rhdr);
 	spin_unlock(&session->back_lock);
 
@@ -713,14 +710,15 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 
 	switch(opcode) {
 	case ISCSI_OP_SCSI_DATA_IN:
-		spin_lock(&conn->session->back_lock);
 		task = iscsi_itt_to_ctask(conn, hdr->itt);
 		if (!task)
 			rc = ISCSI_ERR_BAD_ITT;
 		else
 			rc = iscsi_tcp_data_in(conn, task);
+
 		if (rc) {
-			spin_unlock(&conn->session->back_lock);
+			if (task)
+				iscsi_put_task(task);
 			break;
 		}
 
@@ -753,11 +751,11 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 						   tcp_conn->in.datalen,
 						   iscsi_tcp_process_data_in,
 						   rx_hash);
-			spin_unlock(&conn->session->back_lock);
+			iscsi_put_task(task);
 			return rc;
 		}
-		rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
-		spin_unlock(&conn->session->back_lock);
+		rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
+		iscsi_put_task(task);
 		break;
 	case ISCSI_OP_SCSI_CMD_RSP:
 		if (tcp_conn->in.datalen) {
diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index 217291e81cdb..e28dc249c9f0 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -1469,14 +1469,16 @@ int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask)
 
 	if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
 	     ISCSI_TM_FUNC_ABORT_TASK) {
-		ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt);
-		if (!ctask || !ctask->sc) {
+		ctask = iscsi_itt_to_ctask(conn, tmf_hdr->rtt);
+		if (!ctask) {
 			QEDI_ERR(&qedi->dbg_ctx,
 				 "Could not get reference task\n");
 			return 0;
 		}
+
 		cmd = (struct qedi_cmd *)ctask->dd_data;
 		tmf_pdu_header.rtt = cmd->task_id;
+		iscsi_put_task(ctask);
 	} else {
 		tmf_pdu_header.rtt = ISCSI_RESERVED_TAG;
 	}
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 6f0e77dc2a34..92ef40d755e4 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -384,10 +384,8 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,
 
 	cls_conn = ddb_entry->conn;
 	conn = cls_conn->dd_data;
-	spin_lock(&conn->session->back_lock);
-	task = iscsi_itt_to_task(conn, itt);
-	spin_unlock(&conn->session->back_lock);
 
+	task = iscsi_itt_to_task(conn, itt);
 	if (task == NULL) {
 		ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__);
 		return;
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index af89d39f19e5..754046902141 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -3382,7 +3382,8 @@ static void qla4xxx_task_work(struct work_struct *wdata)
 			   sts->completionStatus);
 		break;
 	}
-	return;
+	/* Release ref taken in qla4xxx_passthru_status_entry */
+	iscsi_put_task(task);
 }
 
 static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 8d1918590aa6..25590b1458ef 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -142,7 +142,11 @@ struct iscsi_task {
 	/* T10 protection information */
 	bool			protected;
 
-	/* state set/tested under session->lock */
+	/*
+	 * task lock must be held when using sc or state to check if task has
+	 * completed
+	 */
+	spinlock_t		lock;
 	int			state;
 	refcount_t		refcount;
 	struct list_head	running;	/* running cmd list */
@@ -162,6 +166,12 @@ static inline void* iscsi_next_hdr(struct iscsi_task *task)
 	return (void*)task->hdr + task->hdr_len;
 }
 
+static inline bool iscsi_task_is_completed(struct iscsi_task *task)
+{
+	return task->state == ISCSI_TASK_COMPLETED ||
+	       task->state == ISCSI_TASK_ABRT_TMF;
+}
+
 /* Connection's states */
 enum {
 	ISCSI_CONN_INITIAL_STAGE,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 27/40] scsi: qedi: use task lock when checking task state
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (25 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 26/40] scsi: iscsi: replace back_lock with task lock for lookup Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 28/40] scsi: be2iscsi: replace back_lock with task lock during eh Mike Christie
                   ` (13 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Convert qedi to check for task->sc instead of SCp.ptr and use the task
lock when grabbing a ref to the task.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/qedi/qedi_fw.c    |  2 +-
 drivers/scsi/qedi/qedi_iscsi.c | 15 +++++----------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index e28dc249c9f0..de5133be1c4b 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -594,7 +594,7 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 		goto error;
 	}
 
-	if (!sc_cmd->SCp.ptr) {
+	if (!task->sc) {
 		QEDI_WARN(&qedi->dbg_ctx,
 			  "SCp.ptr is NULL, returned in another context.\n");
 		goto error;
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 0f3704c4c985..77f0445c0198 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -47,15 +47,10 @@ static int qedi_eh_abort(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *shost = cmd->device->host;
 	struct qedi_ctx *qedi = iscsi_host_priv(shost);
-	struct iscsi_cls_session *cls_session;
-	struct iscsi_session *session;
 	struct qedi_conn *qedi_conn;
 	struct iscsi_task *task;
 	int rc;
 
-	cls_session = starget_to_session(scsi_target(cmd->device));
-	session = cls_session->dd_data;
-
 	if (qedi_do_not_recover) {
 		QEDI_ERR(&qedi->dbg_ctx, "dont send cleanup/abort %d\n",
 			 qedi_do_not_recover);
@@ -63,15 +58,15 @@ static int qedi_eh_abort(struct scsi_cmnd *cmd)
 	}
 
 	/* check if we raced, task just got cleaned up under us */
-	spin_lock_bh(&session->back_lock);
-	task = (struct iscsi_task *)cmd->SCp.ptr;
-	if (!task || !task->sc) {
-		spin_unlock_bh(&session->back_lock);
+	task = scsi_cmd_priv(cmd);
+	spin_lock_bh(&task->lock);
+	if (!task->sc || iscsi_task_is_completed(task)) {
+		spin_unlock_bh(&task->lock);
 		return SUCCESS;
 	}
 
 	__iscsi_get_task(task);
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&task->lock);
 
 	qedi_conn = task->conn->dd_data;
 	set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 28/40] scsi: be2iscsi: replace back_lock with task lock during eh
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (26 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 27/40] scsi: qedi: use task lock when checking task state Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 29/40] scsi: libiscsi: " Mike Christie
                   ` (12 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This replaces the back_lock with the per task lock for when we were
checking the task->state/task->sc/SCp.ptr during error handling.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 4181769d7303..da5ede4ef7f4 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -216,24 +216,19 @@ static char const *cqe_desc[] = {
 
 static int beiscsi_eh_abort(struct scsi_cmnd *sc)
 {
-	struct iscsi_cls_session *cls_session;
 	struct beiscsi_io_task *abrt_io_task;
 	struct beiscsi_conn *beiscsi_conn;
-	struct iscsi_session *session;
 	struct invldt_cmd_tbl inv_tbl;
 	struct iscsi_task *abrt_task;
 	struct beiscsi_hba *phba;
 	struct iscsi_conn *conn;
 	int rc;
 
-	cls_session = starget_to_session(scsi_target(sc->device));
-	session = cls_session->dd_data;
-
 	/* check if we raced, task just got cleaned up under us */
-	spin_lock_bh(&session->back_lock);
 	abrt_task = scsi_cmd_priv(sc);
-	if (!abrt_task->sc) {
-		spin_unlock_bh(&session->back_lock);
+	spin_lock_bh(&abrt_task->lock);
+	if (!abrt_task->sc || iscsi_task_is_completed(abrt_task)) {
+		spin_unlock_bh(&abrt_task->lock);
 		return SUCCESS;
 	}
 	/* get a task ref till FW processes the req for the ICD used */
@@ -252,7 +247,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
 	}
 	inv_tbl.cid = beiscsi_conn->beiscsi_conn_cid;
 	inv_tbl.icd = abrt_io_task->psgl_handle->sgl_index;
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&abrt_task->lock);
 
 	rc = beiscsi_mgmt_invalidate_icds(phba, &inv_tbl, 1);
 	iscsi_put_task(abrt_task);
@@ -274,7 +269,7 @@ struct beiscsi_invldt_cmd_tbl {
 static bool beiscsi_dev_reset_sc_iter(struct scsi_cmnd *sc, void *data,
 				      bool rsvd)
 {
-	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_task *task = scsi_cmd_priv(sc);
 	struct iscsi_sc_iter_data *iter_data = data;
 	struct beiscsi_invldt_cmd_tbl *inv_tbl = iter_data->data;
 	struct beiscsi_conn *beiscsi_conn = iter_data->conn->dd_data;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 29/40] scsi: libiscsi: replace back_lock with task lock during eh
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (27 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 28/40] scsi: be2iscsi: replace back_lock with task lock during eh Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 30/40] scsi: be2iscsi: prep for back_lock removal Mike Christie
                   ` (11 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This replaces the back_lock with the per task lock for when we were
checking the task->state/task->sc/SCp.ptr during error handling.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 132 +++++++++++++++++++++-------------------
 1 file changed, 71 insertions(+), 61 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 955ca15ecf5f..61d73172283e 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -422,7 +422,10 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 	if (session->tt->init_task && session->tt->init_task(task))
 		return -EIO;
 
+	spin_lock_bh(&task->lock);
 	task->state = ISCSI_TASK_RUNNING;
+	spin_unlock_bh(&task->lock);
+
 	session->cmdsn++;
 
 	conn->scsicmd_pdus_cnt++;
@@ -440,7 +443,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
  * __iscsi_free_task - free a task
  * @task: iscsi cmd task
  *
- * Must be called with session back_lock.
  * This function returns the scsi command to scsi-ml or cleans
  * up mgmt tasks then returns the task to the pool.
  */
@@ -481,8 +483,6 @@ static void iscsi_free_task(struct iscsi_task *task)
 	if (!sc)
 		return;
 
-	/* SCSI eh reuses commands to verify us */
-	sc->SCp.ptr = NULL;
 	sc->scsi_done(sc);
 }
 
@@ -514,8 +514,6 @@ EXPORT_SYMBOL_GPL(iscsi_put_task);
  * iscsi_finish_task - finish a task
  * @task: iscsi cmd task
  * @state: state to complete task with
- *
- * Must be called with session back_lock.
  */
 static void iscsi_finish_task(struct iscsi_task *task, int state)
 {
@@ -524,11 +522,15 @@ static void iscsi_finish_task(struct iscsi_task *task, int state)
 	ISCSI_DBG_SESSION(conn->session,
 			  "complete task itt 0x%x state %d sc %p\n",
 			  task->itt, task->state, task->sc);
-	if (task->state == ISCSI_TASK_COMPLETED ||
-	    task->state == ISCSI_TASK_ABRT_TMF)
+	spin_lock_bh(&task->lock);
+	if (iscsi_task_is_completed(task)) {
+		spin_unlock_bh(&task->lock);
 		return;
+	}
+
 	WARN_ON_ONCE(task->state == ISCSI_TASK_FREE);
 	task->state = state;
+	spin_unlock_bh(&task->lock);
 
 	if (READ_ONCE(conn->ping_task) == task)
 		WRITE_ONCE(conn->ping_task, NULL);
@@ -562,7 +564,7 @@ void iscsi_complete_scsi_task(struct iscsi_task *task,
 EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
 
 /*
- * Must be called with back and frwd lock
+ * Must be called with the task and frwd lock
  */
 static bool cleanup_queued_task(struct iscsi_task *task)
 {
@@ -606,9 +608,9 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
 	struct scsi_cmnd *sc;
 	int state;
 
-	spin_lock_bh(&conn->session->back_lock);
+	spin_lock_bh(&task->lock);
 	if (cleanup_queued_task(task)) {
-		spin_unlock_bh(&conn->session->back_lock);
+		spin_unlock_bh(&task->lock);
 		return;
 	}
 
@@ -628,8 +630,9 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
 	sc = task->sc;
 	sc->result = err << 16;
 	scsi_set_resid(sc, scsi_bufflen(sc));
+	spin_unlock_bh(&task->lock);
+
 	iscsi_finish_task(task, state);
-	spin_unlock_bh(&conn->session->back_lock);
 }
 
 static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
@@ -1726,7 +1729,6 @@ static struct iscsi_task *iscsi_init_scsi_task(struct iscsi_conn *conn,
 	struct iscsi_task *task = scsi_cmd_priv(sc);
 
 	sc->SCp.phase = conn->session->age;
-	sc->SCp.ptr = (char *) task;
 
 	refcount_set(&task->refcount, 1);
 	task->itt = blk_mq_unique_tag(sc->request);
@@ -1769,7 +1771,6 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	int sess_state;
 
 	sc->result = 0;
-	sc->SCp.ptr = NULL;
 
 	ihost = shost_priv(host);
 
@@ -1877,9 +1878,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 prepd_reject:
 	spin_unlock_bh(&session->frwd_lock);
 
-	spin_lock_bh(&session->back_lock);
 	__iscsi_free_task(task);
-	spin_unlock_bh(&session->back_lock);
 reject:
 	ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n",
 			  sc->cmnd[0], reason);
@@ -1888,9 +1887,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 prepd_fault:
 	spin_unlock_bh(&session->frwd_lock);
 
-	spin_lock_bh(&session->back_lock);
 	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
-	spin_unlock_bh(&session->back_lock);
 	return 0;
 
 fault:
@@ -1978,39 +1975,43 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
 
 static bool fail_scsi_task_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
 {
-	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_task *task = scsi_cmd_priv(sc);
 	struct iscsi_sc_iter_data *iter_data = data;
 	struct iscsi_conn *conn = iter_data->conn;
 	struct iscsi_session *session = conn->session;
 
 	ISCSI_DBG_SESSION(session, "failing sc %p itt 0x%x state %d\n",
 			  task->sc, task->itt, task->state);
-	__iscsi_get_task(task);
-	spin_unlock_bh(&session->back_lock);
 
 	fail_scsi_task(task, *(int *)iter_data->data);
-
-	spin_unlock_bh(&session->frwd_lock);
-	iscsi_put_task(task);
-	spin_lock_bh(&session->frwd_lock);
-
-	spin_lock_bh(&session->back_lock);
 	return true;
 }
 
 static bool iscsi_sc_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
 {
-	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_task *task = scsi_cmd_priv(sc);
 	struct iscsi_sc_iter_data *iter_data = data;
+	bool rc;
 
-	if (!task || !task->sc || task->state == ISCSI_TASK_FREE ||
-	    task->conn != iter_data->conn)
+	spin_lock_bh(&task->lock);
+	if (!task->sc || iscsi_task_is_completed(task) ||
+	    task->conn != iter_data->conn) {
+		spin_unlock_bh(&task->lock);
 		return true;
+	}
+	__iscsi_get_task(task);
+	spin_unlock_bh(&task->lock);
 
-	if (iter_data->lun != -1 && iter_data->lun != task->sc->device->lun)
-		return true;
+	if (iter_data->lun != -1 && iter_data->lun != task->sc->device->lun) {
+		rc = true;
+		goto put_task;
+	}
 
-	return iter_data->fn(sc, iter_data, rsvd);
+	rc = iter_data->fn(sc, iter_data, rsvd);
+
+put_task:
+	iscsi_put_task(task);
+	return rc;
 }
 
 void iscsi_conn_for_each_sc(struct iscsi_conn *conn,
@@ -2020,9 +2021,7 @@ void iscsi_conn_for_each_sc(struct iscsi_conn *conn,
 	struct Scsi_Host *shost = session->host;
 
 	iter_data->conn = conn;
-	spin_lock_bh(&session->back_lock);
 	scsi_host_busy_iter(shost, iscsi_sc_iter, iter_data);
-	spin_unlock_bh(&session->back_lock);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_for_each_sc);
 
@@ -2102,7 +2101,7 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
 
 static bool check_scsi_task_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
 {
-	struct iscsi_task *task = (struct iscsi_task *)sc->SCp.ptr;
+	struct iscsi_task *task = scsi_cmd_priv(sc);
 	struct iscsi_sc_iter_data *iter_data = data;
 	struct iscsi_task *timed_out_task = iter_data->data;
 
@@ -2152,19 +2151,20 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 	ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
 
 	spin_lock_bh(&session->frwd_lock);
-	spin_lock(&session->back_lock);
-	task = (struct iscsi_task *)sc->SCp.ptr;
-	if (!task) {
+
+	task = scsi_cmd_priv(sc);
+	spin_lock(&task->lock);
+	if (!task->sc || iscsi_task_is_completed(task)) {
 		/*
 		 * Raced with completion. Blk layer has taken ownership
 		 * so let timeout code complete it now.
 		 */
 		rc = BLK_EH_DONE;
-		spin_unlock(&session->back_lock);
+		spin_unlock(&task->lock);
 		goto done;
 	}
 	__iscsi_get_task(task);
-	spin_unlock(&session->back_lock);
+	spin_unlock(&task->lock);
 
 	if (READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN) {
 		/*
@@ -2336,20 +2336,37 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 
 	ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
 
+check_done:
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->frwd_lock);
 	/*
 	 * if session was ISCSI_STATE_IN_RECOVERY then we may not have
 	 * got the command.
 	 */
-	if (!sc->SCp.ptr) {
+	task = scsi_cmd_priv(sc);
+	spin_lock_bh(&task->lock);
+	if (!task->sc) {
 		ISCSI_DBG_EH(session, "sc never reached iscsi layer or "
 				      "it completed.\n");
+		spin_unlock_bh(&task->lock);
 		spin_unlock_bh(&session->frwd_lock);
 		mutex_unlock(&session->eh_mutex);
 		return SUCCESS;
 	}
 
+	if (iscsi_task_is_completed(task)) {
+		spin_unlock_bh(&task->lock);
+		spin_unlock_bh(&session->frwd_lock);
+		mutex_unlock(&session->eh_mutex);
+
+		ISCSI_DBG_EH(session, "sc in process of completing. Waiting.\n");
+		msleep(100);
+		goto check_done;
+	}
+
+	__iscsi_get_task(task);
+	spin_unlock_bh(&task->lock);
+
 	/*
 	 * If we are not logged in or we have started a new session
 	 * then let the host reset code handle this
@@ -2357,6 +2374,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 	if (!session->leadconn ||
 	    READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN ||
 	    sc->SCp.phase != session->age) {
+		iscsi_put_task(task);
 		spin_unlock_bh(&session->frwd_lock);
 		mutex_unlock(&session->eh_mutex);
 		ISCSI_DBG_EH(session, "failing abort due to dropped "
@@ -2368,25 +2386,16 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 	conn->eh_abort_cnt++;
 	age = session->age;
 
-	spin_lock(&session->back_lock);
-	task = (struct iscsi_task *)sc->SCp.ptr;
-	if (!task || !task->sc) {
-		/* task completed before time out */
-		ISCSI_DBG_EH(session, "sc completed while abort in progress\n");
-
-		spin_unlock(&session->back_lock);
-		spin_unlock_bh(&session->frwd_lock);
-		mutex_unlock(&session->eh_mutex);
-		return SUCCESS;
-	}
 	ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", sc, task->itt);
-	__iscsi_get_task(task);
-	spin_unlock(&session->back_lock);
 
+	spin_lock_bh(&task->lock);
 	if (task->state == ISCSI_TASK_PENDING) {
+		spin_unlock_bh(&task->lock);
+
 		fail_scsi_task(task, DID_ABORT);
 		goto success;
 	}
+	spin_unlock_bh(&task->lock);
 
 	/* only have one tmf outstanding at a time */
 	if (conn->tmf_state != TMF_INITIAL)
@@ -2424,7 +2433,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 		iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
 		goto failed_unlocked;
 	case TMF_NOT_FOUND:
-		if (!sc->SCp.ptr) {
+		if (!task->sc) {
 			conn->tmf_state = TMF_INITIAL;
 			memset(hdr, 0, sizeof(*hdr));
 			/* task completed before tmf abort response */
@@ -3334,27 +3343,28 @@ fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn)
 
 	for (i = 0; i < ISCSI_MGMT_CMDS_MAX; i++) {
 		task = conn->session->mgmt_cmds[i];
-		if (task->sc)
-			continue;
 
-		if (task->state == ISCSI_TASK_FREE)
+		spin_lock_bh(&task->lock);
+		if (task->state == ISCSI_TASK_FREE) {
+			spin_unlock_bh(&task->lock);
 			continue;
+		}
 
 		ISCSI_DBG_SESSION(conn->session,
 				  "failing mgmt itt 0x%x state %d\n",
 				  task->itt, task->state);
 
-		spin_lock_bh(&session->back_lock);
 		if (cleanup_queued_task(task)) {
-			spin_unlock_bh(&session->back_lock);
+			spin_unlock_bh(&task->lock);
 			continue;
 		}
 
 		state = ISCSI_TASK_COMPLETED;
 		if (task->state == ISCSI_TASK_PENDING)
 			state = ISCSI_TASK_COMPLETED;
+		spin_unlock_bh(&task->lock);
+
 		iscsi_finish_task(task, state);
-		spin_unlock_bh(&session->back_lock);
 	}
 }
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 30/40] scsi: be2iscsi: prep for back_lock removal
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (28 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 29/40] scsi: libiscsi: " Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 31/40] scsi: iscsi: rm iscsi_put_task back_lock requirement Mike Christie
                   ` (10 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This patchset removes the back_lock. To prep for that this patch has
be2iscsi check if the cmd has completed in the driver under the wrb_lock
and then grab the task lock to check if it's completed in libiscsi. We
then get a ref to the task to make sure it doesn't complete from under
us while we process it.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c | 39 +++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index da5ede4ef7f4..fd62258b1b6d 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1228,8 +1228,8 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
 	uint16_t wrb_index, cid, cri_index;
 	struct hwi_controller *phwi_ctrlr;
 	struct wrb_handle *pwrb_handle;
-	struct iscsi_session *session;
 	struct iscsi_task *task;
+	unsigned long flags;
 
 	phwi_ctrlr = phba->phwi_ctrlr;
 	if (is_chip_be2_be3r(phba)) {
@@ -1247,12 +1247,21 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
 	cri_index = BE_GET_CRI_FROM_CID(cid);
 	pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
 	pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index];
-	session = beiscsi_conn->conn->session;
-	spin_lock_bh(&session->back_lock);
+
+	spin_lock_irqsave(&pwrb_context->wrb_lock, flags);
 	task = pwrb_handle->pio_handle;
+	if (task) {
+		spin_lock(&task->lock);
+		if (!iscsi_task_is_completed(task))
+			__iscsi_get_task(task);
+		else
+			task = NULL;
+		spin_unlock(&task->lock);
+	}
+	spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags);
+
 	if (task)
-		__iscsi_put_task(task);
-	spin_unlock_bh(&session->back_lock);
+		iscsi_put_task(task);
 }
 
 static void
@@ -1338,6 +1347,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
 	struct wrb_handle *pwrb_handle;
 	struct iscsi_task *task;
 	uint16_t cri_index = 0;
+	unsigned long flags;
 	uint8_t type;
 
 	phwi_ctrlr = phba->phwi_ctrlr;
@@ -1351,12 +1361,22 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
 	pwrb_handle = pwrb_context->pwrb_handle_basestd[
 		      csol_cqe.wrb_index];
 
-	spin_lock_bh(&session->back_lock);
+	spin_lock_irqsave(&pwrb_context->wrb_lock, flags);
 	task = pwrb_handle->pio_handle;
-	if (!task) {
-		spin_unlock_bh(&session->back_lock);
-		return;
+	if (task) {
+		spin_lock(&task->lock);
+		if (!iscsi_task_is_completed(task))
+			__iscsi_get_task(task);
+		else
+			task = NULL;
+		spin_unlock(&task->lock);
 	}
+	spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags);
+
+	if (!task)
+		return;
+
+	spin_lock_bh(&session->back_lock);
 	type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type;
 
 	switch (type) {
@@ -1398,6 +1418,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
 	}
 
 	spin_unlock_bh(&session->back_lock);
+	iscsi_put_task(task);
 }
 
 /*
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 31/40] scsi: iscsi: rm iscsi_put_task back_lock requirement
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (29 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 30/40] scsi: be2iscsi: prep for back_lock removal Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 32/40] scsi: libiscsi: improve conn_send_pdu API Mike Christie
                   ` (9 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

There is now no need to hold the back_lock when calling iscsi_put_task.
This patch removes the cases we were grabbing it, and syncs up the ref
count naming functions.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c  |  8 ++--
 drivers/scsi/bnx2i/bnx2i_iscsi.c |  2 -
 drivers/scsi/libiscsi.c          | 64 ++++++++++----------------------
 drivers/scsi/qedi/qedi_fw.c      | 11 ++----
 drivers/scsi/qedi/qedi_iscsi.c   |  2 +-
 include/scsi/libiscsi.h          |  3 +-
 6 files changed, 29 insertions(+), 61 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index fd62258b1b6d..9f1f8b95a2f7 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -232,7 +232,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc)
 		return SUCCESS;
 	}
 	/* get a task ref till FW processes the req for the ICD used */
-	__iscsi_get_task(abrt_task);
+	iscsi_get_task(abrt_task);
 	abrt_io_task = abrt_task->dd_data;
 	conn = abrt_task->conn;
 	beiscsi_conn = conn->dd_data;
@@ -287,7 +287,7 @@ static bool beiscsi_dev_reset_sc_iter(struct scsi_cmnd *sc, void *data,
 	}
 
 	/* get a task ref till FW processes the req for the ICD used */
-	__iscsi_get_task(task);
+	iscsi_get_task(task);
 	io_task = task->dd_data;
 	/* mark WRB invalid which have been not processed by FW yet */
 	if (is_chip_be2_be3r(phba)) {
@@ -1253,7 +1253,7 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
 	if (task) {
 		spin_lock(&task->lock);
 		if (!iscsi_task_is_completed(task))
-			__iscsi_get_task(task);
+			iscsi_get_task(task);
 		else
 			task = NULL;
 		spin_unlock(&task->lock);
@@ -1366,7 +1366,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
 	if (task) {
 		spin_lock(&task->lock);
 		if (!iscsi_task_is_completed(task))
-			__iscsi_get_task(task);
+			iscsi_get_task(task);
 		else
 			task = NULL;
 		spin_unlock(&task->lock);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index a964e4e81a0c..41a1a325ab01 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1162,10 +1162,8 @@ static void bnx2i_cleanup_task(struct iscsi_task *task)
 	if (task->state == ISCSI_TASK_ABRT_TMF) {
 		bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
 
-		spin_unlock_bh(&conn->session->back_lock);
 		wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl,
 				msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT));
-		spin_lock_bh(&conn->session->back_lock);
 	}
 	bnx2i_iscsi_unmap_sg_list(task->dd_data);
 }
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 61d73172283e..d4709e20b05c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -486,28 +486,17 @@ static void iscsi_free_task(struct iscsi_task *task)
 	sc->scsi_done(sc);
 }
 
-void __iscsi_get_task(struct iscsi_task *task)
+void iscsi_get_task(struct iscsi_task *task)
 {
 	refcount_inc(&task->refcount);
 }
-EXPORT_SYMBOL_GPL(__iscsi_get_task);
+EXPORT_SYMBOL_GPL(iscsi_get_task);
 
-void __iscsi_put_task(struct iscsi_task *task)
+void iscsi_put_task(struct iscsi_task *task)
 {
 	if (refcount_dec_and_test(&task->refcount))
 		iscsi_free_task(task);
 }
-EXPORT_SYMBOL_GPL(__iscsi_put_task);
-
-void iscsi_put_task(struct iscsi_task *task)
-{
-	struct iscsi_session *session = task->conn->session;
-
-	/* regular RX path uses back_lock */
-	spin_lock_bh(&session->back_lock);
-	__iscsi_put_task(task);
-	spin_unlock_bh(&session->back_lock);
-}
 EXPORT_SYMBOL_GPL(iscsi_put_task);
 
 /**
@@ -536,7 +525,7 @@ static void iscsi_finish_task(struct iscsi_task *task, int state)
 		WRITE_ONCE(conn->ping_task, NULL);
 
 	/* release get from queueing */
-	__iscsi_put_task(task);
+	iscsi_put_task(task);
 }
 
 /**
@@ -587,12 +576,12 @@ static bool cleanup_queued_task(struct iscsi_task *task)
 		 */
 		if (task->state == ISCSI_TASK_RUNNING ||
 		    task->state == ISCSI_TASK_COMPLETED)
-			__iscsi_put_task(task);
+			iscsi_put_task(task);
 	}
 
 	if (conn->task == task) {
 		conn->task = NULL;
-		__iscsi_put_task(task);
+		iscsi_put_task(task);
 	}
 
 	return early_complete;
@@ -788,10 +777,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	return task;
 
 free_task:
-	/* regular RX path uses back_lock */
-	spin_lock(&session->back_lock);
-	__iscsi_put_task(task);
-	spin_unlock(&session->back_lock);
+	iscsi_put_task(task);
 	return NULL;
 }
 
@@ -1156,7 +1142,7 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 		if (iscsi_task_is_completed(task))
 			return NULL;
 
-		__iscsi_get_task(task);
+		iscsi_get_task(task);
 		return task;
 	} else {
 		return iscsi_itt_to_ctask(conn, itt);
@@ -1426,7 +1412,7 @@ struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt)
 		spin_unlock_bh(&task->lock);
 		return NULL;
 	}
-	__iscsi_get_task(task);
+	iscsi_get_task(task);
 	spin_unlock_bh(&task->lock);
 
 	return task;
@@ -1505,11 +1491,9 @@ static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
 {
 	int rc;
 
-	spin_lock_bh(&conn->session->back_lock);
-
 	if (!conn->task) {
 		/* Take a ref so we can access it after xmit_task() */
-		__iscsi_get_task(task);
+		iscsi_get_task(task);
 	} else {
 		/* Already have a ref from when we failed to send it last call */
 		conn->task = NULL;
@@ -1520,7 +1504,7 @@ static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
 	 * case a bad target sends a cmd rsp before we have handled the task.
 	 */
 	if (was_requeue)
-		__iscsi_put_task(task);
+		iscsi_put_task(task);
 
 	/*
 	 * Do this after dropping the extra ref because if this was a requeue
@@ -1532,31 +1516,26 @@ static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
 		 * task and get woken up again.
 		 */
 		conn->task = task;
-		spin_unlock_bh(&conn->session->back_lock);
 		return -ENODATA;
 	}
-	spin_unlock_bh(&conn->session->back_lock);
 
 	spin_unlock_bh(&conn->session->frwd_lock);
 	rc = conn->session->tt->xmit_task(task);
-	spin_lock_bh(&conn->session->frwd_lock);
 	if (!rc) {
 		/* done with this task */
 		task->last_xfer = jiffies;
+		iscsi_put_task(task);
 	}
-	/* regular RX path uses back_lock */
-	spin_lock(&conn->session->back_lock);
+
+	spin_lock_bh(&conn->session->frwd_lock);
 	if (rc) {
 		/*
-		 * get an extra ref that is released next time we access it
-		 * as conn->task above.
+		 * Keep ref from above. Will be released next time we access it
+		 * as conn->task.
 		 */
-		__iscsi_get_task(task);
 		conn->task = task;
 	}
 
-	__iscsi_put_task(task);
-	spin_unlock(&conn->session->back_lock);
 	return rc;
 }
 
@@ -1627,10 +1606,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
 				  running);
 		list_del_init(&task->running);
 		if (iscsi_prep_mgmt_task(conn, task)) {
-			/* regular RX path uses back_lock */
-			spin_lock_bh(&conn->session->back_lock);
-			__iscsi_put_task(task);
-			spin_unlock_bh(&conn->session->back_lock);
+			iscsi_put_task(task);
 			continue;
 		}
 		rc = iscsi_xmit_task(conn, task, false);
@@ -1999,7 +1975,7 @@ static bool iscsi_sc_iter(struct scsi_cmnd *sc, void *data, bool rsvd)
 		spin_unlock_bh(&task->lock);
 		return true;
 	}
-	__iscsi_get_task(task);
+	iscsi_get_task(task);
 	spin_unlock_bh(&task->lock);
 
 	if (iter_data->lun != -1 && iter_data->lun != task->sc->device->lun) {
@@ -2163,7 +2139,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 		spin_unlock(&task->lock);
 		goto done;
 	}
-	__iscsi_get_task(task);
+	iscsi_get_task(task);
 	spin_unlock(&task->lock);
 
 	if (READ_ONCE(session->state) != ISCSI_STATE_LOGGED_IN) {
@@ -2364,7 +2340,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 		goto check_done;
 	}
 
-	__iscsi_get_task(task);
+	iscsi_get_task(task);
 	spin_unlock_bh(&task->lock);
 
 	/*
diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index de5133be1c4b..53099d560eed 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -706,11 +706,8 @@ static void qedi_mtask_completion(struct qedi_ctx *qedi,
 
 static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi,
 					  struct iscsi_cqe_solicited *cqe,
-					  struct iscsi_task *task,
-					  struct qedi_conn *qedi_conn)
+					  struct iscsi_task *task)
 {
-	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct qedi_cmd *cmd = task->dd_data;
 
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UNSOL,
@@ -720,9 +717,7 @@ static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi,
 	cmd->state = RESPONSE_RECEIVED;
 	qedi_clear_task_idx(qedi, cmd->task_id);
 
-	spin_lock_bh(&session->back_lock);
-	__iscsi_put_task(task);
-	spin_unlock_bh(&session->back_lock);
+	iscsi_put_task(task);
 }
 
 static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
@@ -904,7 +899,7 @@ void qedi_fp_process_cqes(struct qedi_work *work)
 		if ((nopout_hdr->itt == RESERVED_ITT) &&
 		    (cqe->cqe_solicited.itid != (u16)RESERVED_ITT)) {
 			qedi_process_nopin_local_cmpl(qedi, &cqe->cqe_solicited,
-						      task, q_conn);
+						      task);
 		} else {
 			/* Process other solicited responses */
 			qedi_mtask_completion(qedi, cqe, task, q_conn, que_idx);
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 77f0445c0198..6276f49b6402 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -65,7 +65,7 @@ static int qedi_eh_abort(struct scsi_cmnd *cmd)
 		return SUCCESS;
 	}
 
-	__iscsi_get_task(task);
+	iscsi_get_task(task);
 	spin_unlock_bh(&task->lock);
 
 	qedi_conn = task->conn->dd_data;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 25590b1458ef..8f623de1476b 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -487,8 +487,7 @@ extern struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *, itt_t);
 extern struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *, itt_t);
 extern void iscsi_requeue_task(struct iscsi_task *task);
 extern void iscsi_put_task(struct iscsi_task *task);
-extern void __iscsi_put_task(struct iscsi_task *task);
-extern void __iscsi_get_task(struct iscsi_task *task);
+extern void iscsi_get_task(struct iscsi_task *task);
 extern void iscsi_complete_scsi_task(struct iscsi_task *task,
 				     uint32_t exp_cmdsn, uint32_t max_cmdsn);
 extern int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 32/40] scsi: libiscsi: improve conn_send_pdu API
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (30 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 31/40] scsi: iscsi: rm iscsi_put_task back_lock requirement Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 33/40] scsi: libiscsi: add max/exp cmdsn lock Mike Christie
                   ` (8 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The conn_send_pdu API is evil in that it returns a pointer to a
iscsi_task, but that task might have been freed already so you can't
touch it. This patch splits the task allocation and transmission, so
functions like iscsi_send_nopout can access the task before its sent.
We then can remove that INVALID_SCSI_TASK dance.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 68 +++++++++++++++++++++++++++++------------
 include/scsi/libiscsi.h |  3 --
 2 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index d4709e20b05c..33f8702faedd 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -671,11 +671,10 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
 }
 
 static struct iscsi_task *
-__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+iscsi_alloc_mgmt_task(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 		      char *data, uint32_t data_size)
 {
 	struct iscsi_session *session = conn->session;
-	struct iscsi_host *ihost = shost_priv(session->host);
 	uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK;
 	struct iscsi_task *task;
 	int sess_state = READ_ONCE(session->state);
@@ -760,25 +759,50 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 						   task->conn->session->age);
 	}
 
-	if (unlikely(READ_ONCE(conn->ping_task) == INVALID_SCSI_TASK))
-		WRITE_ONCE(conn->ping_task, task);
+	return task;
+
+free_task:
+	iscsi_put_task(task);
+	return NULL;
+}
+
+static int iscsi_send_mgmt_task(struct iscsi_task *task)
+{
+	struct iscsi_conn *conn = task->conn;
+	struct iscsi_session *session = conn->session;
+	struct iscsi_host *ihost = shost_priv(conn->session->host);
+	int rc = 0;
 
 	if (!ihost->workq) {
-		if (iscsi_prep_mgmt_task(conn, task))
-			goto free_task;
+		rc = iscsi_prep_mgmt_task(conn, task);
+		if (rc)
+			return rc;
 
-		if (session->tt->xmit_task(task))
-			goto free_task;
+		rc = session->tt->xmit_task(task);
+		if (rc)
+			return rc;
 	} else {
 		list_add_tail(&task->running, &conn->mgmtqueue);
 		iscsi_conn_queue_work(conn);
 	}
 
-	return task;
+	return 0;
+}
 
-free_task:
-	iscsi_put_task(task);
-	return NULL;
+static int __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+				 char *data, uint32_t data_size)
+{
+	struct iscsi_task *task;
+	int rc;
+
+	task = iscsi_alloc_mgmt_task(conn, hdr, data, data_size);
+	if (!task)
+		return -ENOMEM;
+
+	rc = iscsi_send_mgmt_task(task);
+	if (rc)
+		iscsi_put_task(task);
+	return rc;
 }
 
 int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
@@ -789,7 +813,7 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
 	int err = 0;
 
 	spin_lock_bh(&session->frwd_lock);
-	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
+	if (__iscsi_conn_send_pdu(conn, hdr, data, data_size))
 		err = -EPERM;
 	spin_unlock_bh(&session->frwd_lock);
 	return err;
@@ -964,7 +988,6 @@ static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
 	if (!rhdr) {
 		if (READ_ONCE(conn->ping_task))
 			return -EINVAL;
-		WRITE_ONCE(conn->ping_task, INVALID_SCSI_TASK);
 	}
 
 	memset(&hdr, 0, sizeof(struct iscsi_nopout));
@@ -978,10 +1001,18 @@ static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
 	} else
 		hdr.ttt = RESERVED_ITT;
 
-	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
-	if (!task) {
+	task = iscsi_alloc_mgmt_task(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
+	if (!task)
+		return -ENOMEM;
+
+	if (!rhdr)
+		WRITE_ONCE(conn->ping_task, task);
+
+	if (iscsi_send_mgmt_task(task)) {
 		if (!rhdr)
 			WRITE_ONCE(conn->ping_task, NULL);
+		iscsi_put_task(task);
+
 		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
 		return -EIO;
 	} else if (!rhdr) {
@@ -1906,11 +1937,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
 	__must_hold(&session->frwd_lock)
 {
 	struct iscsi_session *session = conn->session;
-	struct iscsi_task *task;
 
-	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
-				      NULL, 0);
-	if (!task) {
+	if (__iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0)) {
 		spin_unlock_bh(&session->frwd_lock);
 		iscsi_conn_printk(KERN_ERR, conn, "Could not send TMF.\n");
 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 8f623de1476b..6853b1dec0e3 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -153,9 +153,6 @@ struct iscsi_task {
 	void			*dd_data;	/* driver/transport data */
 };
 
-/* invalid scsi_task pointer */
-#define	INVALID_SCSI_TASK	(struct iscsi_task *)-1l
-
 static inline int iscsi_task_has_unsol_data(struct iscsi_task *task)
 {
 	return task->unsol_r2t.data_length > task->unsol_r2t.sent;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 33/40] scsi: libiscsi: add max/exp cmdsn lock
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (31 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 32/40] scsi: libiscsi: improve conn_send_pdu API Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 34/40] scsi: iscsi: remove back_lock Mike Christie
                   ` (7 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This patch adds a lock for the max/exp_cmdsn handling. The next patch
will then cleanup the back_lock uses.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c     | 7 +++++--
 drivers/scsi/libiscsi_tcp.c | 2 --
 include/scsi/libiscsi.h     | 7 ++++---
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 33f8702faedd..dbff0ed10e1f 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -103,6 +103,7 @@ static void __iscsi_update_cmdsn(struct iscsi_session *session,
 	if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1))
 		return;
 
+	spin_lock_bh(&session->back_cmdsn_lock);
 	if (exp_cmdsn != session->exp_cmdsn &&
 	    !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn))
 		session->exp_cmdsn = exp_cmdsn;
@@ -110,6 +111,7 @@ static void __iscsi_update_cmdsn(struct iscsi_session *session,
 	if (max_cmdsn != session->max_cmdsn &&
 	    !iscsi_sna_lt(max_cmdsn, session->max_cmdsn))
 		session->max_cmdsn = max_cmdsn;
+	spin_unlock_bh(&session->back_cmdsn_lock);
 }
 
 void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
@@ -3067,6 +3069,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 	spin_lock_init(&session->mgmt_lock);
 	spin_lock_init(&session->frwd_lock);
 	spin_lock_init(&session->back_lock);
+	spin_lock_init(&session->back_cmdsn_lock);
 
 	/* initialize mgmt task pool */
 	if (iscsi_pool_init(&session->mgmt_pool, ISCSI_MGMT_CMDS_MAX,
@@ -3470,9 +3473,9 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
 	 * The target could have reduced it's window size between logins, so
 	 * we have to reset max/exp cmdsn so we can see the new values.
 	 */
-	spin_lock_bh(&session->back_lock);
+	spin_lock_bh(&session->back_cmdsn_lock);
 	session->max_cmdsn = session->exp_cmdsn = session->cmdsn + 1;
-	spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&session->back_cmdsn_lock);
 	/*
 	 * Unblock xmitworker(), Login Phase will pass through.
 	 */
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index b1399ff5ca9e..92e84a19b100 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -559,9 +559,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 	tcp_conn = conn->dd_data;
 	rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
 	/* fill-in new R2T associated with the task */
-	spin_lock(&session->back_lock);
 	iscsi_update_cmdsn(session, (struct iscsi_nopin *)rhdr);
-	spin_unlock(&session->back_lock);
 
 	if (tcp_conn->in.datalen) {
 		iscsi_conn_printk(KERN_ERR, conn,
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 6853b1dec0e3..3715b3d20890 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -296,10 +296,12 @@ struct iscsi_session {
 	struct mutex		eh_mutex;
 
 	/* iSCSI session-wide sequencing */
-	uint32_t		cmdsn;
+	/* Protects exp and max cmdsn */
+	spinlock_t		back_cmdsn_lock;
 	uint32_t		exp_cmdsn;
 	uint32_t		max_cmdsn;
 
+	uint32_t		cmdsn;
 	/* This tracks the reqs queued into the initiator */
 	uint32_t		queued_cmdsn;
 
@@ -356,8 +358,7 @@ struct iscsi_session {
 						 * cmdsn, suspend_bit,     *
 						 * leadconn, _stage,       *
 						 * tmf_state and queues    */
-	spinlock_t		back_lock;	/* protects cmdsn_exp and  *
-						 * cmdsn_max               */
+	spinlock_t		back_lock;
 	/*
 	 * frwd_lock must be held when transitioning states, but not needed
 	 * if just checking the state in the scsi-ml or iscsi callouts.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 34/40] scsi: iscsi: remove back_lock
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (32 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 33/40] scsi: libiscsi: add max/exp cmdsn lock Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 35/40] scsi: libiscsi: update leadconn comments/locking Mike Christie
                   ` (6 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

The back_lock is no longer used so remove it.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/be2iscsi/be_main.c |  11 ----
 drivers/scsi/bnx2i/bnx2i_hwi.c  |  46 ++++---------
 drivers/scsi/libiscsi.c         |  41 +++---------
 drivers/scsi/qedi/qedi_fw.c     | 112 ++++++++++----------------------
 include/scsi/libiscsi.h         |   6 --
 5 files changed, 58 insertions(+), 158 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 9f1f8b95a2f7..e8e01b83965d 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1339,8 +1339,6 @@ static void adapter_get_sol_cqe(struct beiscsi_hba *phba,
 static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
 			     struct beiscsi_hba *phba, struct sol_cqe *psol)
 {
-	struct iscsi_conn *conn = beiscsi_conn->conn;
-	struct iscsi_session *session = conn->session;
 	struct common_sol_cqe csol_cqe = {0};
 	struct hwi_wrb_context *pwrb_context;
 	struct hwi_controller *phwi_ctrlr;
@@ -1376,9 +1374,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
 	if (!task)
 		return;
 
-	spin_lock_bh(&session->back_lock);
 	type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type;
-
 	switch (type) {
 	case HWH_TYPE_IO:
 	case HWH_TYPE_IO_RD:
@@ -1417,7 +1413,6 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
 		break;
 	}
 
-	spin_unlock_bh(&session->back_lock);
 	iscsi_put_task(task);
 }
 
@@ -1610,7 +1605,6 @@ beiscsi_hdl_fwd_pdu(struct beiscsi_conn *beiscsi_conn,
 		    struct hd_async_context *pasync_ctx,
 		    u16 cri)
 {
-	struct iscsi_session *session = beiscsi_conn->conn->session;
 	struct hd_async_handle *pasync_handle, *plast_handle;
 	struct beiscsi_hba *phba = beiscsi_conn->phba;
 	void *phdr = NULL, *pdata = NULL;
@@ -1651,9 +1645,7 @@ beiscsi_hdl_fwd_pdu(struct beiscsi_conn *beiscsi_conn,
 			    pasync_ctx->async_entry[cri].wq.bytes_needed,
 			    pasync_ctx->async_entry[cri].wq.bytes_received);
 	}
-	spin_lock_bh(&session->back_lock);
 	status = beiscsi_complete_pdu(beiscsi_conn, phdr, pdata, dlen);
-	spin_unlock_bh(&session->back_lock);
 	beiscsi_hdl_purge_handles(phba, pasync_ctx, cri);
 	return status;
 }
@@ -4325,7 +4317,6 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
 	struct hwi_wrb_context *pwrb_context = NULL;
 	struct beiscsi_hba *phba = beiscsi_conn->phba;
 	struct iscsi_task *task = beiscsi_conn->task;
-	struct iscsi_session *session = task->conn->session;
 	u32 doorbell = 0;
 
 	/*
@@ -4333,9 +4324,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
 	 * login/startup related tasks.
 	 */
 	beiscsi_conn->login_in_progress = 0;
-	spin_lock_bh(&session->back_lock);
 	beiscsi_cleanup_task(task);
-	spin_unlock_bh(&session->back_lock);
 
 	pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid,
 				       &pwrb_context);
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index af03ad7bc941..f41f9f5fe6cc 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1415,10 +1415,8 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
 	}
 
 done:
-	spin_lock_bh(&session->back_lock);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
-			     conn->data, datalen);
-	spin_unlock_bh(&session->back_lock);
+	iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
+			   conn->data, datalen);
 	iscsi_put_task(task);
 fail:
 	return 0;
@@ -1483,11 +1481,9 @@ static int bnx2i_process_login_resp(struct iscsi_session *session,
 		}
 	}
 
-	spin_lock(&session->back_lock);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
+	iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
 		bnx2i_conn->gen_pdu.resp_buf,
 		bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf);
-	spin_unlock(&session->back_lock);
 	iscsi_put_task(task);
 done:
 	return 0;
@@ -1544,12 +1540,10 @@ static int bnx2i_process_text_resp(struct iscsi_session *session,
 			bnx2i_conn->gen_pdu.resp_wr_ptr++;
 		}
 	}
-	spin_lock(&session->back_lock);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
-			     bnx2i_conn->gen_pdu.resp_buf,
-			     bnx2i_conn->gen_pdu.resp_wr_ptr -
-			     bnx2i_conn->gen_pdu.resp_buf);
-	spin_unlock(&session->back_lock);
+	iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr,
+			   bnx2i_conn->gen_pdu.resp_buf,
+			   bnx2i_conn->gen_pdu.resp_wr_ptr -
+			   bnx2i_conn->gen_pdu.resp_buf);
 	iscsi_put_task(task);
 done:
 	return 0;
@@ -1587,9 +1581,7 @@ static int bnx2i_process_tmf_resp(struct iscsi_session *session,
 	resp_hdr->itt = task->hdr->itt;
 	resp_hdr->response = tmf_cqe->response;
 
-	spin_lock(&session->back_lock);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
-	spin_unlock(&session->back_lock);
+	iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
 	iscsi_put_task(task);
 done:
 	return 0;
@@ -1633,10 +1625,7 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
 	resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait);
 	resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
 
-	spin_lock(&session->back_lock);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
-	spin_unlock(&session->back_lock);
-
+	iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
 	iscsi_put_task(task);
 
 	bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
@@ -1727,10 +1716,7 @@ static int bnx2i_process_nopin_mesg(struct iscsi_session *session,
 		memcpy(&hdr->lun, nop_in->lun, 8);
 	}
 done:
-	spin_lock(&session->back_lock);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
-	spin_unlock(&session->back_lock);
-
+	iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
 	if (task)
 		iscsi_put_task(task);
 
@@ -1765,7 +1751,6 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
 		return;
 	}
 
-	spin_lock(&session->back_lock);
 	resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr;
 	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
 	resp_hdr->opcode = async_cqe->op_code;
@@ -1782,9 +1767,8 @@ static void bnx2i_process_async_mesg(struct iscsi_session *session,
 	resp_hdr->param2 = cpu_to_be16(async_cqe->param2);
 	resp_hdr->param3 = cpu_to_be16(async_cqe->param3);
 
-	__iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
-			     (struct iscsi_hdr *)resp_hdr, NULL, 0);
-	spin_unlock(&session->back_lock);
+	iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data,
+			   (struct iscsi_hdr *)resp_hdr, NULL, 0);
 }
 
 
@@ -1811,7 +1795,6 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
 	} else
 		bnx2i_unsol_pdu_adjust_rq(bnx2i_conn);
 
-	spin_lock(&session->back_lock);
 	hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr;
 	memset(hdr, 0, sizeof(struct iscsi_hdr));
 	hdr->opcode = reject->op_code;
@@ -1820,9 +1803,8 @@ static void bnx2i_process_reject_mesg(struct iscsi_session *session,
 	hdr->max_cmdsn = cpu_to_be32(reject->max_cmd_sn);
 	hdr->exp_cmdsn = cpu_to_be32(reject->exp_cmd_sn);
 	hdr->ffffffff = cpu_to_be32(RESERVED_ITT);
-	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
-			     reject->data_length);
-	spin_unlock(&session->back_lock);
+	iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data,
+			   reject->data_length);
 }
 
 /**
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index dbff0ed10e1f..e7d1b69c07b5 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -538,8 +538,6 @@ static void iscsi_finish_task(struct iscsi_task *task, int state)
  *
  * This is used when drivers do not need or cannot perform
  * lower level pdu processing.
- *
- * Called with session back_lock
  */
 void iscsi_complete_scsi_task(struct iscsi_task *task,
 			      uint32_t exp_cmdsn, uint32_t max_cmdsn)
@@ -831,7 +829,7 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
  * @datalen: len of buffer
  *
  * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
- * then completes the command and task. called under back_lock
+ * then completes the command and task.
  **/
 static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			       struct iscsi_task *task, char *data,
@@ -929,7 +927,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
  * @task: scsi command task
  *
  * iscsi_data_in_rsp sets up the scsi_cmnd fields based on the data received
- * then completes the command and task. called under back_lock
+ * then completes the command and task.
  **/
 static void
 iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
@@ -1033,7 +1031,7 @@ static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
  * @datalen: length of data
  *
  * iscsi_nop_out_rsp handles nop response from use or
- * from user space. called under back_lock
+ * from user space.
  **/
 static int iscsi_nop_out_rsp(struct iscsi_task *task,
 			     struct iscsi_nopin *nop, char *data, int datalen)
@@ -1103,13 +1101,10 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			 * nop-out in response to target's nop-out rejected.
 			 * Just resend.
 			 */
-			/* In RX path we are under back lock */
-			spin_unlock(&conn->session->back_lock);
-			spin_lock(&conn->session->frwd_lock);
+			spin_lock_bh(&conn->session->frwd_lock);
 			iscsi_send_nopout(conn,
 					  (struct iscsi_nopin*)&rejected_pdu);
-			spin_unlock(&conn->session->frwd_lock);
-			spin_lock(&conn->session->back_lock);
+			spin_unlock_bh(&conn->session->frwd_lock);
 		} else {
 			struct iscsi_task *task;
 			/*
@@ -1184,17 +1179,16 @@ struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt)
 EXPORT_SYMBOL_GPL(iscsi_itt_to_task);
 
 /**
- * __iscsi_complete_pdu - complete pdu
+ * iscsi_complete_pdu - complete pdu
  * @conn: iscsi conn
  * @hdr: iscsi header
  * @data: data buffer
  * @datalen: len of data buffer
  *
  * Completes pdu processing by freeing any resources allocated at
- * queuecommand or send generic. session back_lock must be held and verify
- * itt must have been called.
+ * queuecommand or send generic.
  */
-int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			 char *data, int datalen)
 {
 	int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0;
@@ -1238,7 +1232,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	iscsi_put_task(task);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
+EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
 
 /**
  * iscsi_complete_task - complete iscsi task
@@ -1254,8 +1248,6 @@ EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
  * This function should be used by drivers that do not use the libiscsi
  * itt for the PDU that was sent to the target and has access to the
  * iscsi_task struct directly.
- *
- * Session back_lock must be held.
  */
 int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 			struct iscsi_hdr *hdr, char *data, int datalen)
@@ -1280,11 +1272,9 @@ int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 				break;
 
 			/* In RX path we are under back lock */
-			spin_unlock(&session->back_lock);
 			spin_lock(&session->frwd_lock);
 			iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
 			spin_unlock(&session->frwd_lock);
-			spin_lock(&session->back_lock);
 			break;
 		case ISCSI_OP_REJECT:
 			rc = iscsi_handle_reject(conn, hdr, data, datalen);
@@ -1365,18 +1355,6 @@ int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 }
 EXPORT_SYMBOL_GPL(iscsi_complete_task);
 
-int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-		       char *data, int datalen)
-{
-	int rc;
-
-	spin_lock(&conn->session->back_lock);
-	rc = __iscsi_complete_pdu(conn, hdr, data, datalen);
-	spin_unlock(&conn->session->back_lock);
-	return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_complete_pdu);
-
 int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt)
 {
 	struct iscsi_session *session = conn->session;
@@ -3068,7 +3046,6 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 	mutex_init(&session->eh_mutex);
 	spin_lock_init(&session->mgmt_lock);
 	spin_lock_init(&session->frwd_lock);
-	spin_lock_init(&session->back_lock);
 	spin_lock_init(&session->back_cmdsn_lock);
 
 	/* initialize mgmt task pool */
diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
index 53099d560eed..7b66b573882f 100644
--- a/drivers/scsi/qedi/qedi_fw.c
+++ b/drivers/scsi/qedi/qedi_fw.c
@@ -31,13 +31,11 @@ static void qedi_process_logout_resp(struct qedi_ctx *qedi,
 {
 	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
 	struct iscsi_logout_rsp *resp_hdr;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_logout_response_hdr *cqe_logout_response;
 	struct qedi_cmd *cmd;
 
 	cmd = (struct qedi_cmd *)task->dd_data;
 	cqe_logout_response = &cqe->cqe_common.iscsi_hdr.logout_response;
-	spin_lock(&session->back_lock);
 	resp_hdr = (struct iscsi_logout_rsp *)&qedi_conn->gen_pdu.resp_hdr;
 	memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
 	resp_hdr->opcode = cqe_logout_response->opcode;
@@ -55,7 +53,7 @@ static void qedi_process_logout_resp(struct qedi_ctx *qedi,
 		  "Freeing tid=0x%x for cid=0x%x\n",
 		  cmd->task_id, qedi_conn->iscsi_conn_id);
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	if (likely(cmd->io_cmd_in_list)) {
 		cmd->io_cmd_in_list = false;
 		list_del_init(&cmd->io_cmd);
@@ -66,13 +64,11 @@ static void qedi_process_logout_resp(struct qedi_ctx *qedi,
 			  cmd->task_id, qedi_conn->iscsi_conn_id,
 			  &cmd->io_cmd);
 	}
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	cmd->state = RESPONSE_RECEIVED;
 	qedi_clear_task_idx(qedi, cmd->task_id);
 	iscsi_complete_task(conn, task, (struct iscsi_hdr *)resp_hdr, NULL, 0);
-
-	spin_unlock(&session->back_lock);
 }
 
 static void qedi_process_text_resp(struct qedi_ctx *qedi,
@@ -81,7 +77,6 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
 				   struct qedi_conn *qedi_conn)
 {
 	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct e4_iscsi_task_context *task_ctx;
 	struct iscsi_text_rsp *resp_hdr_ptr;
 	struct iscsi_text_response_hdr *cqe_text_response;
@@ -92,7 +87,6 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
 	task_ctx = qedi_get_task_mem(&qedi->tasks, cmd->task_id);
 
 	cqe_text_response = &cqe->cqe_common.iscsi_hdr.text_response;
-	spin_lock(&session->back_lock);
 	resp_hdr_ptr =  (struct iscsi_text_rsp *)&qedi_conn->gen_pdu.resp_hdr;
 	memset(resp_hdr_ptr, 0, sizeof(struct iscsi_hdr));
 	resp_hdr_ptr->opcode = cqe_text_response->opcode;
@@ -118,7 +112,7 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
 		  "Freeing tid=0x%x for cid=0x%x\n",
 		  cmd->task_id, qedi_conn->iscsi_conn_id);
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	if (likely(cmd->io_cmd_in_list)) {
 		cmd->io_cmd_in_list = false;
 		list_del_init(&cmd->io_cmd);
@@ -129,7 +123,7 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
 			  cmd->task_id, qedi_conn->iscsi_conn_id,
 			  &cmd->io_cmd);
 	}
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	cmd->state = RESPONSE_RECEIVED;
 	qedi_clear_task_idx(qedi, cmd->task_id);
@@ -138,7 +132,6 @@ static void qedi_process_text_resp(struct qedi_ctx *qedi,
 			    qedi_conn->gen_pdu.resp_buf,
 			    (qedi_conn->gen_pdu.resp_wr_ptr -
 			     qedi_conn->gen_pdu.resp_buf));
-	spin_unlock(&session->back_lock);
 }
 
 static void qedi_tmf_resp_work(struct work_struct *work)
@@ -166,11 +159,8 @@ static void qedi_tmf_resp_work(struct work_struct *work)
 	iscsi_unblock_session(session->cls_session);
 	qedi_clear_task_idx(qedi, qedi_cmd->task_id);
 
-	spin_lock(&session->back_lock);
 	iscsi_complete_task(conn, qedi_cmd->task,
 			    (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
-	spin_unlock(&session->back_lock);
-
 exit_tmf_resp:
 	kfree(resp_hdr_ptr);
 	clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
@@ -183,7 +173,6 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
 
 {
 	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_tmf_response_hdr *cqe_tmp_response;
 	struct iscsi_tm_rsp *resp_hdr_ptr;
 	struct iscsi_tm *tmf_hdr;
@@ -200,7 +189,6 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
 		return;
 	}
 
-	spin_lock(&session->back_lock);
 	resp_hdr_ptr =  (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf;
 	memset(resp_hdr_ptr, 0, sizeof(struct iscsi_tm_rsp));
 
@@ -219,13 +207,13 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
 
 	tmf_hdr = (struct iscsi_tm *)qedi_cmd->task->hdr;
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	if (likely(qedi_cmd->io_cmd_in_list)) {
 		qedi_cmd->io_cmd_in_list = false;
 		list_del_init(&qedi_cmd->io_cmd);
 		qedi_conn->active_cmd_count--;
 	}
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) ==
 	      ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) ||
@@ -235,7 +223,7 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
 	      ISCSI_TM_FUNC_TARGET_COLD_RESET)) {
 		INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_resp_work);
 		queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work);
-		goto unblock_sess;
+		return;
 	}
 
 	qedi_clear_task_idx(qedi, qedi_cmd->task_id);
@@ -243,9 +231,6 @@ static void qedi_process_tmf_resp(struct qedi_ctx *qedi,
 	iscsi_complete_task(conn, qedi_cmd->task,
 			    (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0);
 	kfree(resp_hdr_ptr);
-
-unblock_sess:
-	spin_unlock(&session->back_lock);
 }
 
 static void qedi_process_login_resp(struct qedi_ctx *qedi,
@@ -254,7 +239,6 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
 				    struct qedi_conn *qedi_conn)
 {
 	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct e4_iscsi_task_context *task_ctx;
 	struct iscsi_login_rsp *resp_hdr_ptr;
 	struct iscsi_login_response_hdr *cqe_login_response;
@@ -266,7 +250,6 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
 	cqe_login_response = &cqe->cqe_common.iscsi_hdr.login_response;
 	task_ctx = qedi_get_task_mem(&qedi->tasks, cmd->task_id);
 
-	spin_lock(&session->back_lock);
 	resp_hdr_ptr =  (struct iscsi_login_rsp *)&qedi_conn->gen_pdu.resp_hdr;
 	memset(resp_hdr_ptr, 0, sizeof(struct iscsi_login_rsp));
 	resp_hdr_ptr->opcode = cqe_login_response->opcode;
@@ -286,13 +269,13 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
 		  ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK;
 	qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	if (likely(cmd->io_cmd_in_list)) {
 		cmd->io_cmd_in_list = false;
 		list_del_init(&cmd->io_cmd);
 		qedi_conn->active_cmd_count--;
 	}
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	memset(task_ctx, '\0', sizeof(*task_ctx));
 
@@ -301,7 +284,6 @@ static void qedi_process_login_resp(struct qedi_ctx *qedi,
 			    (qedi_conn->gen_pdu.resp_wr_ptr -
 			     qedi_conn->gen_pdu.resp_buf));
 
-	spin_unlock(&session->back_lock);
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
 		  "Freeing tid=0x%x for cid=0x%x\n",
 		  cmd->task_id, qedi_conn->iscsi_conn_id);
@@ -404,7 +386,6 @@ static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
 				   struct qedi_conn *qedi_conn, u16 que_idx)
 {
 	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_nop_in_hdr *cqe_nop_in;
 	struct iscsi_nopin *hdr;
 	struct qedi_cmd *cmd;
@@ -414,7 +395,6 @@ static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
 	char bdq_data[QEDI_BDQ_BUF_SIZE];
 	unsigned long flags;
 
-	spin_lock_bh(&session->back_lock);
 	cqe_nop_in = &cqe->cqe_common.iscsi_hdr.nop_in;
 
 	pdu_len = cqe_nop_in->hdr_second_dword &
@@ -450,22 +430,20 @@ static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
 			  "Freeing tid=0x%x for cid=0x%x\n",
 			  cmd->task_id, qedi_conn->iscsi_conn_id);
 		cmd->state = RESPONSE_RECEIVED;
-		spin_lock(&qedi_conn->list_lock);
+		spin_lock_bh(&qedi_conn->list_lock);
 		if (likely(cmd->io_cmd_in_list)) {
 			cmd->io_cmd_in_list = false;
 			list_del_init(&cmd->io_cmd);
 			qedi_conn->active_cmd_count--;
 		}
 
-		spin_unlock(&qedi_conn->list_lock);
+		spin_unlock_bh(&qedi_conn->list_lock);
 		qedi_clear_task_idx(qedi, cmd->task_id);
 	}
 
 done:
 	iscsi_complete_task(conn, task, (struct iscsi_hdr *)hdr, bdq_data,
 			    pdu_len);
-
-	spin_unlock_bh(&session->back_lock);
 	return tgt_async_nop;
 }
 
@@ -475,7 +453,6 @@ static void qedi_process_async_mesg(struct qedi_ctx *qedi,
 				    u16 que_idx)
 {
 	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_async_msg_hdr *cqe_async_msg;
 	struct iscsi_async *resp_hdr;
 	u32 lun[2];
@@ -483,8 +460,6 @@ static void qedi_process_async_mesg(struct qedi_ctx *qedi,
 	char bdq_data[QEDI_BDQ_BUF_SIZE];
 	unsigned long flags;
 
-	spin_lock_bh(&session->back_lock);
-
 	cqe_async_msg = &cqe->cqe_common.iscsi_hdr.async_msg;
 	pdu_len = cqe_async_msg->hdr_second_dword &
 		ISCSI_ASYNC_MSG_HDR_DATA_SEG_LEN_MASK;
@@ -518,8 +493,6 @@ static void qedi_process_async_mesg(struct qedi_ctx *qedi,
 
 	iscsi_complete_task(conn, NULL, (struct iscsi_hdr *)resp_hdr, bdq_data,
 			    pdu_len);
-
-	spin_unlock_bh(&session->back_lock);
 }
 
 static void qedi_process_reject_mesg(struct qedi_ctx *qedi,
@@ -528,13 +501,11 @@ static void qedi_process_reject_mesg(struct qedi_ctx *qedi,
 				     uint16_t que_idx)
 {
 	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_reject_hdr *cqe_reject;
 	struct iscsi_reject *hdr;
 	u32 pld_len, num_bdqs;
 	unsigned long flags;
 
-	spin_lock_bh(&session->back_lock);
 	cqe_reject = &cqe->cqe_common.iscsi_hdr.reject;
 	pld_len = cqe_reject->hdr_second_dword &
 		  ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK;
@@ -560,7 +531,6 @@ static void qedi_process_reject_mesg(struct qedi_ctx *qedi,
 
 	iscsi_complete_task(conn, NULL, (struct iscsi_hdr *)hdr, conn->data,
 			    pld_len);
-	spin_unlock_bh(&session->back_lock);
 }
 
 static void qedi_scsi_completion(struct qedi_ctx *qedi,
@@ -570,7 +540,6 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 {
 	struct scsi_cmnd *sc_cmd;
 	struct qedi_cmd *cmd = task->dd_data;
-	struct iscsi_session *session = conn->session;
 	struct iscsi_scsi_rsp *hdr;
 	struct iscsi_data_in_hdr *cqe_data_in;
 	int datalen = 0;
@@ -585,33 +554,32 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 	cqe_err_bits =
 		cqe->cqe_common.error_bitmap.error_bits.cqe_error_status_bits;
 
-	spin_lock_bh(&session->back_lock);
 	/* get the scsi command */
 	sc_cmd = cmd->scsi_cmd;
 
 	if (!sc_cmd) {
 		QEDI_WARN(&qedi->dbg_ctx, "sc_cmd is NULL!\n");
-		goto error;
+		return;
 	}
 
 	if (!task->sc) {
 		QEDI_WARN(&qedi->dbg_ctx,
 			  "SCp.ptr is NULL, returned in another context.\n");
-		goto error;
+		return;
 	}
 
 	if (!sc_cmd->request) {
 		QEDI_WARN(&qedi->dbg_ctx,
 			  "sc_cmd->request is NULL, sc_cmd=%p.\n",
 			  sc_cmd);
-		goto error;
+		return;
 	}
 
 	if (!sc_cmd->request->q) {
 		QEDI_WARN(&qedi->dbg_ctx,
 			  "request->q is NULL so request is not valid, sc_cmd=%p.\n",
 			  sc_cmd);
-		goto error;
+		return;
 	}
 
 	qedi_iscsi_unmap_sg_list(cmd);
@@ -646,13 +614,13 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 		hdr->flags &= (~ISCSI_FLAG_CMD_OVERFLOW);
 	}
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	if (likely(cmd->io_cmd_in_list)) {
 		cmd->io_cmd_in_list = false;
 		list_del_init(&cmd->io_cmd);
 		qedi_conn->active_cmd_count--;
 	}
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
 		  "Freeing tid=0x%x for cid=0x%x\n",
@@ -664,8 +632,6 @@ static void qedi_scsi_completion(struct qedi_ctx *qedi,
 	qedi_clear_task_idx(qedi, cmd->task_id);
 	iscsi_complete_task(conn, task, (struct iscsi_hdr *)hdr, conn->data,
 			    datalen);
-error:
-	spin_unlock_bh(&session->back_lock);
 }
 
 static void qedi_mtask_completion(struct qedi_ctx *qedi,
@@ -783,13 +749,13 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 
 		qedi_clear_task_idx(qedi_conn->qedi, rtid);
 
-		spin_lock(&qedi_conn->list_lock);
+		spin_lock_bh(&qedi_conn->list_lock);
 		if (likely(dbg_cmd->io_cmd_in_list)) {
 			dbg_cmd->io_cmd_in_list = false;
 			list_del_init(&dbg_cmd->io_cmd);
 			qedi_conn->active_cmd_count--;
 		}
-		spin_unlock(&qedi_conn->list_lock);
+		spin_unlock_bh(&qedi_conn->list_lock);
 		qedi_cmd->state = CLEANUP_RECV;
 		wake_up_interruptible(&qedi_conn->wait_queue);
 	} else if (qedi_conn->cmd_cleanup_req > 0) {
@@ -1070,11 +1036,11 @@ int qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
 	if (rval)
 		return -1;
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
 	qedi_cmd->io_cmd_in_list = true;
 	qedi_conn->active_cmd_count++;
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	qedi_ring_doorbell(qedi_conn);
 	return 0;
@@ -1143,11 +1109,11 @@ int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
 	if (rval)
 		return -1;
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
 	qedi_cmd->io_cmd_in_list = true;
 	qedi_conn->active_cmd_count++;
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	qedi_ring_doorbell(qedi_conn);
 	return 0;
@@ -1162,8 +1128,6 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
 	struct iscsi_tm *tmf_hdr;
 	unsigned int lun = 0;
 	bool lun_reset = false;
-	struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
 
 	/* From recovery, task is NULL or from tmf resp valid task */
 	if (task) {
@@ -1184,10 +1148,7 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
 		  qedi_conn->active_cmd_count, qedi_conn->iscsi_conn_id,
 		  in_recovery, lun_reset);
 
-	if (lun_reset)
-		spin_lock_bh(&session->back_lock);
-
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 
 	list_for_each_entry_safe(cmd, cmd_tmp, &qedi_conn->active_cmd_list,
 				 io_cmd) {
@@ -1218,10 +1179,7 @@ int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn,
 			  &cmd->io_cmd, qedi_conn->iscsi_conn_id);
 	}
 
-	spin_unlock(&qedi_conn->list_lock);
-
-	if (lun_reset)
-		spin_unlock_bh(&session->back_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM,
 		  "cmd_cleanup_req=%d, cid=0x%x\n",
@@ -1392,13 +1350,13 @@ int qedi_fw_cleanup_cmd(struct iscsi_task *ctask)
 	}
 	spin_unlock_bh(&qedi_conn->tmf_work_lock);
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	if (likely(cmd->io_cmd_in_list)) {
 		cmd->io_cmd_in_list = false;
 		list_del_init(&cmd->io_cmd);
 		qedi_conn->active_cmd_count--;
 	}
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	return -1;
 }
@@ -1500,11 +1458,11 @@ int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, struct iscsi_task *mtask)
 	if (rval)
 		return -1;
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
 	qedi_cmd->io_cmd_in_list = true;
 	qedi_conn->active_cmd_count++;
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	qedi_ring_doorbell(qedi_conn);
 	return 0;
@@ -1599,11 +1557,11 @@ int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
 	if (rval)
 		return -1;
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
 	qedi_cmd->io_cmd_in_list = true;
 	qedi_conn->active_cmd_count++;
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	qedi_ring_doorbell(qedi_conn);
 	return 0;
@@ -1669,11 +1627,11 @@ int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
 		nop_out_pdu_header.itt = tid;
 		nop_out_pdu_header.ttt = ISCSI_TTT_ALL_ONES;
 
-		spin_lock(&qedi_conn->list_lock);
+		spin_lock_bh(&qedi_conn->list_lock);
 		list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
 		qedi_cmd->io_cmd_in_list = true;
 		qedi_conn->active_cmd_count++;
-		spin_unlock(&qedi_conn->list_lock);
+		spin_unlock_bh(&qedi_conn->list_lock);
 	}
 
 	/* Fill tx AHS and rx buffer */
@@ -2093,11 +2051,11 @@ int qedi_iscsi_send_ioreq(struct iscsi_task *task)
 	if (rval)
 		return -1;
 
-	spin_lock(&qedi_conn->list_lock);
+	spin_lock_bh(&qedi_conn->list_lock);
 	list_add_tail(&cmd->io_cmd, &qedi_conn->active_cmd_list);
 	cmd->io_cmd_in_list = true;
 	qedi_conn->active_cmd_count++;
-	spin_unlock(&qedi_conn->list_lock);
+	spin_unlock_bh(&qedi_conn->list_lock);
 
 	qedi_ring_doorbell(qedi_conn);
 	return 0;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 3715b3d20890..8001c5a26a00 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -349,16 +349,10 @@ struct iscsi_session {
 	struct iscsi_transport	*tt;
 	struct Scsi_Host	*host;
 	struct iscsi_conn	*leadconn;	/* leading connection */
-	/* Between the forward and the backward locks exists a strict locking
-	 * hierarchy. The mutual exclusion zone protected by the forward lock
-	 * can enclose the mutual exclusion zone protected by the backward lock
-	 * but not vice versa.
-	 */
 	spinlock_t		frwd_lock;	/* protects queued_cmdsn,  *
 						 * cmdsn, suspend_bit,     *
 						 * leadconn, _stage,       *
 						 * tmf_state and queues    */
-	spinlock_t		back_lock;
 	/*
 	 * frwd_lock must be held when transitioning states, but not needed
 	 * if just checking the state in the scsi-ml or iscsi callouts.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 35/40] scsi: libiscsi: update leadconn comments/locking
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (33 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 34/40] scsi: iscsi: remove back_lock Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 36/40] scsi: libiscsi: move ISCSI_SUSPEND_BIT check during queueing Mike Christie
                   ` (5 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

We don't need the frwd_lock to access the lead conn. It's setup at
creation time and then only cleared during destruction. It was from
when we supported MC/s before this code was merged upstream. We've
only supported the single conn session for 15 years now.

This cleans up the non iscsi and SCSI EH paths. The frwd lock is kind
of intertwined with multiple checks in those paths and I have a another
patchset to fix up the tmf handling.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 6 +-----
 include/scsi/libiscsi.h | 4 ++--
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index e7d1b69c07b5..211c56fc6488 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1813,15 +1813,14 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 		goto fault;
 	}
 
-	spin_lock_bh(&session->frwd_lock);
 	conn = session->leadconn;
 	if (!conn) {
-		spin_unlock_bh(&session->frwd_lock);
 		reason = FAILURE_SESSION_FREED;
 		sc->result = DID_NO_CONNECT << 16;
 		goto fault;
 	}
 
+	spin_lock_bh(&session->frwd_lock);
 	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
 		spin_unlock_bh(&session->frwd_lock);
 		reason = FAILURE_SESSION_IN_RECOVERY;
@@ -3441,11 +3440,8 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
 	struct iscsi_session *session = cls_session->dd_data;
 	struct iscsi_conn *conn = cls_conn->dd_data;
 
-	spin_lock_bh(&session->frwd_lock);
 	if (is_leading)
 		session->leadconn = conn;
-	spin_unlock_bh(&session->frwd_lock);
-
 	/*
 	 * The target could have reduced it's window size between logins, so
 	 * we have to reset max/exp cmdsn so we can see the new values.
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 8001c5a26a00..c053de831c2c 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -351,8 +351,8 @@ struct iscsi_session {
 	struct iscsi_conn	*leadconn;	/* leading connection */
 	spinlock_t		frwd_lock;	/* protects queued_cmdsn,  *
 						 * cmdsn, suspend_bit,     *
-						 * leadconn, _stage,       *
-						 * tmf_state and queues    */
+						 * _stage, tmf_state and   *
+						 * queues                  */
 	/*
 	 * frwd_lock must be held when transitioning states, but not needed
 	 * if just checking the state in the scsi-ml or iscsi callouts.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 36/40] scsi: libiscsi: move ISCSI_SUSPEND_BIT check during queueing
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (34 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 35/40] scsi: libiscsi: update leadconn comments/locking Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 37/40] scsi: libiscsi: add new task state for requeues Mike Christie
                   ` (4 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

Drivers that use the iscsi host workqueue already check the
ISCSI_SUSPEND_BIT when we run iscsi_data_xmit, so we don't need to check
it in queuecommand. This patch moves the check to the full offload case.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 211c56fc6488..136531200643 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1821,22 +1821,22 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 	}
 
 	spin_lock_bh(&session->frwd_lock);
-	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
-		spin_unlock_bh(&session->frwd_lock);
-		reason = FAILURE_SESSION_IN_RECOVERY;
-		sc->result = DID_REQUEUE << 16;
-		goto fault;
-	}
-
 	if (iscsi_check_cmdsn_window_closed(conn)) {
 		spin_unlock_bh(&session->frwd_lock);
 		reason = FAILURE_WINDOW_CLOSED;
 		goto reject;
 	}
 
-	task = iscsi_init_scsi_task(conn, sc);
-
 	if (!ihost->workq) {
+		if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
+			spin_unlock_bh(&session->frwd_lock);
+			reason = FAILURE_SESSION_IN_RECOVERY;
+			sc->result = DID_REQUEUE << 16;
+			goto fault;
+		}
+
+		task = iscsi_init_scsi_task(conn, sc);
+
 		reason = iscsi_prep_scsi_cmd_pdu(task);
 		if (reason) {
 			if (reason == -ENOMEM ||  reason == -EACCES) {
@@ -1853,6 +1853,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 			goto prepd_reject;
 		}
 	} else {
+		task = iscsi_init_scsi_task(conn, sc);
 		list_add_tail(&task->running, &conn->cmdqueue);
 		iscsi_conn_queue_work(conn);
 	}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 37/40] scsi: libiscsi: add new task state for requeues
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (35 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 36/40] scsi: libiscsi: move ISCSI_SUSPEND_BIT check during queueing Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 38/40] scsi: libiscsi: replace list_head with llist_head Mike Christie
                   ` (3 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This is a prep patch for the next patch that removes the frwd lock use
when adding to the cmdqueue/requeue. This adds a new state
ISCSI_TASK_REQUEUED so we can quickly check if the cmd is already
requeued for R2T handling.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 16 ++++++++++++----
 include/scsi/libiscsi.h |  1 +
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 136531200643..1c134f721a56 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -574,7 +574,7 @@ static bool cleanup_queued_task(struct iscsi_task *task)
 		 * If it's on a list but still running this could be cleanup
 		 * from a TMF or session recovery.
 		 */
-		if (task->state == ISCSI_TASK_RUNNING ||
+		if (task->state == ISCSI_TASK_REQUEUED ||
 		    task->state == ISCSI_TASK_COMPLETED)
 			iscsi_put_task(task);
 	}
@@ -1565,15 +1565,19 @@ void iscsi_requeue_task(struct iscsi_task *task)
 	 * is handling the r2ts while we are adding new ones
 	 */
 	spin_lock_bh(&conn->session->frwd_lock);
-	if (list_empty(&task->running)) {
-		list_add_tail(&task->running, &conn->requeue);
-	} else {
+	spin_lock(&task->lock);
+	if (task->state == ISCSI_TASK_REQUEUED) {
 		/*
 		 * Don't need the extra ref since it's already requeued and
 		 * has a ref.
 		 */
 		iscsi_put_task(task);
+	} else {
+		task->state = ISCSI_TASK_REQUEUED;
+		list_add_tail(&task->running, &conn->requeue);
 	}
+	spin_unlock(&task->lock);
+
 	iscsi_conn_queue_work(conn);
 	spin_unlock_bh(&conn->session->frwd_lock);
 }
@@ -1639,7 +1643,11 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
 		if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
 			break;
 
+		spin_lock_bh(&task->lock);
+		task->state = ISCSI_TASK_RUNNING;
 		list_del_init(&task->running);
+		spin_unlock_bh(&task->lock);
+
 		rc = iscsi_xmit_task(conn, task, true);
 		if (rc)
 			goto done;
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index c053de831c2c..358701227f7f 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -95,6 +95,7 @@ enum {
 	ISCSI_TASK_FREE,
 	ISCSI_TASK_COMPLETED,
 	ISCSI_TASK_PENDING,
+	ISCSI_TASK_REQUEUED,
 	ISCSI_TASK_RUNNING,
 	ISCSI_TASK_ABRT_TMF,		/* aborted due to TMF */
 };
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 38/40] scsi: libiscsi: replace list_head with llist_head
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (36 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 37/40] scsi: libiscsi: add new task state for requeues Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 39/40] scsi: libiscsi: remove queued_cmdsn Mike Christie
                   ` (2 subsequent siblings)
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

This replaces the cmdqueue and requeue list_heads with llist_heads. We
can do not need the frwd_lock in the queuecommand and recv paths for
this. This patch does not yet cleanup the frwd_lock because we still
need it for the cmdsn handling. When that is fixed up the next patches
then the frwd_lock will be completely removed for the software case.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c | 248 +++++++++++++++++++++++++++++-----------
 include/scsi/libiscsi.h |  23 ++--
 2 files changed, 198 insertions(+), 73 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 1c134f721a56..1b4b6ee246cf 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -730,7 +730,6 @@ iscsi_alloc_mgmt_task(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	refcount_set(&task->refcount, 1);
 	task->conn = conn;
 	task->sc = NULL;
-	INIT_LIST_HEAD(&task->running);
 	task->state = ISCSI_TASK_PENDING;
 
 	if (data_size) {
@@ -782,7 +781,7 @@ static int iscsi_send_mgmt_task(struct iscsi_task *task)
 		if (rc)
 			return rc;
 	} else {
-		list_add_tail(&task->running, &conn->mgmtqueue);
+		list_add_tail(&task->running, &conn->mgmt_exec_list);
 		iscsi_conn_queue_work(conn);
 	}
 
@@ -1564,7 +1563,6 @@ void iscsi_requeue_task(struct iscsi_task *task)
 	 * this may be on the requeue list already if the xmit_task callout
 	 * is handling the r2ts while we are adding new ones
 	 */
-	spin_lock_bh(&conn->session->frwd_lock);
 	spin_lock(&task->lock);
 	if (task->state == ISCSI_TASK_REQUEUED) {
 		/*
@@ -1574,129 +1572,238 @@ void iscsi_requeue_task(struct iscsi_task *task)
 		iscsi_put_task(task);
 	} else {
 		task->state = ISCSI_TASK_REQUEUED;
-		list_add_tail(&task->running, &conn->requeue);
+		llist_add(&task->queue, &conn->requeue);
 	}
 	spin_unlock(&task->lock);
 
 	iscsi_conn_queue_work(conn);
-	spin_unlock_bh(&conn->session->frwd_lock);
 }
 EXPORT_SYMBOL_GPL(iscsi_requeue_task);
 
-/**
- * iscsi_data_xmit - xmit any command into the scheduled connection
- * @conn: iscsi connection
- *
- * Notes:
- *	The function can return -EAGAIN in which case the caller must
- *	re-schedule it again later or recover. '0' return code means
- *	successful xmit.
- **/
-static int iscsi_data_xmit(struct iscsi_conn *conn)
+static bool iscsi_move_tasks(struct llist_head *submit_queue,
+			     struct list_head *exec_queue)
 {
-	struct iscsi_task *task;
-	int rc = 0, cnt;
-
-	spin_lock_bh(&conn->session->frwd_lock);
-	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
-		ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
-		spin_unlock_bh(&conn->session->frwd_lock);
-		return -ENODATA;
-	}
-
-	if (conn->task) {
-		rc = iscsi_xmit_task(conn, conn->task, false);
-	        if (rc)
-		        goto done;
-	}
+	struct iscsi_task *task, *next_task;
+	struct list_head *list_end;
+	struct llist_node *node;
 
 	/*
-	 * process mgmt pdus like nops before commands since we should
-	 * only have one nop-out as a ping from us and targets should not
-	 * overflow us with nop-ins
+	 * The llist_head is in the reverse order cmds were submitted in. We
+	 * are going to reverse it here. If the exec_queue is empty we want
+	 * to add cmds at starting at head. If the exec_queue has cmds from a
+	 * previous call then we need to start adding this batch at the end of
+	 * the last batch.
 	 */
-check_mgmt:
-	while (!list_empty(&conn->mgmtqueue)) {
-		task = list_entry(conn->mgmtqueue.next, struct iscsi_task,
+	list_end = exec_queue->prev;
+
+	node = llist_del_all(submit_queue);
+	llist_for_each_entry_safe(task, next_task, node, queue)
+		list_add(&task->running, list_end);
+
+	return !list_empty(exec_queue);
+}
+
+static void iscsi_move_all_tasks(struct iscsi_conn *conn)
+{
+	iscsi_move_tasks(&conn->requeue, &conn->requeue_exec_list);
+	iscsi_move_tasks(&conn->cmdqueue, &conn->cmd_exec_list);
+}
+
+static int iscsi_exec_mgmt_tasks(struct iscsi_conn *conn)
+{
+	struct iscsi_task *task;
+	int rc;
+
+	while (!list_empty(&conn->mgmt_exec_list)) {
+		task = list_entry(conn->mgmt_exec_list.next, struct iscsi_task,
 				  running);
 		list_del_init(&task->running);
+
 		if (iscsi_prep_mgmt_task(conn, task)) {
 			iscsi_put_task(task);
 			continue;
 		}
+
 		rc = iscsi_xmit_task(conn, task, false);
 		if (rc)
-			goto done;
+			return rc;
 	}
 
-check_requeue:
-	while (!list_empty(&conn->requeue)) {
+	return 0;
+}
+
+static int iscsi_exec_requeued_tasks(struct iscsi_conn *conn, unsigned int *cnt)
+{
+	struct iscsi_task *task;
+	int rc = 0;
+
+	while (!list_empty(&conn->requeue_exec_list)) {
 		/*
 		 * we always do fastlogout - conn stop code will clean up.
 		 */
 		if (READ_ONCE(conn->session->state) == ISCSI_STATE_LOGGING_OUT)
 			break;
 
-		task = list_entry(conn->requeue.next, struct iscsi_task,
-				  running);
+		task = list_entry(conn->requeue_exec_list.next,
+				  struct iscsi_task, running);
 
 		if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
 			break;
 
 		spin_lock_bh(&task->lock);
-		task->state = ISCSI_TASK_RUNNING;
+		/*
+		 * We might have raced and handld multiple R2Ts in one run.
+		 */
 		list_del_init(&task->running);
+		if (task->state == ISCSI_TASK_COMPLETED) {
+			spin_unlock_bh(&task->lock);
+			iscsi_put_task(task);
+			continue;
+		}
+
+		task->state = ISCSI_TASK_RUNNING;
 		spin_unlock_bh(&task->lock);
 
 		rc = iscsi_xmit_task(conn, task, true);
 		if (rc)
-			goto done;
-		if (!list_empty(&conn->mgmtqueue))
-			goto check_mgmt;
+			break;
+		(*cnt)++;
+
+		rc = iscsi_exec_mgmt_tasks(conn);
+		if (rc)
+			break;
 	}
 
-	/* process pending command queue */
-	cnt = 0;
-	while (!list_empty(&conn->cmdqueue)) {
-		task = list_entry(conn->cmdqueue.next, struct iscsi_task,
+	ISCSI_DBG_CONN(conn, "executed %u requeued cmds.\n", *cnt);
+	return rc;
+}
+
+static int iscsi_exec_tasks(struct iscsi_conn *conn,
+			    struct llist_head *submit_queue,
+			    struct list_head *exec_queue,
+			    int (*exec_fn)(struct iscsi_conn *conn,
+					   unsigned int *cnt))
+{
+	unsigned int cnt = 0;
+	int rc = 0;
+
+	while (iscsi_move_tasks(submit_queue, exec_queue)) {
+		rc = exec_fn(conn, &cnt);
+		if (rc)
+			break;
+
+	}
+
+	ISCSI_DBG_CONN(conn, "executed %u total %s cmds.\n", cnt,
+		       exec_fn == iscsi_exec_requeued_tasks ?
+		       "requeued" : "new");
+	return 0;
+}
+
+static int iscsi_exec_cmd_tasks(struct iscsi_conn *conn, unsigned int *cnt)
+{
+	struct iscsi_task *task;
+	int rc = 0;
+
+	while (!list_empty(&conn->cmd_exec_list)) {
+		task = list_entry(conn->cmd_exec_list.next, struct iscsi_task,
 				  running);
 		list_del_init(&task->running);
+
 		if (READ_ONCE(conn->session->state) == ISCSI_STATE_LOGGING_OUT) {
 			fail_scsi_task(task, DID_IMM_RETRY);
 			continue;
 		}
+
 		rc = iscsi_prep_scsi_cmd_pdu(task);
 		if (rc) {
 			if (rc == -ENOMEM || rc == -EACCES)
 				fail_scsi_task(task, DID_IMM_RETRY);
 			else
 				fail_scsi_task(task, DID_ABORT);
+			rc = 0;
 			continue;
 		}
+
 		rc = iscsi_xmit_task(conn, task, false);
 		if (rc)
-			goto done;
+			break;
+		(*cnt)++;
+
 		/*
-		 * we could continuously get new task requests so
-		 * we need to check the mgmt queue for nops that need to
-		 * be sent to aviod starvation
+		 * Make sure we handle target pings quickly so it doesn't
+		 * timeout and drop the conn on us.
 		 */
-		if (!list_empty(&conn->mgmtqueue))
-			goto check_mgmt;
+		rc = iscsi_exec_mgmt_tasks(conn);
+		if (rc)
+			break;
 		/*
 		 * Avoid starving the requeue list if new cmds keep coming in.
 		 * Incase the app tried to batch cmds to us, we allow up to
 		 * queueing limit.
 		 */
-		cnt++;
-		if (cnt == conn->session->host->cmd_per_lun) {
-			cnt = 0;
+		if (*cnt == conn->session->host->cmd_per_lun) {
+			*cnt = 0;
+
+			ISCSI_DBG_CONN(conn, "hit dequeue limit.\n");
 
-			if (!list_empty(&conn->requeue))
-				goto check_requeue;
+			rc = iscsi_exec_tasks(conn, &conn->requeue,
+					      &conn->requeue_exec_list,
+					      iscsi_exec_requeued_tasks);
+			if (rc)
+				break;
 		}
 	}
 
+	ISCSI_DBG_CONN(conn, "executed %u cmds.\n", *cnt);
+	return rc;
+}
+
+/**
+ * iscsi_data_xmit - xmit any command into the scheduled connection
+ * @conn: iscsi connection
+ *
+ * Notes:
+ *	The function can return -EAGAIN in which case the caller must
+ *	re-schedule it again later or recover. '0' return code means
+ *	successful xmit.
+ **/
+static int iscsi_data_xmit(struct iscsi_conn *conn)
+{
+	int rc = 0;
+
+	spin_lock_bh(&conn->session->frwd_lock);
+	if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
+		ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
+		spin_unlock_bh(&conn->session->frwd_lock);
+		return -ENODATA;
+	}
+
+	if (conn->task) {
+		rc = iscsi_xmit_task(conn, conn->task, false);
+		if (rc)
+			goto done;
+	}
+
+	/*
+	 * process mgmt pdus like nops before commands since we should
+	 * only have one nop-out as a ping from us and targets should not
+	 * overflow us with nop-ins
+	 */
+	rc = iscsi_exec_mgmt_tasks(conn);
+	if (rc)
+		goto done;
+
+	rc = iscsi_exec_tasks(conn, &conn->requeue, &conn->requeue_exec_list,
+			      iscsi_exec_requeued_tasks);
+	if (rc)
+		goto done;
+
+	rc = iscsi_exec_tasks(conn, &conn->cmdqueue, &conn->cmd_exec_list,
+			      iscsi_exec_cmd_tasks);
+	if (rc)
+		goto done;
+
 	spin_unlock_bh(&conn->session->frwd_lock);
 	return -ENODATA;
 
@@ -1732,7 +1839,6 @@ static struct iscsi_task *iscsi_init_scsi_task(struct iscsi_conn *conn,
 	task->last_timeout = jiffies;
 	task->last_xfer = jiffies;
 	task->protected = false;
-	INIT_LIST_HEAD(&task->running);
 
 	spin_lock_bh(&task->lock);
 	task->state = ISCSI_TASK_PENDING;
@@ -1862,7 +1968,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 		}
 	} else {
 		task = iscsi_init_scsi_task(conn, sc);
-		list_add_tail(&task->running, &conn->cmdqueue);
+		llist_add(&task->queue, &conn->cmdqueue);
 		iscsi_conn_queue_work(conn);
 	}
 
@@ -2028,6 +2134,8 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, u64 lun, int error)
 		.data = &error,
 	};
 
+	/* Make sure we don't leave cmds in the queues */
+	iscsi_move_all_tasks(conn);
 	iscsi_conn_for_each_sc(conn, &iter_data);
 }
 
@@ -2381,7 +2489,12 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 	ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", sc, task->itt);
 
 	spin_lock_bh(&task->lock);
-	if (task->state == ISCSI_TASK_PENDING) {
+	/*
+	 * If we haven't sent the cmd, but it's still on the cmdqueue we
+	 * don't have an easy way to dequeue that single cmd here.
+	 * iscsi_check_tmf_restrictions will end up handling it.
+	 */
+	if (task->state == ISCSI_TASK_PENDING && !list_empty(&task->running)) {
 		spin_unlock_bh(&task->lock);
 
 		fail_scsi_task(task, DID_ABORT);
@@ -3174,9 +3287,12 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
 
 	timer_setup(&conn->transport_timer, iscsi_check_transport_timeouts, 0);
 
-	INIT_LIST_HEAD(&conn->mgmtqueue);
-	INIT_LIST_HEAD(&conn->cmdqueue);
-	INIT_LIST_HEAD(&conn->requeue);
+	init_llist_head(&conn->cmdqueue);
+	init_llist_head(&conn->requeue);
+	INIT_LIST_HEAD(&conn->cmd_exec_list);
+	INIT_LIST_HEAD(&conn->mgmt_exec_list);
+	INIT_LIST_HEAD(&conn->requeue_exec_list);
+
 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
 	/* allocate login_task used for the login/text sequences */
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 358701227f7f..21579d3dc1f6 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -150,7 +150,8 @@ struct iscsi_task {
 	spinlock_t		lock;
 	int			state;
 	refcount_t		refcount;
-	struct list_head	running;	/* running cmd list */
+	struct llist_node	queue;
+	struct list_head	running;
 	void			*dd_data;	/* driver/transport data */
 };
 
@@ -212,10 +213,18 @@ struct iscsi_conn {
 	struct iscsi_task	*task;		/* xmit task in progress */
 
 	/* xmit */
-	/* items must be added/deleted under frwd lock */
-	struct list_head	mgmtqueue;	/* mgmt (control) xmit queue */
-	struct list_head	cmdqueue;	/* data-path cmd queue */
-	struct list_head	requeue;	/* tasks needing another run */
+	struct llist_head	cmdqueue;	/* data-path cmd queue */
+	struct llist_head	requeue;	/* tasks needing another run */
+
+	/* The frwd_lock is used to access these lists in the xmit and eh path */
+	struct list_head	cmd_exec_list;
+	struct list_head	requeue_exec_list;
+	/*
+	 * The frwd_lock is used to access this list in the xmit, eh and
+	 * submission paths.
+	 */
+	struct list_head	mgmt_exec_list;
+
 	struct work_struct	xmitwork;	/* per-conn. xmit workqueue */
 	unsigned long		suspend_tx;	/* suspend Tx */
 	unsigned long		suspend_rx;	/* suspend Rx */
@@ -352,8 +361,8 @@ struct iscsi_session {
 	struct iscsi_conn	*leadconn;	/* leading connection */
 	spinlock_t		frwd_lock;	/* protects queued_cmdsn,  *
 						 * cmdsn, suspend_bit,     *
-						 * _stage, tmf_state and   *
-						 * queues                  */
+						 * _stage, exec lists, and
+						 * tmf_state    */
 	/*
 	 * frwd_lock must be held when transitioning states, but not needed
 	 * if just checking the state in the scsi-ml or iscsi callouts.
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 39/40] scsi: libiscsi: remove queued_cmdsn
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (37 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 38/40] scsi: libiscsi: replace list_head with llist_head Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-03 23:23 ` [PATCH 40/40] scsi: iscsi_tcp: tell net layer we are sending multiple pdus Mike Christie
  2021-04-08 16:34 ` [PATCH 00/40] iscsi lock and refcount fix ups michael.christie
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

queue_cmdsn was meant to prevent cmds from sitting in the cmdqueue too
long, but iscsi_eh_cmd_timed_out already handles this. By dropping it and
moving the window check to iscsi_data_xmit we will no longer need the
frwd lock for the cmdsn for the iscsi xmit wq based drivers. We also get
the benefit that we can detect when nops open the window, and IOPs seems
to have gone up for the cases we are hitting the window limit.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/libiscsi.c     | 116 +++++++++++++++++++-----------------
 drivers/scsi/libiscsi_tcp.c |   4 +-
 include/scsi/libiscsi.h     |  12 ++--
 3 files changed, 68 insertions(+), 64 deletions(-)

diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 1b4b6ee246cf..dd1e1963dd05 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -93,9 +93,30 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
 
-static void __iscsi_update_cmdsn(struct iscsi_session *session,
-				 uint32_t exp_cmdsn, uint32_t max_cmdsn)
+static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
 {
+	struct iscsi_session *session = conn->session;
+
+	/* make sure we see the updated SNs */
+	smp_rmb();
+	/*
+	 * Check for iSCSI window and take care of CmdSN wrap-around
+	 */
+	if (!iscsi_sna_lte(session->cmdsn, session->max_cmdsn)) {
+		ISCSI_DBG_SESSION(session, "iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u CmdSN %u\n",
+				  session->exp_cmdsn, session->max_cmdsn,
+				  session->cmdsn);
+		return -ENOSPC;
+	}
+	return 0;
+}
+
+static void __iscsi_update_cmdsn(struct iscsi_conn *conn, uint32_t exp_cmdsn,
+				 uint32_t max_cmdsn)
+{
+	struct iscsi_session *session = conn->session;
+	bool win_was_closed = false;
+
 	/*
 	 * standard specifies this check for when to update expected and
 	 * max sequence numbers
@@ -109,14 +130,24 @@ static void __iscsi_update_cmdsn(struct iscsi_session *session,
 		session->exp_cmdsn = exp_cmdsn;
 
 	if (max_cmdsn != session->max_cmdsn &&
-	    !iscsi_sna_lt(max_cmdsn, session->max_cmdsn))
+	    !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) {
+
+		if (iscsi_check_cmdsn_window_closed(conn))
+			win_was_closed = true;
+
 		session->max_cmdsn = max_cmdsn;
+		/* Make sure we see the max_cmdsn from the xmit/queue paths */
+		smp_wmb();
+
+		if (win_was_closed)
+			iscsi_conn_queue_work(conn);
+	}
 	spin_unlock_bh(&session->back_cmdsn_lock);
 }
 
-void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
+void iscsi_update_cmdsn(struct iscsi_conn *conn, struct iscsi_nopin *hdr)
 {
-	__iscsi_update_cmdsn(session, be32_to_cpu(hdr->exp_cmdsn),
+	__iscsi_update_cmdsn(conn, be32_to_cpu(hdr->exp_cmdsn),
 			     be32_to_cpu(hdr->max_cmdsn));
 }
 EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
@@ -429,14 +460,15 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
 	spin_unlock_bh(&task->lock);
 
 	session->cmdsn++;
+	/* make sure window checkers see the update */
+	smp_wmb();
 
 	conn->scsicmd_pdus_cnt++;
 	ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
 			  "itt 0x%x len %d cmdsn %d win %d]\n",
 			  sc->sc_data_direction == DMA_TO_DEVICE ?
 			  "write" : "read", conn->id, sc, sc->cmnd[0],
-			  task->itt, transfer_length,
-			  session->cmdsn,
+			  task->itt, transfer_length, session->cmdsn,
 			  session->max_cmdsn - session->exp_cmdsn + 1);
 	return 0;
 }
@@ -547,7 +579,7 @@ void iscsi_complete_scsi_task(struct iscsi_task *task,
 	ISCSI_DBG_SESSION(conn->session, "[itt 0x%x]\n", task->itt);
 
 	conn->last_recv = jiffies;
-	__iscsi_update_cmdsn(conn->session, exp_cmdsn, max_cmdsn);
+	__iscsi_update_cmdsn(conn, exp_cmdsn, max_cmdsn);
 	iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 }
 EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
@@ -593,7 +625,6 @@ static bool cleanup_queued_task(struct iscsi_task *task)
  */
 static void fail_scsi_task(struct iscsi_task *task, int err)
 {
-	struct iscsi_conn *conn = task->conn;
 	struct scsi_cmnd *sc;
 	int state;
 
@@ -603,15 +634,8 @@ static void fail_scsi_task(struct iscsi_task *task, int err)
 		return;
 	}
 
-	if (task->state == ISCSI_TASK_PENDING) {
-		/*
-		 * cmd never made it to the xmit thread, so we should not count
-		 * the cmd in the sequencing
-		 */
-		conn->session->queued_cmdsn--;
-		/* it was never sent so just complete like normal */
-		state = ISCSI_TASK_COMPLETED;
-	} else if (err == DID_TRANSPORT_DISRUPTED)
+	if (task->state == ISCSI_TASK_PENDING ||
+	    err == DID_TRANSPORT_DISRUPTED)
 		state = ISCSI_TASK_COMPLETED;
 	else
 		state = ISCSI_TASK_ABRT_TMF;
@@ -652,7 +676,6 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn,
 		 */
 		if (conn->c_stage == ISCSI_CONN_STARTED &&
 		    !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
-			session->queued_cmdsn++;
 			session->cmdsn++;
 		}
 	}
@@ -838,7 +861,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	struct iscsi_session *session = conn->session;
 	struct scsi_cmnd *sc = task->sc;
 
-	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+	iscsi_update_cmdsn(conn, (struct iscsi_nopin *)rhdr);
 	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
 
 	sc->result = (DID_OK << 16) | rhdr->cmd_status;
@@ -938,7 +961,7 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
 		return;
 
-	iscsi_update_cmdsn(conn->session, (struct iscsi_nopin *)hdr);
+	iscsi_update_cmdsn(conn, (struct iscsi_nopin *)hdr);
 	sc->result = (DID_OK << 16) | rhdr->cmd_status;
 	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
 	if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
@@ -1258,7 +1281,7 @@ int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 			  opcode, conn->id, task ? task->itt : ~0U, datalen);
 
 	if (!task) {
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+		iscsi_update_cmdsn(conn, (struct iscsi_nopin *)hdr);
 
 		switch(opcode) {
 		case ISCSI_OP_NOOP_IN:
@@ -1303,7 +1326,7 @@ int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 		iscsi_data_in_rsp(conn, hdr, task);
 		break;
 	case ISCSI_OP_LOGOUT_RSP:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+		iscsi_update_cmdsn(conn, (struct iscsi_nopin *)hdr);
 		if (datalen) {
 			rc = ISCSI_ERR_PROTO;
 			break;
@@ -1312,14 +1335,14 @@ int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 		goto recv_pdu;
 	case ISCSI_OP_LOGIN_RSP:
 	case ISCSI_OP_TEXT_RSP:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+		iscsi_update_cmdsn(conn, (struct iscsi_nopin *)hdr);
 		/*
 		 * login related PDU's exp_statsn is handled in
 		 * userspace
 		 */
 		goto recv_pdu;
 	case ISCSI_OP_SCSI_TMFUNC_RSP:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+		iscsi_update_cmdsn(conn, (struct iscsi_nopin *)hdr);
 		if (datalen) {
 			rc = ISCSI_ERR_PROTO;
 			break;
@@ -1329,7 +1352,7 @@ int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 		iscsi_finish_task(task, ISCSI_TASK_COMPLETED);
 		break;
 	case ISCSI_OP_NOOP_IN:
-		iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+		iscsi_update_cmdsn(conn, (struct iscsi_nopin *)hdr);
 		if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
 			rc = ISCSI_ERR_PROTO;
 			break;
@@ -1479,23 +1502,6 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_failure);
 
-static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
-{
-	struct iscsi_session *session = conn->session;
-
-	/*
-	 * Check for iSCSI window and take care of CmdSN wrap-around
-	 */
-	if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
-		ISCSI_DBG_SESSION(session, "iSCSI CmdSN closed. ExpCmdSn "
-				  "%u MaxCmdSN %u CmdSN %u/%u\n",
-				  session->exp_cmdsn, session->max_cmdsn,
-				  session->cmdsn, session->queued_cmdsn);
-		return -ENOSPC;
-	}
-	return 0;
-}
-
 static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
 			   bool was_requeue)
 {
@@ -1706,6 +1712,10 @@ static int iscsi_exec_cmd_tasks(struct iscsi_conn *conn, unsigned int *cnt)
 	int rc = 0;
 
 	while (!list_empty(&conn->cmd_exec_list)) {
+		rc = iscsi_check_cmdsn_window_closed(conn);
+		if (rc)
+			return rc;
+
 		task = list_entry(conn->cmd_exec_list.next, struct iscsi_task,
 				  running);
 		list_del_init(&task->running);
@@ -1934,14 +1944,14 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 		goto fault;
 	}
 
-	spin_lock_bh(&session->frwd_lock);
-	if (iscsi_check_cmdsn_window_closed(conn)) {
-		spin_unlock_bh(&session->frwd_lock);
-		reason = FAILURE_WINDOW_CLOSED;
-		goto reject;
-	}
-
 	if (!ihost->workq) {
+		spin_lock_bh(&session->frwd_lock);
+		if (iscsi_check_cmdsn_window_closed(conn)) {
+			spin_unlock_bh(&session->frwd_lock);
+			reason = FAILURE_WINDOW_CLOSED;
+			goto reject;
+		}
+
 		if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
 			spin_unlock_bh(&session->frwd_lock);
 			reason = FAILURE_SESSION_IN_RECOVERY;
@@ -1966,14 +1976,13 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 			reason = FAILURE_SESSION_NOT_READY;
 			goto prepd_reject;
 		}
+		spin_unlock_bh(&session->frwd_lock);
 	} else {
 		task = iscsi_init_scsi_task(conn, sc);
 		llist_add(&task->queue, &conn->cmdqueue);
 		iscsi_conn_queue_work(conn);
 	}
 
-	session->queued_cmdsn++;
-	spin_unlock_bh(&session->frwd_lock);
 	return 0;
 
 prepd_reject:
@@ -3157,7 +3166,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
 	session->abort_timeout = 10;
 	session->scsi_cmds_max = scsi_cmds;
 	session->cmds_max = scsi_cmds + ISCSI_INFLIGHT_MGMT_MAX;
-	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
+	session->cmdsn = initial_cmdsn;
 	session->exp_cmdsn = initial_cmdsn + 1;
 	session->max_cmdsn = initial_cmdsn + 1;
 	session->max_r2t = 1;
@@ -3409,7 +3418,6 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
 	spin_lock_bh(&session->frwd_lock);
 	conn->c_stage = ISCSI_CONN_STARTED;
 	WRITE_ONCE(session->state, ISCSI_STATE_LOGGED_IN);
-	session->queued_cmdsn = session->cmdsn;
 
 	conn->last_recv = jiffies;
 	conn->last_ping = jiffies;
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 92e84a19b100..c38e39b1546a 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -496,7 +496,7 @@ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task)
 	 * is status.
 	 */
 	if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS))
-		iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr);
+		iscsi_update_cmdsn(conn, (struct iscsi_nopin *)rhdr);
 
 	if (tcp_conn->in.datalen == 0)
 		return 0;
@@ -559,7 +559,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 	tcp_conn = conn->dd_data;
 	rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr;
 	/* fill-in new R2T associated with the task */
-	iscsi_update_cmdsn(session, (struct iscsi_nopin *)rhdr);
+	iscsi_update_cmdsn(conn, (struct iscsi_nopin *)rhdr);
 
 	if (tcp_conn->in.datalen) {
 		iscsi_conn_printk(KERN_ERR, conn,
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 21579d3dc1f6..12bdaee3b87e 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -310,10 +310,7 @@ struct iscsi_session {
 	spinlock_t		back_cmdsn_lock;
 	uint32_t		exp_cmdsn;
 	uint32_t		max_cmdsn;
-
 	uint32_t		cmdsn;
-	/* This tracks the reqs queued into the initiator */
-	uint32_t		queued_cmdsn;
 
 	/* configuration */
 	int			abort_timeout;
@@ -359,10 +356,9 @@ struct iscsi_session {
 	struct iscsi_transport	*tt;
 	struct Scsi_Host	*host;
 	struct iscsi_conn	*leadconn;	/* leading connection */
-	spinlock_t		frwd_lock;	/* protects queued_cmdsn,  *
-						 * cmdsn, suspend_bit,     *
-						 * _stage, exec lists, and
-						 * tmf_state    */
+	spinlock_t		frwd_lock;	/* protects cmdsn for offload,*
+						 * suspend_bit, _stage, exec  *
+						 * lists, and tmf_state       */
 	/*
 	 * frwd_lock must be held when transitioning states, but not needed
 	 * if just checking the state in the scsi-ml or iscsi callouts.
@@ -474,7 +470,7 @@ extern void iscsi_conn_queue_work(struct iscsi_conn *conn);
 /*
  * pdu and task processing
  */
-extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);
+extern void iscsi_update_cmdsn(struct iscsi_conn *conn, struct iscsi_nopin *hdr);
 extern void iscsi_prep_data_out_pdu(struct iscsi_task *task,
 				    struct iscsi_r2t_info *r2t,
 				    struct iscsi_data *hdr);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH 40/40] scsi: iscsi_tcp: tell net layer we are sending multiple pdus
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (38 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 39/40] scsi: libiscsi: remove queued_cmdsn Mike Christie
@ 2021-04-03 23:23 ` Mike Christie
  2021-04-08 16:34 ` [PATCH 00/40] iscsi lock and refcount fix ups michael.christie
  40 siblings, 0 replies; 44+ messages in thread
From: Mike Christie @ 2021-04-03 23:23 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb
  Cc: Mike Christie

If we are executing a multiple pdu sequence, tell the network layer we
will have more data.

This also sets MSG_MORE if the app batched cmds and we know we have more
than one that are going to be sent.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/scsi/iscsi_tcp.c | 16 +++++++++++-----
 drivers/scsi/libiscsi.c  | 10 ++++++++++
 include/scsi/libiscsi.h  |  1 +
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index eff5f8456ced..a85688d7ae2b 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -246,7 +246,8 @@ iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)
 /**
  * iscsi_sw_tcp_xmit_segment - transmit segment
  * @tcp_conn: the iSCSI TCP connection
- * @segment: the buffer to transmnit
+ * @task: iscsi task we are transmitting data for
+ * @segment: the buffer to transmit
  *
  * This function transmits as much of the buffer as
  * the network layer will accept, and returns the number of
@@ -257,6 +258,7 @@ iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)
  * it will retrieve the hash value and send it as well.
  */
 static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
+				     struct iscsi_task *task,
 				     struct iscsi_segment *segment)
 {
 	struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
@@ -273,7 +275,10 @@ static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
 		offset = segment->copied;
 		copy = segment->size - offset;
 
-		if (segment->total_copied + segment->size < segment->total_size)
+		if (segment->total_copied + segment->size <
+		    segment->total_size ||
+		    !(task->hdr->flags & ISCSI_FLAG_CMD_FINAL) ||
+		    !iscsi_xmit_list_is_empty(tcp_conn->iscsi_conn))
 			flags |= MSG_MORE;
 
 		/* Use sendpage if we can; else fall back to sendmsg */
@@ -304,8 +309,9 @@ static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
 /**
  * iscsi_sw_tcp_xmit - TCP transmit
  * @conn: iscsi connection
+ * @task: iscsi task to send data for
  **/
-static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)
+static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
 {
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
@@ -314,7 +320,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)
 	int rc = 0;
 
 	while (1) {
-		rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment);
+		rc = iscsi_sw_tcp_xmit_segment(tcp_conn, task, segment);
 		/*
 		 * We may not have been able to send data because the conn
 		 * is getting stopped. libiscsi will know so propagate err
@@ -382,7 +388,7 @@ static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task)
 	noreclaim_flag = memalloc_noreclaim_save();
 
 	while (iscsi_sw_tcp_xmit_qlen(conn)) {
-		rc = iscsi_sw_tcp_xmit(conn);
+		rc = iscsi_sw_tcp_xmit(conn, task);
 		if (rc == 0) {
 			rc = -EAGAIN;
 			break;
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index dd1e1963dd05..168afcb63bcf 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1609,6 +1609,16 @@ static bool iscsi_move_tasks(struct llist_head *submit_queue,
 	return !list_empty(exec_queue);
 }
 
+inline bool iscsi_xmit_list_is_empty(struct iscsi_conn *conn)
+{
+	if (!list_empty(&conn->cmd_exec_list) ||
+	    !list_empty(&conn->requeue_exec_list))
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(iscsi_xmit_list_is_empty);
+
 static void iscsi_move_all_tasks(struct iscsi_conn *conn)
 {
 	iscsi_move_tasks(&conn->requeue, &conn->requeue_exec_list);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 12bdaee3b87e..f53f41f032d5 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -491,6 +491,7 @@ extern void iscsi_complete_scsi_task(struct iscsi_task *task,
 extern int iscsi_complete_task(struct iscsi_conn *conn, struct iscsi_task *task,
 			       struct iscsi_hdr *hdr, char *data, int datalen);
 extern int iscsi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd);
+extern bool iscsi_xmit_list_is_empty(struct iscsi_conn *conn);
 
 struct iscsi_sc_iter_data {
 	struct iscsi_conn *conn;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH 01/40] scsi: iscsi: fix shost->max_id use
  2021-04-03 23:22 ` [PATCH 01/40] scsi: iscsi: fix shost->max_id use Mike Christie
@ 2021-04-05 16:00   ` Lee Duncan
  0 siblings, 0 replies; 44+ messages in thread
From: Lee Duncan @ 2021-04-05 16:00 UTC (permalink / raw)
  To: Mike Christie, cleech, njavali, mrangankar,
	GR-QLogic-Storage-Upstream, varun, subbu.seetharaman,
	ketan.mukadam, jitendra.bhivare, martin.petersen, linux-scsi,
	jejb

On 4/3/21 4:22 PM, Mike Christie wrote:
> The iscsi offload drivers are setting the shost->max_id to the max number
> of sessions they support. The problem is that max_id is not the max number
> of targets but the highest identifier the targets can have. To use it to
> limit the number of targets we need to set it to max sessions - 1, or we
> can end up with a session we might not have preallocated resources for.
> 
> Signed-off-by: Mike Christie <michael.christie@oracle.com>
> ---
>  drivers/scsi/be2iscsi/be_main.c  | 4 ++--
>  drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +-
>  drivers/scsi/cxgbi/libcxgbi.c    | 4 ++--
>  drivers/scsi/qedi/qedi_main.c    | 2 +-
>  4 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
> index 90fcddb76f46..56bd4441a789 100644
> --- a/drivers/scsi/be2iscsi/be_main.c
> +++ b/drivers/scsi/be2iscsi/be_main.c
> @@ -416,7 +416,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
>  			"beiscsi_hba_alloc - iscsi_host_alloc failed\n");
>  		return NULL;
>  	}
> -	shost->max_id = BE2_MAX_SESSIONS;
> +	shost->max_id = BE2_MAX_SESSIONS - 1;
>  	shost->max_channel = 0;
>  	shost->max_cmd_len = BEISCSI_MAX_CMD_LEN;
>  	shost->max_lun = BEISCSI_NUM_MAX_LUN;
> @@ -5318,7 +5318,7 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba)
>  	/* Re-enable UER. If different TPE occurs then it is recoverable. */
>  	beiscsi_set_uer_feature(phba);
>  
> -	phba->shost->max_id = phba->params.cxns_per_ctrl;
> +	phba->shost->max_id = phba->params.cxns_per_ctrl - 1;
>  	phba->shost->can_queue = phba->params.ios_per_ctrl;
>  	ret = beiscsi_init_port(phba);
>  	if (ret < 0) {
> diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
> index 1e6d8f62ea3c..37f5b719050e 100644
> --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
> +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
> @@ -791,7 +791,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
>  		return NULL;
>  	shost->dma_boundary = cnic->pcidev->dma_mask;
>  	shost->transportt = bnx2i_scsi_xport_template;
> -	shost->max_id = ISCSI_MAX_CONNS_PER_HBA;
> +	shost->max_id = ISCSI_MAX_CONNS_PER_HBA - 1;
>  	shost->max_channel = 0;
>  	shost->max_lun = 512;
>  	shost->max_cmd_len = 16;
> diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
> index f078b3c4e083..ecb134b4699f 100644
> --- a/drivers/scsi/cxgbi/libcxgbi.c
> +++ b/drivers/scsi/cxgbi/libcxgbi.c
> @@ -337,7 +337,7 @@ void cxgbi_hbas_remove(struct cxgbi_device *cdev)
>  EXPORT_SYMBOL_GPL(cxgbi_hbas_remove);
>  
>  int cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun,
> -		unsigned int max_id, struct scsi_host_template *sht,
> +		unsigned int max_conns, struct scsi_host_template *sht,
>  		struct scsi_transport_template *stt)
>  {
>  	struct cxgbi_hba *chba;
> @@ -357,7 +357,7 @@ int cxgbi_hbas_add(struct cxgbi_device *cdev, u64 max_lun,
>  
>  		shost->transportt = stt;
>  		shost->max_lun = max_lun;
> -		shost->max_id = max_id;
> +		shost->max_id = max_conns - 1;
>  		shost->max_channel = 0;
>  		shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE;
>  
> diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
> index 47ad64b06623..0aa0061dad40 100644
> --- a/drivers/scsi/qedi/qedi_main.c
> +++ b/drivers/scsi/qedi/qedi_main.c
> @@ -642,7 +642,7 @@ static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev)
>  		goto exit_setup_shost;
>  	}
>  
> -	shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA;
> +	shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA - 1;
>  	shost->max_channel = 0;
>  	shost->max_lun = ~0;
>  	shost->max_cmd_len = 16;
> 

Reviewed-by: Lee Duncan <lduncan@suse.com>


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 03/40] scsi: iscsi: remove unneeded task state check
  2021-04-03 23:22 ` [PATCH 03/40] scsi: iscsi: remove unneeded task state check Mike Christie
@ 2021-04-05 16:03   ` Lee Duncan
  0 siblings, 0 replies; 44+ messages in thread
From: Lee Duncan @ 2021-04-05 16:03 UTC (permalink / raw)
  To: Mike Christie, cleech, njavali, mrangankar,
	GR-QLogic-Storage-Upstream, varun, subbu.seetharaman,
	ketan.mukadam, jitendra.bhivare, martin.petersen, linux-scsi,
	jejb

On 4/3/21 4:22 PM, Mike Christie wrote:
> The patch:
> 
> commit 5923d64b7ab6 ("scsi: libiscsi: Drop taskqueuelock")
> 
> added an extra task->state because for
> 
> commit 6f8830f5bbab ("scsi: libiscsi: add lock around task lists to fix
> list corruption regression")
> 
> we didn't know why we ended up with cmds on the list and thought it
> might have been a bad target sending a response while we were still
> sending the cmd. It turns out the bug was just a race in libiscsi/
> libiscsi_tcp where
> 
> 1. iscsi_tcp_r2t_rsp queues a r2t to tcp_task->r2tqueue.
> 2. iscsi_tcp_task_xmit runs iscsi_tcp_get_curr_r2t and sees we have a r2t.
> It dequeues it and iscsi_tcp_task_xmit starts to process it.
> 3. iscsi_tcp_r2t_rsp runs iscsi_requeue_task and puts the task on the
> requeue list.
> 4. iscsi_tcp_task_xmit sends the data for r2t. This is the final chunk of
> data, so the cmd is done.
> 5. target sends the response.
> 6. On a different CPU from #3, iscsi_complete_task processes the response.
> Since there was no common lock for the list, the lists/tasks pointers are
> not fully in sync, so could end up with list corruption.
> 
> Since it was just a race on our side, this patch removes the extra check.
> 
> Signed-off-by: Mike Christie <michael.christie@oracle.com>
> ---
>  drivers/scsi/libiscsi.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
> index 643edc4eb6fe..94cb9410230a 100644
> --- a/drivers/scsi/libiscsi.c
> +++ b/drivers/scsi/libiscsi.c
> @@ -562,16 +562,19 @@ static bool cleanup_queued_task(struct iscsi_task *task)
>  	struct iscsi_conn *conn = task->conn;
>  	bool early_complete = false;
>  
> -	/* Bad target might have completed task while it was still running */
> +	/*
> +	 * We might have raced where we handled a R2T early and got a response
> +	 * but have not yet taken the task off the requeue list, then a TMF or
> +	 * recovery happened and so we can still see it here.
> +	 */
>  	if (task->state == ISCSI_TASK_COMPLETED)
>  		early_complete = true;
>  
>  	if (!list_empty(&task->running)) {
>  		list_del_init(&task->running);
>  		/*
> -		 * If it's on a list but still running, this could be from
> -		 * a bad target sending a rsp early, cleanup from a TMF, or
> -		 * session recovery.
> +		 * If it's on a list but still running this could be cleanup
> +		 * from a TMF or session recovery.
>  		 */
>  		if (task->state == ISCSI_TASK_RUNNING ||
>  		    task->state == ISCSI_TASK_COMPLETED)
> @@ -1470,7 +1473,7 @@ static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
>  	}
>  	/* regular RX path uses back_lock */
>  	spin_lock(&conn->session->back_lock);
> -	if (rc && task->state == ISCSI_TASK_RUNNING) {
> +	if (rc) {
>  		/*
>  		 * get an extra ref that is released next time we access it
>  		 * as conn->task above.
> 

Reviewed-by: Lee Duncan <lduncan@suse.com>


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 00/40] iscsi lock and refcount fix ups
  2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
                   ` (39 preceding siblings ...)
  2021-04-03 23:23 ` [PATCH 40/40] scsi: iscsi_tcp: tell net layer we are sending multiple pdus Mike Christie
@ 2021-04-08 16:34 ` michael.christie
  40 siblings, 0 replies; 44+ messages in thread
From: michael.christie @ 2021-04-08 16:34 UTC (permalink / raw)
  To: lduncan, cleech, njavali, mrangankar, GR-QLogic-Storage-Upstream,
	varun, subbu.seetharaman, ketan.mukadam, jitendra.bhivare,
	martin.petersen, linux-scsi, jejb

Lee and Manish and others,

Don't review this patchset.

I'm hitting some issues with the code before my patchset. It will be easier
to test/review if I fix them first.

Lee, I'll send patches for the ep_disconnect/iscsi_conn_stop issue.

Manish, I found some bugs in qedi that we might be hitting:

- it shouldn't use iscsi_block_session in the tmf path
- libiscsi and qedi can get out of sync in the tmf paths and cleanup the
wrong cmds.


On 4/3/21 6:22 PM, Mike Christie wrote:
> The following patches apply over Linus's tree or Martin's staging branch.
> They fix up the locking and refcount handling in the iscsi code so for
> software iscsi we longer need a lock when going from queuecommand to the
> xmit thread and no longer need a common iscsi level lock between the xmit
> thread and completion paths.
> 
> For simple throughput workloads like
> 
> fio --filename=/dev/sdb --direct=1 --rw=randwrite --bs=256k \
> --ioengine=libaio --iodepth=128 --numjobs=1 --time_based \
> --group_reporting --name=throughput --runtime=120
> 
> I'm able to get throughput from 24 Gb/s to 28 where I then hit a
> bottleneck on the target side.
> 
> IOPs might increase by around 10% in some cases with:
> 
> fio --filename=/dev/sdb --direct=1 --rw=randwrite --bs=4k \
> --ioengine=libaio --iodepth=128 --numjobs=1 --time_based \
> --group_reporting --name=throughput --runtime=120
> 
> I'm still debugging some target side issues.
> 
> A bigger advantage I'm seeing with the patches is that for setups where
> you have software iscsi sharing CPUs with other subsystems like vhost
> IOPs can increase by up to 20%.
> 
> Notes:
> - I've tested iscsi_tcp, ib_iser, be2iscsi and qedi. I don't have cxgbi
> or bnx2i hardware, but cxbgi changes were API only.
> 
> - Lee, the first 2 patches are new bug fixes. The first half are then
> similar to what you saw before. I was not sure how far through them you
> were. The second half was the part that removed the back lock and frwd
> lock from iscsi_queuecommand are new.
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2021-04-08 16:35 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-03 23:22 [PATCH 00/40] iscsi lock and refcount fix ups Mike Christie
2021-04-03 23:22 ` [PATCH 01/40] scsi: iscsi: fix shost->max_id use Mike Christie
2021-04-05 16:00   ` Lee Duncan
2021-04-03 23:22 ` [PATCH 02/40] scsi: libiscsi: fix write starvation Mike Christie
2021-04-03 23:22 ` [PATCH 03/40] scsi: iscsi: remove unneeded task state check Mike Christie
2021-04-05 16:03   ` Lee Duncan
2021-04-03 23:22 ` [PATCH 04/40] scsi: libiscsi: drop frwd lock for session state Mike Christie
2021-04-03 23:22 ` [PATCH 05/40] scsi: iscsi: add task prealloc/free callouts Mike Christie
2021-04-03 23:22 ` [PATCH 06/40] scsi: qedi: implement alloc_task_priv/free_task_priv Mike Christie
2021-04-03 23:23 ` [PATCH 07/40] scsi: bnx2i: " Mike Christie
2021-04-03 23:23 ` [PATCH 08/40] scsi: iser, be2iscsi, qla4xxx: set scsi_host_template cmd_size Mike Christie
2021-04-03 23:23 ` [PATCH 09/40] scsi: bnx2i: " Mike Christie
2021-04-03 23:23 ` [PATCH 10/40] scsi: qedi: " Mike Christie
2021-04-03 23:23 ` [PATCH 11/40] scsi: iscsi_tcp, libcxgbi: use init_cmd_priv/exit_cmd_priv Mike Christie
2021-04-03 23:23 ` [PATCH 12/40] scsi: libiscsi: use scsi_host_busy_iter Mike Christie
2021-04-03 23:23 ` [PATCH 13/40] scsi: be2iscsi: " Mike Christie
2021-04-03 23:23 ` [PATCH 14/40] scsi: libiscsi rename iscsi_complete_task Mike Christie
2021-04-03 23:23 ` [PATCH 15/40] scsi: libiscsi: add helper to complete a iscsi task Mike Christie
2021-04-03 23:23 ` [PATCH 16/40] scsi: be2iscsi: switch to iscsi_complete_task Mike Christie
2021-04-03 23:23 ` [PATCH 17/40] scsi: qedi: cleanup abort handling Mike Christie
2021-04-03 23:23 ` [PATCH 18/40] scsi: qedi: misc cleanup Mike Christie
2021-04-03 23:23 ` [PATCH 19/40] scsi: qedi: drop libiscsi itt use Mike Christie
2021-04-03 23:23 ` [PATCH 20/40] scsi: qedi: rm unused nr_hw_queues Mike Christie
2021-04-03 23:23 ` [PATCH 21/40] scsi: iscsi: use blk/scsi-ml mq cmd pre-allocator Mike Christie
2021-04-03 23:23 ` [PATCH 22/40] scsi: libiscsi: remove ISCSI_TASK_ABRT_SESS_RECOV Mike Christie
2021-04-03 23:23 ` [PATCH 23/40] scsi: libiscsi: remove ISCSI_TASK_REQUEUE_SCSIQ Mike Christie
2021-04-03 23:23 ` [PATCH 24/40] scsi: be2iscsi: check for running task under back_lock Mike Christie
2021-04-03 23:23 ` [PATCH 25/40] scsi: iscsi: add mgmt lock Mike Christie
2021-04-03 23:23 ` [PATCH 26/40] scsi: iscsi: replace back_lock with task lock for lookup Mike Christie
2021-04-03 23:23 ` [PATCH 27/40] scsi: qedi: use task lock when checking task state Mike Christie
2021-04-03 23:23 ` [PATCH 28/40] scsi: be2iscsi: replace back_lock with task lock during eh Mike Christie
2021-04-03 23:23 ` [PATCH 29/40] scsi: libiscsi: " Mike Christie
2021-04-03 23:23 ` [PATCH 30/40] scsi: be2iscsi: prep for back_lock removal Mike Christie
2021-04-03 23:23 ` [PATCH 31/40] scsi: iscsi: rm iscsi_put_task back_lock requirement Mike Christie
2021-04-03 23:23 ` [PATCH 32/40] scsi: libiscsi: improve conn_send_pdu API Mike Christie
2021-04-03 23:23 ` [PATCH 33/40] scsi: libiscsi: add max/exp cmdsn lock Mike Christie
2021-04-03 23:23 ` [PATCH 34/40] scsi: iscsi: remove back_lock Mike Christie
2021-04-03 23:23 ` [PATCH 35/40] scsi: libiscsi: update leadconn comments/locking Mike Christie
2021-04-03 23:23 ` [PATCH 36/40] scsi: libiscsi: move ISCSI_SUSPEND_BIT check during queueing Mike Christie
2021-04-03 23:23 ` [PATCH 37/40] scsi: libiscsi: add new task state for requeues Mike Christie
2021-04-03 23:23 ` [PATCH 38/40] scsi: libiscsi: replace list_head with llist_head Mike Christie
2021-04-03 23:23 ` [PATCH 39/40] scsi: libiscsi: remove queued_cmdsn Mike Christie
2021-04-03 23:23 ` [PATCH 40/40] scsi: iscsi_tcp: tell net layer we are sending multiple pdus Mike Christie
2021-04-08 16:34 ` [PATCH 00/40] iscsi lock and refcount fix ups michael.christie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.