All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/20] qla2xxx: Patches for target-pending branch
@ 2015-12-08  0:48 Himanshu Madhani
  2015-12-08  0:48 ` [PATCH 01/20] qla2xxx: Enable Extended Login support Himanshu Madhani
                   ` (19 more replies)
  0 siblings, 20 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

Hi Nic,

This patch series adds performance improvement for qla2xxx target mode driver.

Please apply this series to target-pending for next mainline merge window.

Thanks,
Himanshu

Alexei Potashnik (2):
  qla2xxx: Delete session if initiator is gone from FW
  qla2xxx: Wait for all conflicts before ack'ing PLOGI

Dilip Kumar Uppugandla (1):
  qla2xxx: Check for online flag instead of active reset when
    transmitting responses

Himanshu Madhani (4):
  qla2xxx: Enable Extended Login support
  qla2xxx: Enable Exchange offload support.
  qla2xxx: Enable Target counters in DebugFS.
  qla2xxx: Added interface to send ELS commands from driver.

Quinn Tran (13):
  qla2xxx: Add FW resource count in DebugFS.
  qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit.
  qla2xxx: Change check_stop_free to always return 1
  qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  qla2xxx: Add TAS detection for kernel 3.15 n newer
  target/tmr: LUN reset cause cmd premature free.
  qla2xxx: Remove dependency on hardware_lock to reduce lock
    contention.
  qla2xxx: Add irq affinity notification
  qla2xxx: Add selective command queuing
  qla2xxx: Move atioq to a different lock to reduce lock contention
  qla2xxx: Disable ZIO at start time.
  qla2xxx: Set all queues to 4k
  qla2xxx: Add bulk send for atio & ctio completion paths.

 drivers/scsi/qla2xxx/qla_attr.c        |   36 ++
 drivers/scsi/qla2xxx/qla_dbg.c         |   19 +-
 drivers/scsi/qla2xxx/qla_def.h         |   86 ++++-
 drivers/scsi/qla2xxx/qla_dfs.c         |  106 +++++
 drivers/scsi/qla2xxx/qla_gbl.h         |   19 +-
 drivers/scsi/qla2xxx/qla_init.c        |   58 ++-
 drivers/scsi/qla2xxx/qla_inline.h      |    2 +
 drivers/scsi/qla2xxx/qla_iocb.c        |  190 ++++++++
 drivers/scsi/qla2xxx/qla_isr.c         |  129 +++++-
 drivers/scsi/qla2xxx/qla_mbx.c         |  264 +++++++++++-
 drivers/scsi/qla2xxx/qla_os.c          |  163 +++++++-
 drivers/scsi/qla2xxx/qla_target.c      |  737 +++++++++++++++++++++++++-------
 drivers/scsi/qla2xxx/qla_target.h      |   95 +++--
 drivers/scsi/qla2xxx/tcm_qla2xxx.c     |  205 ++++++++-
 drivers/target/target_core_tmr.c       |   33 ++-
 drivers/target/target_core_transport.c |   35 ++-
 include/target/target_core_base.h      |    2 +
 17 files changed, 1894 insertions(+), 285 deletions(-)

-- 
1.7.7

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

* [PATCH 01/20] qla2xxx: Enable Extended Login support
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08 15:51   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 02/20] qla2xxx: Enable Exchange offload support Himanshu Madhani
                   ` (18 subsequent siblings)
  19 siblings, 1 reply; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_dbg.c  |    9 +--
 drivers/scsi/qla2xxx/qla_def.h  |   13 ++++-
 drivers/scsi/qla2xxx/qla_gbl.h  |    7 ++
 drivers/scsi/qla2xxx/qla_init.c |    7 ++
 drivers/scsi/qla2xxx/qla_mbx.c  |  119 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_os.c   |   76 +++++++++++++++++++++++++
 6 files changed, 224 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 34dc9a3..5766640 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,7 +14,7 @@
  * | Module Init and Probe        |       0x017f       | 0x0146         |
  * |                              |                    | 0x015b-0x0160	|
  * |                              |                    | 0x016e-0x0170  |
- * | Mailbox commands             |       0x118d       | 0x1115-0x1116	|
+ * | Mailbox commands             |       0x1192       | 0x1018-0x1019	|
  * |                              |                    | 0x111a-0x111b  |
  * | Device Discovery             |       0x2016       | 0x2020-0x2022, |
  * |                              |                    | 0x2011-0x2012, |
@@ -60,10 +60,9 @@
  * |                              |                    | 0xb13c-0xb140  |
  * |                              |                    | 0xb149		|
  * | MultiQ                       |       0xc00c       |		|
- * | Misc                         |       0xd300       | 0xd016-0xd017	|
- * |                              |                    | 0xd021,0xd024	|
- * |                              |                    | 0xd025,0xd029	|
- * |                              |                    | 0xd02a,0xd02e	|
+ * | Misc                         |       0xd300       | 0xd012-0xd014	|
+ * |                              |                    | 0xd016-0xd017	|
+ * |                              |                    | 0xd02e		|
  * |                              |                    | 0xd031-0xd0ff	|
  * |                              |                    | 0xd101-0xd1fe	|
  * |                              |                    | 0xd214-0xd2fe	|
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 388d790..8f465b7 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -891,6 +891,7 @@ struct mbx_cmd_32 {
 #define MBC_DISABLE_VI			0x24	/* Disable VI operation. */
 #define MBC_ENABLE_VI			0x25	/* Enable VI operation. */
 #define MBC_GET_FIRMWARE_OPTION		0x28	/* Get Firmware Options. */
+#define MBC_GET_MEM_OFFLOAD_CNTRL_STAT	0x34	/* Memory Offload ctrl/Stat*/
 #define MBC_SET_FIRMWARE_OPTION		0x38	/* Set Firmware Options. */
 #define MBC_LOOP_PORT_BYPASS		0x40	/* Loop Port Bypass. */
 #define MBC_LOOP_PORT_ENABLE		0x41	/* Loop Port Enable. */
@@ -2962,11 +2963,12 @@ struct qla_hw_data {
 		uint32_t	isp82xx_no_md_cap:1;
 		uint32_t	host_shutting_down:1;
 		uint32_t	idc_compl_status:1;
-
 		uint32_t        mr_reset_hdlr_active:1;
 		uint32_t        mr_intr_valid:1;
+
 		uint32_t	fawwpn_enabled:1;
-		/* 35 bits */
+		uint32_t	exlogins_enabled:1;
+		/* 34 bits */
 	} flags;
 
 	/* This spinlock is used to protect "io transactions", you must
@@ -3237,6 +3239,13 @@ struct qla_hw_data {
 	void		*async_pd;
 	dma_addr_t	async_pd_dma;
 
+#define ENABLE_EXTENDED_LOGIN	BIT_7
+
+	/* Extended Logins  */
+	void		*exlogin_buf;
+	dma_addr_t	exlogin_buf_dma;
+	int		exlogin_size;
+
 	void		*swl;
 
 	/* These are used by mailbox operations. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 7686bfe..d396c49 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -117,6 +117,7 @@ extern int ql2xdontresethba;
 extern uint64_t ql2xmaxlun;
 extern int ql2xmdcapmask;
 extern int ql2xmdenable;
+extern int ql2xexlogins;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -135,6 +136,8 @@ extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
 extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
     fc_port_t *, uint16_t *);
+extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
 
 extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
 
@@ -766,4 +769,8 @@ extern int qla8044_abort_isp(scsi_qla_host_t *);
 extern int qla8044_check_fw_alive(struct scsi_qla_host *);
 
 extern void qlt_host_reset_handler(struct qla_hw_data *ha);
+extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
+	uint16_t *);
+extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 16a1935c..ef61a24 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1843,9 +1843,16 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
 			ql_dbg(ql_dbg_init, vha, 0x00ca,
 			    "Starting firmware.\n");
 
+			if (ql2xexlogins)
+				ha->flags.exlogins_enabled = 1;
+
 			rval = qla2x00_execute_fw(vha, srisc_address);
 			/* Retrieve firmware information. */
 			if (rval == QLA_SUCCESS) {
+				rval = qla2x00_set_exlogins_buffer(vha);
+				if (rval != QLA_SUCCESS)
+					goto failed;
+
 enable_82xx_npiv:
 				fw_major_version = ha->fw_major_version;
 				if (IS_P3P_TYPE(ha))
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index cb11e04..a0ae178 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -489,6 +489,10 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 			    EXTENDED_BB_CREDITS);
 		} else
 			mcp->mb[4] = 0;
+
+		if (ha->flags.exlogins_enabled)
+			mcp->mb[4] |= ENABLE_EXTENDED_LOGIN;
+
 		mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
 		mcp->in_mb |= MBX_1;
 	} else {
@@ -521,6 +525,117 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 }
 
 /*
+ * qla_get_exlogin_status
+ *	Get extended login status
+ *	uses the memory offload control/status Mailbox
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fwopt:		firmware options
+ *
+ * Returns:
+ *	qla2x00 local function status
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define	FETCH_XLOGINS_STAT	0x8
+int
+qla_get_exlogin_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+	uint16_t *ex_logins_cnt)
+{
+	int rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118f,
+	    "Entered %s\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = FETCH_XLOGINS_STAT;
+	mcp->out_mb = MBX_1|MBX_0;
+	mcp->in_mb = MBX_10|MBX_4|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1115, "Failed=%x.\n", rval);
+	} else {
+		*buf_sz = mcp->mb[4];
+		*ex_logins_cnt = mcp->mb[10];
+
+		ql_log(ql_log_info, vha, 0x1190,
+		    "buffer size 0x%x, exchange login count=%d\n",
+		    mcp->mb[4], mcp->mb[10]);
+
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1116,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
+ * qla_set_exlogin_mem_cfg
+ *	set extended login memory configuration
+ *	Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	buffer:		buffer pointer
+ *	phys_addr:	physical address of buffer
+ *	size:		size of buffer
+ *	TARGET_QUEUE_LOCK must be released
+ *	ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ *	qla2x00 local funxtion status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define CONFIG_XLOGINS_MEM	0x3
+int
+qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+	struct qla_hw_data *ha = vha->hw;
+	int configured_count;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111a,
+	    "Entered %s.\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = CONFIG_XLOGINS_MEM;
+	mcp->mb[2] = MSW(phys_addr);
+	mcp->mb[3] = LSW(phys_addr);
+	mcp->mb[6] = MSW(MSD(phys_addr));
+	mcp->mb[7] = LSW(MSD(phys_addr));
+	mcp->mb[8] = MSW(ha->exlogin_size);
+	mcp->mb[9] = LSW(ha->exlogin_size);
+	mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_11|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		ql_dbg(ql_dbg_mbx, vha, 0x111b, "Failed=%x.\n", rval);
+	} else {
+		configured_count = mcp->mb[11];
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
  * qla2x00_get_fw_version
  *	Get firmware version.
  *
@@ -594,6 +709,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x112f,
 		    "%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
 		    __func__, mcp->mb[17], mcp->mb[16]);
+		if (ha->fw_attributes_h & 0x4)
+			ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118d,
+			    "%s: Firmware supports Extended Login 0x%x\n",
+			    __func__, ha->fw_attributes_h);
 	}
 
 	if (IS_QLA27XX(ha)) {
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 6be32fd..bfe33d5 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -221,6 +221,12 @@ MODULE_PARM_DESC(ql2xmdenable,
 		"0 - MiniDump disabled. "
 		"1 (Default) - MiniDump enabled.");
 
+int ql2xexlogins = 0;
+module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexlogins,
+		 "Number of extended Logins. "
+		 "0 (Default)- Disabled.");
+
 /*
  * SCSI host template entry points
  */
@@ -3128,6 +3134,10 @@ qla2x00_remove_one(struct pci_dev *pdev)
 
 	base_vha->flags.online = 0;
 
+	/* free DMA memory */
+	if (ha->exlogin_buf)
+		qla2x00_free_exlogin_buffer(ha);
+
 	qla2x00_destroy_deferred_work(ha);
 
 	qlt_remove_target(ha, base_vha);
@@ -3587,6 +3597,72 @@ fail:
 	return -ENOMEM;
 }
 
+int
+qla2x00_set_exlogins_buffer(scsi_qla_host_t *vha)
+{
+	int rval;
+	uint16_t	size, max_cnt, temp;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Return if we don't need to alloacate any extended logins */
+	if (!ql2xexlogins)
+		return QLA_SUCCESS;
+
+	ql_log(ql_log_info, vha, 0xd021, "EXLOGIN count: %d.\n", ql2xexlogins);
+	max_cnt = 0;
+	rval = qla_get_exlogin_status(vha, &size, &max_cnt);
+	if (rval != QLA_SUCCESS) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd029,
+		    "Failed to get exlogin status.\n");
+		return rval;
+	}
+
+	temp = (ql2xexlogins > max_cnt) ? max_cnt : ql2xexlogins;
+	ha->exlogin_size = (size * temp);
+	ql_log(ql_log_info, vha, 0xd024,
+		"EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n",
+		max_cnt, size, temp);
+
+	ql_log(ql_log_info, vha, 0xd025, "EXLOGIN: requested size=0x%x\n",
+		ha->exlogin_size);
+
+	/* Get consistent memory for extended logins */
+	ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev,
+	    ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL);
+	if (!ha->exlogin_buf) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a,
+		    "Failed to allocate memory for exlogin_buf_dma.\n");
+		return -ENOMEM;
+	}
+
+	/* Now configure the dma buffer */
+	rval = qla_set_exlogin_mem_cfg(vha, ha->exlogin_buf_dma);
+	if (rval) {
+		ql_log(ql_log_fatal, vha, 0x00cf,
+		    "Setup extended login buffer  ****FAILED****.\n");
+		qla2x00_free_exlogin_buffer(ha);
+	}
+
+	return rval;
+}
+
+/*
+* qla2x00_free_exlogin_buffer
+*
+* Input:
+*	ha = adapter block pointer
+*/
+void
+qla2x00_free_exlogin_buffer(struct qla_hw_data *ha)
+{
+	if (ha->exlogin_buf) {
+		dma_free_coherent(&ha->pdev->dev, ha->exlogin_size,
+		    ha->exlogin_buf, ha->exlogin_buf_dma);
+		ha->exlogin_buf = NULL;
+		ha->exlogin_size = 0;
+	}
+}
+
 /*
 * qla2x00_free_fw_dump
 *	Frees fw dump stuff.
-- 
1.7.7


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

* [PATCH 02/20] qla2xxx: Enable Exchange offload support.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
  2015-12-08  0:48 ` [PATCH 01/20] qla2xxx: Enable Extended Login support Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08 15:52   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 03/20] qla2xxx: Enable Target counters in DebugFS Himanshu Madhani
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_dbg.c  |    9 +--
 drivers/scsi/qla2xxx/qla_def.h  |   12 ++++-
 drivers/scsi/qla2xxx/qla_gbl.h  |    6 ++
 drivers/scsi/qla2xxx/qla_init.c |    7 ++
 drivers/scsi/qla2xxx/qla_mbx.c  |  117 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_os.c   |   76 +++++++++++++++++++++++++
 6 files changed, 220 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 5766640..e25f5ac 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,8 +14,8 @@
  * | Module Init and Probe        |       0x017f       | 0x0146         |
  * |                              |                    | 0x015b-0x0160	|
  * |                              |                    | 0x016e-0x0170  |
- * | Mailbox commands             |       0x1192       | 0x1018-0x1019	|
- * |                              |                    | 0x111a-0x111b  |
+ * | Mailbox commands             |       0x1192       | 		|
+ * |                              |                    |		|
  * | Device Discovery             |       0x2016       | 0x2020-0x2022, |
  * |                              |                    | 0x2011-0x2012, |
  * |                              |                    | 0x2099-0x20a4  |
@@ -60,10 +60,7 @@
  * |                              |                    | 0xb13c-0xb140  |
  * |                              |                    | 0xb149		|
  * | MultiQ                       |       0xc00c       |		|
- * | Misc                         |       0xd300       | 0xd012-0xd014	|
- * |                              |                    | 0xd016-0xd017	|
- * |                              |                    | 0xd02e		|
- * |                              |                    | 0xd031-0xd0ff	|
+ * | Misc                         |       0xd300       | 0xd031-0xd0ff	|
  * |                              |                    | 0xd101-0xd1fe	|
  * |                              |                    | 0xd214-0xd2fe	|
  * | Target Mode		  |	  0xe080       |		|
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 8f465b7..be9a674 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -272,6 +272,7 @@
 #define RESPONSE_ENTRY_CNT_MQ		128	/* Number of response entries.*/
 #define ATIO_ENTRY_CNT_24XX		4096	/* Number of ATIO entries. */
 #define RESPONSE_ENTRY_CNT_FX00		256     /* Number of response entries.*/
+#define EXTENDED_EXCH_ENTRY_CNT		32768   /* Reuqest Entries for offload case*/
 
 struct req_que;
 struct qla_tgt_sess;
@@ -2968,7 +2969,8 @@ struct qla_hw_data {
 
 		uint32_t	fawwpn_enabled:1;
 		uint32_t	exlogins_enabled:1;
-		/* 34 bits */
+		uint32_t	exchoffld_enabled:1;
+		/* 35 bits */
 	} flags;
 
 	/* This spinlock is used to protect "io transactions", you must
@@ -3246,6 +3248,14 @@ struct qla_hw_data {
 	dma_addr_t	exlogin_buf_dma;
 	int		exlogin_size;
 
+#define ENABLE_EXCHANGE_OFFLD	BIT_2
+
+	/* Exchange Offload */
+	void		*exchoffld_buf;
+	dma_addr_t	exchoffld_buf_dma;
+	int		exchoffld_size;
+	int 		exchoffld_count;
+
 	void		*swl;
 
 	/* These are used by mailbox operations. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index d396c49..f9ebfcf 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -118,6 +118,7 @@ extern uint64_t ql2xmaxlun;
 extern int ql2xmdcapmask;
 extern int ql2xmdenable;
 extern int ql2xexlogins;
+extern int ql2xexchoffld;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -138,6 +139,8 @@ extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
     fc_port_t *, uint16_t *);
 extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
 extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
+extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exchoffld_buffer(struct qla_hw_data *);
 
 extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
 
@@ -772,5 +775,8 @@ extern void qlt_host_reset_handler(struct qla_hw_data *ha);
 extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
 	uint16_t *);
 extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
+extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha,
+    dma_addr_t phys_addr);
 
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index ef61a24..b3ed3b3 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1846,6 +1846,9 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
 			if (ql2xexlogins)
 				ha->flags.exlogins_enabled = 1;
 
+			if (ql2xexchoffld)
+				ha->flags.exchoffld_enabled = 1;
+
 			rval = qla2x00_execute_fw(vha, srisc_address);
 			/* Retrieve firmware information. */
 			if (rval == QLA_SUCCESS) {
@@ -1853,6 +1856,10 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
 				if (rval != QLA_SUCCESS)
 					goto failed;
 
+				rval = qla2x00_set_exchoffld_buffer(vha);
+				if (rval != QLA_SUCCESS)
+					goto failed;
+
 enable_82xx_npiv:
 				fw_major_version = ha->fw_major_version;
 				if (IS_P3P_TYPE(ha))
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index a0ae178..06de0eb 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -493,6 +493,9 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 		if (ha->flags.exlogins_enabled)
 			mcp->mb[4] |= ENABLE_EXTENDED_LOGIN;
 
+		if (ha->flags.exchoffld_enabled)
+			mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD;
+
 		mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
 		mcp->in_mb |= MBX_1;
 	} else {
@@ -636,6 +639,114 @@ qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
 }
 
 /*
+ * qla_get_exchoffld_status
+ *	Get exchange offload status
+ *	uses the memory offload control/status Mailbox
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fwopt:		firmware options
+ *
+ * Returns:
+ *	qla2x00 local function status
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define	FETCH_XCHOFFLD_STAT	0x2
+int
+qla_get_exchoffld_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+	uint16_t *ex_logins_cnt)
+{
+	int rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1019,
+	    "Entered %s\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = FETCH_XCHOFFLD_STAT;
+	mcp->out_mb = MBX_1|MBX_0;
+	mcp->in_mb = MBX_10|MBX_4|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1155, "Failed=%x.\n", rval);
+	} else {
+		*buf_sz = mcp->mb[4];
+		*ex_logins_cnt = mcp->mb[10];
+
+		ql_log(ql_log_info, vha, 0x118e, "buffer size 0x%x, exchange offload count=%d\n",
+		    mcp->mb[4], mcp->mb[10]);
+
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1156,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
+ * qla_set_exchoffld_mem_cfg
+ *	Set exchange offload memory configuration
+ *	Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	buffer:		buffer pointer
+ *	phys_addr:	physical address of buffer
+ *	size:		size of buffer
+ *	TARGET_QUEUE_LOCK must be released
+ *	ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ *	qla2x00 local funxtion status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+#define CONFIG_XCHOFFLD_MEM	0x3
+int
+qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+	struct qla_hw_data *ha = vha->hw;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1157,
+	    "Entered %s.\n", __func__);
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+	mcp->mb[1] = CONFIG_XCHOFFLD_MEM;
+	mcp->mb[2] = MSW(phys_addr);
+	mcp->mb[3] = LSW(phys_addr);
+	mcp->mb[6] = MSW(MSD(phys_addr));
+	mcp->mb[7] = LSW(MSD(phys_addr));
+	mcp->mb[8] = MSW(ha->exlogin_size);
+	mcp->mb[9] = LSW(ha->exlogin_size);
+	mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_11|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		ql_dbg(ql_dbg_mbx, vha, 0x1158, "Failed=%x.\n", rval);
+	} else {
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+/*
  * qla2x00_get_fw_version
  *	Get firmware version.
  *
@@ -709,10 +820,16 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x112f,
 		    "%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
 		    __func__, mcp->mb[17], mcp->mb[16]);
+
 		if (ha->fw_attributes_h & 0x4)
 			ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118d,
 			    "%s: Firmware supports Extended Login 0x%x\n",
 			    __func__, ha->fw_attributes_h);
+
+		if (ha->fw_attributes_h & 0x8)
+			ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1191,
+			    "%s: Firmware supports Exchange Offload 0x%x\n",
+			    __func__, ha->fw_attributes_h);
 	}
 
 	if (IS_QLA27XX(ha)) {
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index bfe33d5..a63ce6e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -227,6 +227,12 @@ MODULE_PARM_DESC(ql2xexlogins,
 		 "Number of extended Logins. "
 		 "0 (Default)- Disabled.");
 
+int ql2xexchoffld = 0;
+module_param(ql2xexchoffld, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexchoffld,
+		 "Number of exchanges to offload. "
+		 "0 (Default)- Disabled.");
+
 /*
  * SCSI host template entry points
  */
@@ -3138,6 +3144,10 @@ qla2x00_remove_one(struct pci_dev *pdev)
 	if (ha->exlogin_buf)
 		qla2x00_free_exlogin_buffer(ha);
 
+	/* free DMA memory */
+	if (ha->exchoffld_buf)
+		qla2x00_free_exchoffld_buffer(ha);
+
 	qla2x00_destroy_deferred_work(ha);
 
 	qlt_remove_target(ha, base_vha);
@@ -3663,6 +3673,72 @@ qla2x00_free_exlogin_buffer(struct qla_hw_data *ha)
 	}
 }
 
+int
+qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
+{
+	int rval;
+	uint16_t	size, max_cnt, temp;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Return if we don't need to alloacate any extended logins */
+	if (!ql2xexchoffld)
+		return QLA_SUCCESS;
+
+	ql_log(ql_log_info, vha, 0xd014, "Exchange offload count: %d.\n", ql2xexlogins);
+	max_cnt = 0;
+	rval = qla_get_exchoffld_status(vha, &size, &max_cnt);
+	if (rval != QLA_SUCCESS) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd012,
+		    "Failed to get exlogin status.\n");
+		return rval;
+	}
+
+	temp = (ql2xexchoffld > max_cnt) ? max_cnt : ql2xexchoffld;
+	ha->exchoffld_size = (size * temp);
+	ql_log(ql_log_info, vha, 0xd016,
+		"Exchange offload: max_count=%d, buffers=0x%x, total=%d.\n",
+		max_cnt, size, temp);
+
+	ql_log(ql_log_info, vha, 0xd017,
+	    "Exchange Buffers requested size = 0x%x\n", ha->exchoffld_size);
+
+	/* Get consistent memory for extended logins */
+	ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev,
+	    ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL);
+	if (!ha->exchoffld_buf) {
+		ql_log_pci(ql_log_fatal, ha->pdev, 0xd013,
+		    "Failed to allocate memory for exchoffld_buf_dma.\n");
+		return -ENOMEM;
+	}
+
+	/* Now configure the dma buffer */
+	rval = qla_set_exchoffld_mem_cfg(vha, ha->exchoffld_buf_dma);
+	if (rval) {
+		ql_log(ql_log_fatal, vha, 0xd02e,
+		    "Setup exchange offload buffer ****FAILED****.\n");
+		qla2x00_free_exchoffld_buffer(ha);
+	}
+
+	return rval;
+}
+
+/*
+* qla2x00_free_exchoffld_buffer
+*
+* Input:
+*	ha = adapter block pointer
+*/
+void
+qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha)
+{
+	if (ha->exchoffld_buf) {
+		dma_free_coherent(&ha->pdev->dev, ha->exchoffld_size,
+		    ha->exchoffld_buf, ha->exchoffld_buf_dma);
+		ha->exchoffld_buf = NULL;
+		ha->exchoffld_size = 0;
+	}
+}
+
 /*
 * qla2x00_free_fw_dump
 *	Frees fw dump stuff.
-- 
1.7.7

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

* [PATCH 03/20] qla2xxx: Enable Target counters in DebugFS.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
  2015-12-08  0:48 ` [PATCH 01/20] qla2xxx: Enable Extended Login support Himanshu Madhani
  2015-12-08  0:48 ` [PATCH 02/20] qla2xxx: Enable Exchange offload support Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08 15:52   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 04/20] qla2xxx: Add FW resource count " Himanshu Madhani
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

Following counters are added in target mode to help debugging efforts.

Target Counters

qla_core_sbt_cmd = 0
qla_core_ret_sta_ctio = 0
qla_core_ret_ctio = 0
core_qla_que_buf = 0
core_qla_snd_status = 0
core_qla_free_cmd = 0
num alloc iocb failed = 0
num term exchange sent = 0
num Q full sent = 0

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_dbg.c     |    2 +-
 drivers/scsi/qla2xxx/qla_def.h     |   15 +++++++++
 drivers/scsi/qla2xxx/qla_dfs.c     |   56 ++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_iocb.c    |    1 +
 drivers/scsi/qla2xxx/qla_target.c  |    7 ++++
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |    4 ++
 6 files changed, 84 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index e25f5ac..07451bb 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -60,7 +60,7 @@
  * |                              |                    | 0xb13c-0xb140  |
  * |                              |                    | 0xb149		|
  * | MultiQ                       |       0xc00c       |		|
- * | Misc                         |       0xd300       | 0xd031-0xd0ff	|
+ * | Misc                         |       0xd301       | 0xd031-0xd0ff	|
  * |                              |                    | 0xd101-0xd1fe	|
  * |                              |                    | 0xd214-0xd2fe	|
  * | Target Mode		  |	  0xe080       |		|
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index be9a674..1d2a51a 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3342,6 +3342,8 @@ struct qla_hw_data {
 	uint32_t	chain_offset;
 	struct dentry *dfs_dir;
 	struct dentry *dfs_fce;
+	struct dentry *dfs_tgt_counters;
+
 	dma_addr_t	fce_dma;
 	void		*fce;
 	uint32_t	fce_bufs;
@@ -3499,6 +3501,18 @@ struct qla_hw_data {
 	int	allow_cna_fw_dump;
 };
 
+struct qla_tgt_counters {
+	uint64_t qla_core_sbt_cmd;
+	uint64_t core_qla_que_buf;
+	uint64_t qla_core_ret_ctio;
+	uint64_t core_qla_snd_status;
+	uint64_t qla_core_ret_sta_ctio;
+	uint64_t core_qla_free_cmd;
+	uint64_t num_q_full_sent;
+	uint64_t num_alloc_iocb_failed;
+	uint64_t num_term_xchg_sent;
+};
+
 /*
  * Qlogic scsi host structure
  */
@@ -3651,6 +3665,7 @@ typedef struct scsi_qla_host {
 
 	atomic_t	vref_count;
 	struct qla8044_reset_template reset_tmplt;
+	struct qla_tgt_counters tgt_counters;
 } scsi_qla_host_t;
 
 #define SET_VP_IDX	1
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 15cf074..449541f 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,48 @@ static struct dentry *qla2x00_dfs_root;
 static atomic_t qla2x00_dfs_root_count;
 
 static int
+qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
+{
+	struct scsi_qla_host *vha = s->private;
+
+	seq_puts(s, "Target Counters\n");
+	seq_printf(s, "qla_core_sbt_cmd = %lld\n",
+		vha->tgt_counters.qla_core_sbt_cmd);
+	seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
+		vha->tgt_counters.qla_core_ret_sta_ctio);
+	seq_printf(s, "qla_core_ret_ctio = %lld\n",
+		vha->tgt_counters.qla_core_ret_ctio);
+	seq_printf(s, "core_qla_que_buf = %lld\n",
+		vha->tgt_counters.core_qla_que_buf);
+	seq_printf(s, "core_qla_snd_status = %lld\n",
+		vha->tgt_counters.core_qla_snd_status);
+	seq_printf(s, "core_qla_free_cmd = %lld\n",
+		vha->tgt_counters.core_qla_free_cmd);
+	seq_printf(s, "num alloc iocb failed = %lld\n",
+		vha->tgt_counters.num_alloc_iocb_failed);
+	seq_printf(s, "num term exchange sent = %lld\n",
+		vha->tgt_counters.num_term_xchg_sent);
+	seq_printf(s, "num Q full sent = %lld\n",
+		vha->tgt_counters.num_q_full_sent);
+
+	return 0;
+}
+
+static int
+qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
+{
+	struct scsi_qla_host *vha = inode->i_private;
+	return single_open(file, qla_dfs_tgt_counters_show, vha);
+}
+
+static const struct file_operations dfs_tgt_counters_ops = {
+	.open           = qla_dfs_tgt_counters_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = single_release,
+};
+
+static int
 qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
 {
 	scsi_qla_host_t *vha = s->private;
@@ -146,6 +188,14 @@ create_dir:
 	atomic_inc(&qla2x00_dfs_root_count);
 
 create_nodes:
+	ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
+	    ha->dfs_dir, vha, &dfs_tgt_counters_ops);
+	if (!ha->dfs_tgt_counters) {
+		ql_log(ql_log_warn, vha, 0xd301,
+		    "Unable to create debugFS tgt_counters node.\n");
+		goto out;
+	}
+
 	ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
 	    &dfs_fce_ops);
 	if (!ha->dfs_fce) {
@@ -161,6 +211,12 @@ int
 qla2x00_dfs_remove(scsi_qla_host_t *vha)
 {
 	struct qla_hw_data *ha = vha->hw;
+
+	if (ha->dfs_tgt_counters) {
+		debugfs_remove(ha->dfs_tgt_counters);
+		ha->dfs_tgt_counters = NULL;
+	}
+
 	if (ha->dfs_fce) {
 		debugfs_remove(ha->dfs_fce);
 		ha->dfs_fce = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c49df34..c798234 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1868,6 +1868,7 @@ skip_cmd_array:
 	}
 
 queuing_error:
+	vha->tgt_counters.num_alloc_iocb_failed++;
 	return pkt;
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 75514a1..f404e48 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -2510,6 +2510,11 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
+	if (xmit_type == QLA_TGT_XMIT_STATUS)
+		vha->tgt_counters.core_qla_snd_status++;
+	else
+		vha->tgt_counters.core_qla_que_buf++;
+
 	if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
 		/*
 		 * Either a chip reset is active or this request was from
@@ -2957,6 +2962,7 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
 			ret = 1;
 	}
 
+	vha->tgt_counters.num_term_xchg_sent++;
 	pkt->entry_count = 1;
 	pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
 
@@ -4916,6 +4922,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
 		return -ENOMEM;
 	}
 
+	vha->tgt_counters.num_q_full_sent++;
 	pkt->entry_count = 1;
 	pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
 
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 81af294..3403428 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -284,6 +284,7 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
 
 	WARN_ON(cmd->cmd_flags &  BIT_16);
 
+	cmd->vha->tgt_counters.qla_core_ret_sta_ctio++;
 	cmd->cmd_flags |= BIT_16;
 	transport_generic_free_cmd(&cmd->se_cmd, 0);
 }
@@ -295,6 +296,7 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
  */
 static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
 {
+	cmd->vha->tgt_counters.core_qla_free_cmd++;
 	cmd->cmd_in_wq = 1;
 	INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
 	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
@@ -454,6 +456,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
 		return -EINVAL;
 	}
 
+	cmd->vha->tgt_counters.qla_core_sbt_cmd++;
 	return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0],
 				cmd->unpacked_lun, data_length, fcp_task_attr,
 				data_dir, flags);
@@ -469,6 +472,7 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 	 */
 	cmd->cmd_in_wq = 0;
 	cmd->cmd_flags |= BIT_11;
+	cmd->vha->tgt_counters.qla_core_ret_ctio++;
 	if (!cmd->write_data_transferred) {
 		/*
 		 * Check if se_cmd has already been aborted via LUN_RESET, and
-- 
1.7.7

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

* [PATCH 04/20] qla2xxx: Add FW resource count in DebugFS.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (2 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 03/20] qla2xxx: Enable Target counters in DebugFS Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08 15:53   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Himanshu Madhani
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

DebugFS now will show fw_resource_count node.

FW Resource count

Original TGT exchg count[0]
current TGT exchg count[0]
original Initiator Exchange count[2048]
Current Initiator Exchange count[2048]
Original IOCB count[2078]
Current IOCB count[2067]
MAX VP count[254]
MAX FCF count[0]

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_def.h     |   13 +++++++--
 drivers/scsi/qla2xxx/qla_dfs.c     |   50 ++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_gbl.h     |    3 +-
 drivers/scsi/qla2xxx/qla_init.c    |   12 +++-----
 drivers/scsi/qla2xxx/qla_mbx.c     |   28 ++++++++-----------
 drivers/scsi/qla2xxx/qla_target.c  |    4 +-
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |    2 +-
 7 files changed, 81 insertions(+), 31 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 1d2a51a..cf32fb9 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2917,7 +2917,7 @@ struct qlt_hw_data {
 #define MAX_QFULL_CMDS_ALLOC	8192
 #define Q_FULL_THRESH_HOLD_PERCENT 90
 #define Q_FULL_THRESH_HOLD(ha) \
-	((ha->fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
+	((ha->cur_fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
 
 #define LEAK_EXCHG_THRESH_HOLD_PERCENT 75	/* 75 percent */
 
@@ -3298,8 +3298,14 @@ struct qla_hw_data {
 #define RISC_START_ADDRESS_2100 0x1000
 #define RISC_START_ADDRESS_2300 0x800
 #define RISC_START_ADDRESS_2400 0x100000
-	uint16_t	fw_xcb_count;
-	uint16_t	fw_iocb_count;
+
+	uint16_t	orig_fw_tgt_xcb_count;
+	uint16_t	cur_fw_tgt_xcb_count;
+	uint16_t	orig_fw_xcb_count;
+	uint16_t	cur_fw_xcb_count;
+	uint16_t	orig_fw_iocb_count;
+	uint16_t	cur_fw_iocb_count;
+	uint16_t	fw_max_fcf_count;
 
 	uint32_t	fw_shared_ram_start;
 	uint32_t	fw_shared_ram_end;
@@ -3343,6 +3349,7 @@ struct qla_hw_data {
 	struct dentry *dfs_dir;
 	struct dentry *dfs_fce;
 	struct dentry *dfs_tgt_counters;
+	struct dentry *dfs_fw_resource_cnt;
 
 	dma_addr_t	fce_dma;
 	void		*fce;
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 449541f..cd8b96a 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,43 @@ static struct dentry *qla2x00_dfs_root;
 static atomic_t qla2x00_dfs_root_count;
 
 static int
+qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
+{
+	struct scsi_qla_host *vha = s->private;
+	struct qla_hw_data *ha = vha->hw;
+
+	seq_puts(s, "FW Resource count\n\n");
+	seq_printf(s, "Original TGT exchg count[%d]\n",
+	    ha->orig_fw_tgt_xcb_count);
+	seq_printf(s, "current TGT exchg count[%d]\n",
+	    ha->cur_fw_tgt_xcb_count);
+	seq_printf(s, "original Initiator Exchange count[%d]\n",
+	    ha->orig_fw_xcb_count);
+	seq_printf(s, "Current Initiator Exchange count[%d]\n",
+	    ha->cur_fw_xcb_count);
+	seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
+	seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
+	seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
+	seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
+
+	return 0;
+}
+
+static int
+qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
+{
+	struct scsi_qla_host *vha = inode->i_private;
+	return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
+}
+
+static const struct file_operations dfs_fw_resource_cnt_ops = {
+	.open           = qla_dfs_fw_resource_cnt_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = single_release,
+};
+
+static int
 qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
 {
 	struct scsi_qla_host *vha = s->private;
@@ -188,6 +225,14 @@ create_dir:
 	atomic_inc(&qla2x00_dfs_root_count);
 
 create_nodes:
+	ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
+	    S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
+	if (!ha->dfs_fw_resource_cnt) {
+		ql_log(ql_log_warn, vha, 0x00fd,
+		    "Unable to create debugFS fw_resource_count node.\n");
+		goto out;
+	}
+
 	ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
 	    ha->dfs_dir, vha, &dfs_tgt_counters_ops);
 	if (!ha->dfs_tgt_counters) {
@@ -212,6 +257,11 @@ qla2x00_dfs_remove(scsi_qla_host_t *vha)
 {
 	struct qla_hw_data *ha = vha->hw;
 
+	if (ha->dfs_fw_resource_cnt) {
+		debugfs_remove(ha->dfs_fw_resource_cnt);
+		ha->dfs_fw_resource_cnt = NULL;
+	}
+
 	if (ha->dfs_tgt_counters) {
 		debugfs_remove(ha->dfs_tgt_counters);
 		ha->dfs_tgt_counters = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index f9ebfcf..0b6e1c5 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -329,8 +329,7 @@ extern int
 qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
 
 extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
-    uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *);
 
 extern int
 qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index b3ed3b3..35d1ea8 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1766,10 +1766,10 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req)
 	    (ql2xmultique_tag || ql2xmaxqueues > 1)))
 		req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS;
 	else {
-		if (ha->fw_xcb_count <= ha->fw_iocb_count)
-			req->num_outstanding_cmds = ha->fw_xcb_count;
+		if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count)
+			req->num_outstanding_cmds = ha->cur_fw_xcb_count;
 		else
-			req->num_outstanding_cmds = ha->fw_iocb_count;
+			req->num_outstanding_cmds = ha->cur_fw_iocb_count;
 	}
 
 	req->outstanding_cmds = kzalloc(sizeof(srb_t *) *
@@ -1878,9 +1878,7 @@ enable_82xx_npiv:
 						ha->max_npiv_vports =
 						    MIN_MULTI_ID_FABRIC - 1;
 				}
-				qla2x00_get_resource_cnts(vha, NULL,
-				    &ha->fw_xcb_count, NULL, &ha->fw_iocb_count,
-				    &ha->max_npiv_vports, NULL);
+				qla2x00_get_resource_cnts(vha);
 
 				/*
 				 * Allocate the array of outstanding commands
@@ -2262,7 +2260,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
 	if (IS_FWI2_CAPABLE(ha)) {
 		mid_init_cb->options = cpu_to_le16(BIT_1);
 		mid_init_cb->init_cb.execution_throttle =
-		    cpu_to_le16(ha->fw_xcb_count);
+		    cpu_to_le16(ha->cur_fw_xcb_count);
 		/* D-Port Status */
 		if (IS_DPORT_CAPABLE(ha))
 			mid_init_cb->init_cb.firmware_options_1 |=
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 06de0eb..286eced 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2619,10 +2619,9 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
  *	Kernel context.
  */
 int
-qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
-    uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
-    uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports, uint16_t *max_fcfs)
+qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
 {
+	struct qla_hw_data *ha = vha->hw;
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
@@ -2650,19 +2649,16 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
 		    mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10],
 		    mcp->mb[11], mcp->mb[12]);
 
-		if (cur_xchg_cnt)
-			*cur_xchg_cnt = mcp->mb[3];
-		if (orig_xchg_cnt)
-			*orig_xchg_cnt = mcp->mb[6];
-		if (cur_iocb_cnt)
-			*cur_iocb_cnt = mcp->mb[7];
-		if (orig_iocb_cnt)
-			*orig_iocb_cnt = mcp->mb[10];
-		if (vha->hw->flags.npiv_supported && max_npiv_vports)
-			*max_npiv_vports = mcp->mb[11];
-		if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) ||
-		    IS_QLA27XX(vha->hw)) && max_fcfs)
-			*max_fcfs = mcp->mb[12];
+		ha->orig_fw_tgt_xcb_count =  mcp->mb[1];
+		ha->cur_fw_tgt_xcb_count = mcp->mb[2];
+		ha->cur_fw_xcb_count = mcp->mb[3];
+		ha->orig_fw_xcb_count = mcp->mb[6];
+		ha->cur_fw_iocb_count = mcp->mb[7];
+		ha->orig_fw_iocb_count = mcp->mb[10];
+		if (ha->flags.npiv_supported)
+			ha->max_npiv_vports = mcp->mb[11];
+		if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+			ha->fw_max_fcf_count = mcp->mb[12];
 	}
 
 	return (rval);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index f404e48..661124a 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3034,7 +3034,7 @@ static void qlt_init_term_exchange(struct scsi_qla_host *vha)
 	struct qla_tgt_cmd *cmd, *tcmd;
 
 	vha->hw->tgt.leak_exchg_thresh_hold =
-	    (vha->hw->fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
+	    (vha->hw->cur_fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
 
 	cmd = tcmd = NULL;
 	if (!list_empty(&vha->hw->tgt.q_full_list)) {
@@ -3064,7 +3064,7 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
 
 		ql_dbg(ql_dbg_tgt, vha, 0xe079,
 		    "Chip reset due to exchange starvation: %d/%d.\n",
-		    total_leaked, vha->hw->fw_xcb_count);
+		    total_leaked, vha->hw->cur_fw_xcb_count);
 
 		if (IS_P3P_TYPE(vha->hw))
 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 3403428..74c6e9b 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1357,7 +1357,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
 	struct qla_tgt_sess *sess = qla_tgt_sess;
 	unsigned char port_name[36];
 	unsigned long flags;
-	int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count :
+	int num_tags = (ha->cur_fw_xcb_count) ? ha->cur_fw_xcb_count :
 		       TCM_QLA2XXX_DEFAULT_TAGS;
 
 	lport = vha->vha_tgt.target_lport_ptr;
-- 
1.7.7


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

* [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (3 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 04/20] qla2xxx: Add FW resource count " Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08  2:10   ` kbuild test robot
                     ` (2 more replies)
  2015-12-08  0:48 ` [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW Himanshu Madhani
                   ` (14 subsequent siblings)
  19 siblings, 3 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_attr.c   |   36 +++++++
 drivers/scsi/qla2xxx/qla_dbg.c    |    5 +-
 drivers/scsi/qla2xxx/qla_def.h    |   19 ++++-
 drivers/scsi/qla2xxx/qla_gbl.h    |    2 +
 drivers/scsi/qla2xxx/qla_inline.h |    2 +
 drivers/scsi/qla2xxx/qla_iocb.c   |  189 +++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_isr.c    |    6 +
 7 files changed, 255 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6b942d9..6992ebc 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -824,6 +824,41 @@ static struct bin_attribute sysfs_reset_attr = {
 };
 
 static ssize_t
+qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr,
+			char *buf, loff_t off, size_t count)
+{
+	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	int type;
+	int rval = 0;
+	port_id_t did;
+
+	type = simple_strtol(buf, NULL, 10);
+
+	did.b.domain = (type & 0x00ff0000) >> 16;
+	did.b.area = (type & 0x0000ff00) >> 8;
+	did.b.al_pa = (type & 0x000000ff);
+
+	ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
+	    did.b.domain, did.b.area, did.b.al_pa);
+
+	ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
+
+	rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+	return count;
+}
+
+static struct bin_attribute sysfs_issue_logo_attr = {
+	.attr = {
+		.name = "issue_logo",
+		.mode = S_IWUSR,
+	},
+	.size = 0,
+	.write = qla2x00_issue_logo,
+};
+
+static ssize_t
 qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
 		       struct bin_attribute *bin_attr,
 		       char *buf, loff_t off, size_t count)
@@ -937,6 +972,7 @@ static struct sysfs_entry {
 	{ "vpd", &sysfs_vpd_attr, 1 },
 	{ "sfp", &sysfs_sfp_attr, 1 },
 	{ "reset", &sysfs_reset_attr, },
+	{ "issue_logo", &sysfs_issue_logo_attr, },
 	{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
 	{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
 	{ NULL },
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 07451bb..02f01be 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -19,7 +19,7 @@
  * | Device Discovery             |       0x2016       | 0x2020-0x2022, |
  * |                              |                    | 0x2011-0x2012, |
  * |                              |                    | 0x2099-0x20a4  |
- * | Queue Command and IO tracing |       0x3075       | 0x300b         |
+ * | Queue Command and IO tracing |       0x3074       | 0x300b         |
  * |                              |                    | 0x3027-0x3028  |
  * |                              |                    | 0x303d-0x3041  |
  * |                              |                    | 0x302d,0x3033  |
@@ -27,12 +27,11 @@
  * |                              |                    | 0x303a		|
  * | DPC Thread                   |       0x4023       | 0x4002,0x4013  |
  * | Async Events                 |       0x508a       | 0x502b-0x502f  |
- * |                              |                    | 0x5047		|
  * |                              |                    | 0x5084,0x5075	|
  * |                              |                    | 0x503d,0x5044  |
  * |                              |                    | 0x507b,0x505f	|
  * | Timer Routines               |       0x6012       |                |
- * | User Space Interactions      |       0x70e2       | 0x7018,0x702e  |
+ * | User Space Interactions      |       0x70e65      | 0x7018,0x702e  |
  * |				  |		       | 0x7020,0x7024  |
  * |                              |                    | 0x7039,0x7045  |
  * |                              |                    | 0x7073-0x7075  |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index cf32fb9..366f65b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -310,6 +310,14 @@ struct srb_cmd {
 /* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
 #define IS_PROT_IO(sp)	(sp->flags & SRB_CRC_CTX_DSD_VALID)
 
+struct els_logo_payload {
+	uint8_t opcode;
+	uint8_t rsvd[3];
+	uint8_t s_id[3];
+	uint8_t rsvd1[1];
+	uint8_t wwpn[WWN_SIZE];
+};
+
 /*
  * SRB extensions.
  */
@@ -323,6 +331,15 @@ struct srb_iocb {
 			uint16_t data[2];
 		} logio;
 		struct {
+#define ELS_DCMD_TIMEOUT 20
+#define ELS_DCMD_LOGO 0x5
+			uint32_t flags;
+			uint32_t els_cmd;
+			struct completion comp;
+			struct els_logo_payload *els_logo_pyld;
+			dma_addr_t els_logo_pyld_dma;
+		} els_logo;
+		struct {
 			/*
 			 * Values for flags field below are as
 			 * defined in tsk_mgmt_entry struct
@@ -383,7 +400,7 @@ struct srb_iocb {
 #define SRB_FXIOCB_DCMD	10
 #define SRB_FXIOCB_BCMD	11
 #define SRB_ABT_CMD	12
-
+#define SRB_ELS_DCMD	13
 
 typedef struct srb {
 	atomic_t ref_count;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 0b6e1c5..2e91966 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -44,6 +44,8 @@ extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
 extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
 extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
 
+extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
+
 extern void qla2x00_update_fcports(scsi_qla_host_t *);
 
 extern int qla2x00_abort_isp(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index fee9eb7..a6b7f15 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -258,6 +258,8 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
 	if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
 	    (sp->type == SRB_FXIOCB_DCMD))
 		init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
+	if (sp->type == SRB_ELS_DCMD)
+		init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
 }
 
 static inline int
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c798234..7940bb6 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2011,6 +2011,192 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
 }
 
 static void
+qla2x00_els_dcmd_sp_free(void *ptr, void *data)
+{
+	struct scsi_qla_host *vha = (scsi_qla_host_t *)ptr;
+	struct qla_hw_data *ha = vha->hw;
+	srb_t *sp = (srb_t *)data;
+	struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+	if (sp->fcport)
+		kfree(sp->fcport);
+
+	if (elsio->u.els_logo.els_logo_pyld)
+		dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+		    elsio->u.els_logo.els_logo_pyld,
+		    elsio->u.els_logo.els_logo_pyld_dma);
+
+	del_timer(&elsio->timer);
+	qla2x00_rel_sp(vha, sp);
+}
+
+static void
+qla2x00_els_dcmd_iocb_timeout(void *data)
+{
+	srb_t *sp = (srb_t *)data;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
+	fc_port_t *fcport = sp->fcport;
+	struct scsi_qla_host *vha = fcport->vha;
+	struct qla_hw_data *ha = vha->hw;
+	unsigned long flags = 0;
+
+	ql_dbg(ql_dbg_io, vha, 0x3069,
+	    "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
+	    sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
+	    fcport->d_id.b.al_pa);
+
+	/* Abort the exchange */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	if (ha->isp_ops->abort_command(sp)) {
+		ql_dbg(ql_dbg_io, vha, 0x3070,
+		    "mbx abort_command failed.\n");
+	} else {
+		ql_dbg(ql_dbg_io, vha, 0x3071,
+		    "mbx abort_command success.\n");
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	complete(&lio->u.els_logo.comp);
+}
+
+static void
+qla2x00_els_dcmd_sp_done(void *data, void *ptr, int res)
+{
+	srb_t *sp = (srb_t *)ptr;
+	fc_port_t *fcport = sp->fcport;
+	struct srb_iocb *lio = &sp->u.iocb_cmd;
+	struct scsi_qla_host *vha = fcport->vha;
+
+	ql_dbg(ql_dbg_io, vha, 0x3072,
+	    "%s hdl=%x, portid=%02x%02x%02x done\n",
+	    sp->name, sp->handle, fcport->d_id.b.domain,
+	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+	complete(&lio->u.els_logo.comp);
+}
+
+int
+qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
+    port_id_t remote_did)
+{
+	srb_t *sp;
+	fc_port_t *fcport = NULL;
+	struct srb_iocb *elsio = NULL;
+	struct qla_hw_data *ha = vha->hw;
+	struct els_logo_payload logo_pyld;
+	int rval = QLA_SUCCESS;
+
+	fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+	if (!fcport) {
+	       ql_log(ql_log_info, vha, 0x70e5,
+		   "fcport allocation failed\n");
+	       return -ENOMEM;
+	}
+
+	/* Alloc SRB structure */
+	sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+	if (!sp) {
+		kfree(fcport);
+		ql_log(ql_log_info, vha, 0x70e6,
+		 "SRB allocation failed\n");
+		return -ENOMEM;
+	}
+
+	elsio = &sp->u.iocb_cmd;
+	fcport->loop_id = 0xFFFF;
+	fcport->d_id.b.domain = remote_did.b.domain;
+	fcport->d_id.b.area = remote_did.b.area;
+	fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+	ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
+	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+	sp->type = SRB_ELS_DCMD;
+	sp->name = "ELS_DCMD";
+	sp->fcport = fcport;
+	qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+	elsio->timeout = qla2x00_els_dcmd_iocb_timeout;
+	sp->done = qla2x00_els_dcmd_sp_done;
+	sp->free = qla2x00_els_dcmd_sp_free;
+
+	elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
+			    DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
+			    GFP_KERNEL);
+
+	if (!elsio->u.els_logo.els_logo_pyld) {
+		sp->free(vha, sp);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
+
+	elsio->u.els_logo.els_cmd = els_opcode;
+	logo_pyld.opcode = els_opcode;
+	logo_pyld.s_id[0] = vha->d_id.b.al_pa;
+	logo_pyld.s_id[1] = vha->d_id.b.area;
+	logo_pyld.s_id[2] = vha->d_id.b.domain;
+	host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
+	memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
+
+	memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
+	    sizeof(struct els_logo_payload));
+
+	rval = qla2x00_start_sp(sp);
+	if (rval != QLA_SUCCESS) {
+		sp->free(vha, sp);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	ql_dbg(ql_dbg_io, vha, 0x3074,
+	    "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
+	    sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+	    fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+	wait_for_completion(&elsio->u.els_logo.comp);
+
+	sp->free(vha, sp);
+	return rval;
+}
+
+static void
+qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+{
+	scsi_qla_host_t *vha = sp->fcport->vha;
+	struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+	els_iocb->entry_type = ELS_IOCB_TYPE;
+	els_iocb->entry_count = 1;
+	els_iocb->sys_define = 0;
+	els_iocb->entry_status = 0;
+	els_iocb->handle = sp->handle;
+	els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+	els_iocb->tx_dsd_count = 1;
+	els_iocb->vp_index = vha->vp_idx;
+	els_iocb->sof_type = EST_SOFI3;
+	els_iocb->rx_dsd_count = 0;
+	els_iocb->opcode = elsio->u.els_logo.els_cmd;
+
+	els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+	els_iocb->port_id[1] = sp->fcport->d_id.b.area;
+	els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+	els_iocb->control_flags = 0;
+
+	els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+	els_iocb->tx_address[0] =
+	    cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+	els_iocb->tx_address[1] =
+	    cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+	els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+
+	els_iocb->rx_byte_count = 0;
+	els_iocb->rx_address[0] = 0;
+	els_iocb->rx_address[1] = 0;
+	els_iocb->rx_len = 0;
+
+	sp->fcport->vha->qla_stats.control_requests++;
+}
+
+static void
 qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
 	struct fc_bsg_job *bsg_job = sp->u.bsg_job;
@@ -2624,6 +2810,9 @@ qla2x00_start_sp(srb_t *sp)
 			qlafx00_abort_iocb(sp, pkt) :
 			qla24xx_abort_iocb(sp, pkt);
 		break;
+	case SRB_ELS_DCMD:
+		qla24xx_els_logo_iocb(sp, pkt);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ccf6a7f..ea7e8e8 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1418,6 +1418,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
 	case SRB_CT_CMD:
 		type = "ct pass-through";
 		break;
+	case SRB_ELS_DCMD:
+		type = "Driver ELS logo";
+		ql_dbg(ql_dbg_user, vha, 0x5047,
+		    "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
+		sp->done(vha, sp, 0);
+		return;
 	default:
 		ql_dbg(ql_dbg_user, vha, 0x503e,
 		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
-- 
1.7.7

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

* [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (4 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08  1:41   ` kbuild test robot
  2015-12-08 15:58   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 07/20] qla2xxx: Wait for all conflicts before ack'ing PLOGI Himanshu Madhani
                   ` (13 subsequent siblings)
  19 siblings, 2 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Alexei Potashnik <alexei@purestorage.com>

1. Initiator A is logged in with fc_id(1)/loop_id(1)
2. Initiator A re-logs in with fc_id(2)/loop_id(2)
3. Part of old session deletion async logoout for 1/1 is queued
4. Initiator B logs in with fc_id(1)/loop_id(1), starts
   passing data and creates session.
5. Async logo from 3 is processed by DPC and sent to FW

Now initiator B has the session but is logged out from FW.

This condition is detected first with CTIO error 29 at which
point we should delete current session. During session
deletion we will send LOGO to initiator to force re-login.

Under rare circumstances initiator might be logged out of FW,
not have driver session, but still think it's logged in.
E.g. the above sequence plus session deletion due to re-config.
Incoming commands will fail to create local session because
initiator is not found in FW. In this case we also issue LOGO
to initiator to force him re-login.

Finally this patch fixes exchange leak when commands where
received in logged out state. In this case loop_id must be
set to FFFF when corresponding exchange is terminated. The
patch modifies exchange termination to always use FFFF,
since in certain scenarios it's impossible to tell whether
command was received in logged in or logged out state.

Signed-off-by: Alexei Potashnik <alexei@purestorage.com>
Acked-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_def.h    |    2 +
 drivers/scsi/qla2xxx/qla_os.c     |    1 +
 drivers/scsi/qla2xxx/qla_target.c |  108 +++++++++++++++++++++++++++++++------
 drivers/scsi/qla2xxx/qla_target.h |    9 +++
 4 files changed, 104 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 366f65b..1050fc2 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3652,6 +3652,8 @@ typedef struct scsi_qla_host {
 	atomic_t		generation_tick;
 	/* Time when global fcport update has been scheduled */
 	int			total_fcport_update_gen;
+	/* List of pending LOGOs, protected by tgt_mutex */
+	struct list_head	logo_list;
 
 	uint32_t	vp_abort_cnt;
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index a63ce6e..c02cbc6 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3918,6 +3918,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
 	INIT_LIST_HEAD(&vha->list);
 	INIT_LIST_HEAD(&vha->qla_cmd_list);
 	INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
+	INIT_LIST_HEAD(&vha->logo_list);
 
 	spin_lock_init(&vha->work_lock);
 	spin_lock_init(&vha->cmd_list_lock);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 661124a..5ef9d4c 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -389,6 +389,52 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
 
 }
 
+typedef struct {
+	/* These fields must be initialized by the caller */
+	port_id_t id;
+	/*
+	 * number of cmds dropped while we were waiting for
+	 * initiator to ack LOGO initialize to 1 if LOGO is
+	 * triggered by a command, otherwise, to 0
+	 */
+	int cmd_count;
+
+	/* These fields are used by callee */
+	struct list_head list;
+} qlt_port_logo_t;
+
+static void
+qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
+{
+	qlt_port_logo_t *tmp;
+	int res;
+
+	mutex_lock(&vha->vha_tgt.tgt_mutex);
+
+	list_for_each_entry(tmp, &vha->logo_list, list) {
+		if (tmp->id.b24 == logo->id.b24) {
+			tmp->cmd_count += logo->cmd_count;
+			mutex_unlock(&vha->vha_tgt.tgt_mutex);
+			return;
+		}
+	}
+
+	list_add_tail(&logo->list, &vha->logo_list);
+
+	mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+	res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id);
+
+	mutex_lock(&vha->vha_tgt.tgt_mutex);
+	list_del(&logo->list);
+	mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+	dev_info(&vha->hw->pdev->dev,
+		 "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
+		 logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
+		 logo->cmd_count, res);
+}
+
 static void qlt_free_session_done(struct work_struct *work)
 {
 	struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess,
@@ -402,14 +448,21 @@ static void qlt_free_session_done(struct work_struct *work)
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
 		"%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
-		" s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+		" s_id %02x:%02x:%02x logout %d keep %d plogi %d els_logo %d\n",
 		__func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
 		sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
 		sess->logout_on_delete, sess->keep_nport_handle,
-		sess->plogi_ack_needed);
+		sess->plogi_ack_needed, sess->send_els_logo);
 
 	BUG_ON(!tgt);
 
+	if (sess->send_els_logo) {
+		qlt_port_logo_t logo;
+		logo.id = sess->s_id;
+		logo.cmd_count = 0;
+		qlt_send_first_logo(vha, &logo);
+	}
+
 	if (sess->logout_on_delete) {
 		int rc;
 
@@ -636,12 +689,12 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id,
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045,
 		    "qla_target(%d): get_id_list() failed: %x\n",
 		    vha->vp_idx, rc);
-		res = -1;
+		res = -EBUSY;
 		goto out_free_id_list;
 	}
 
 	id_iter = (char *)gid_list;
-	res = -1;
+	res = -ENOENT;
 	for (i = 0; i < entries; i++) {
 		struct gid_list_info *gid = (struct gid_list_info *)id_iter;
 		if ((gid->al_pa == s_id[2]) &&
@@ -2968,7 +3021,7 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
 
 	ctio24 = (struct ctio7_to_24xx *)pkt;
 	ctio24->entry_type = CTIO_TYPE7;
-	ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED;
+	ctio24->nport_handle = CTIO7_NHANDLE_UNRECOGNIZED;
 	ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
 	ctio24->vp_index = vha->vp_idx;
 	ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
@@ -3404,13 +3457,26 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 
 		case CTIO_PORT_LOGGED_OUT:
 		case CTIO_PORT_UNAVAILABLE:
+		{
+			bool logged_out = (status & 0xFFFF);
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
-			    "qla_target(%d): CTIO with PORT LOGGED "
-			    "OUT (29) or PORT UNAVAILABLE (28) status %x "
+			    "qla_target(%d): CTIO with %s status %x "
 			    "received (state %x, se_cmd %p)\n", vha->vp_idx,
+			    (logged_out == CTIO_PORT_LOGGED_OUT) ?
+			    "PORT LOGGED OUT" : "PORT UNAVAILABLE",
 			    status, cmd->state, se_cmd);
-			break;
 
+			if (logged_out && cmd->sess) {
+				/*
+				 * Session is already logged out, but we need
+				 * to notify initiator, who's not aware of this
+				 */
+				cmd->sess->logout_on_delete = 0;
+				cmd->sess->send_els_logo = 1;
+				qlt_schedule_sess_for_deletion(cmd->sess, true);
+			}
+			break;
+		}
 		case CTIO_SRR_RECEIVED:
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a,
 			    "qla_target(%d): CTIO with SRR_RECEIVED"
@@ -3698,10 +3764,8 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
 		goto out_term;
 	}
 
-	mutex_lock(&vha->vha_tgt.tgt_mutex);
 	sess = qlt_make_local_sess(vha, s_id);
 	/* sess has an extra creation ref. */
-	mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
 	if (!sess)
 		goto out_term;
@@ -5541,12 +5605,16 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *vha,
 	int rc, global_resets;
 	uint16_t loop_id = 0;
 
+	mutex_lock(&vha->vha_tgt.tgt_mutex);
+
 retry:
 	global_resets =
 	    atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
 
 	rc = qla24xx_get_loop_id(vha, s_id, &loop_id);
 	if (rc != 0) {
+		mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
 		if ((s_id[0] == 0xFF) &&
 		    (s_id[1] == 0xFC)) {
 			/*
@@ -5557,17 +5625,27 @@ retry:
 			    "Unable to find initiator with S_ID %x:%x:%x",
 			    s_id[0], s_id[1], s_id[2]);
 		} else
-			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf071,
+			ql_log(ql_log_info, vha, 0xf071,
 			    "qla_target(%d): Unable to find "
 			    "initiator with S_ID %x:%x:%x",
 			    vha->vp_idx, s_id[0], s_id[1],
 			    s_id[2]);
+
+		if (rc == -ENOENT) {
+			qlt_port_logo_t logo;
+			sid_to_portid(s_id, &logo.id);
+			logo.cmd_count = 1;
+			qlt_send_first_logo(vha, &logo);
+		}
+
 		return NULL;
 	}
 
 	fcport = qlt_get_port_database(vha, loop_id);
-	if (!fcport)
+	if (!fcport) {
+		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 		return NULL;
+	}
 
 	if (global_resets !=
 	    atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) {
@@ -5582,6 +5660,8 @@ retry:
 
 	sess = qlt_create_sess(vha, fcport, true);
 
+	mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
 	kfree(fcport);
 	return sess;
 }
@@ -5611,10 +5691,8 @@ static void qlt_abort_work(struct qla_tgt *tgt,
 	if (!sess) {
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-		mutex_lock(&vha->vha_tgt.tgt_mutex);
 		sess = qlt_make_local_sess(vha, s_id);
 		/* sess has got an extra creation ref */
-		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
 		spin_lock_irqsave(&ha->hardware_lock, flags);
 		if (!sess)
@@ -5670,10 +5748,8 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
 	if (!sess) {
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-		mutex_lock(&vha->vha_tgt.tgt_mutex);
 		sess = qlt_make_local_sess(vha, s_id);
 		/* sess has got an extra creation ref */
-		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
 		spin_lock_irqsave(&ha->hardware_lock, flags);
 		if (!sess)
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index bca584a..e316d42 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -909,6 +909,7 @@ struct qla_tgt_sess {
 	unsigned int logout_on_delete:1;
 	unsigned int plogi_ack_needed:1;
 	unsigned int keep_nport_handle:1;
+	unsigned int send_els_logo:1;
 
 	unsigned char logout_completed;
 
@@ -1120,6 +1121,14 @@ static inline uint32_t sid_to_key(const uint8_t *s_id)
 	return key;
 }
 
+static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
+{
+	memset(p, 0, sizeof(*p));
+	p->b.domain = s_id[0];
+	p->b.area = s_id[1];
+	p->b.al_pa = s_id[2];
+}
+
 /*
  * Exported symbols from qla_target.c LLD logic used by qla2xxx code..
  */
-- 
1.7.7


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

* [PATCH 07/20] qla2xxx: Wait for all conflicts before ack'ing PLOGI
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (5 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08 16:00   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 08/20] qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit Himanshu Madhani
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Alexei Potashnik <alexei@purestorage.com>

Until now ack'ing of a new PLOGI has only been delayed if there
was an existing session for the same WWN. Ack was released when
the session deletion completed.

If there was another WWN session with the same fc_id/loop_id pair
(aka "conflicting session"), PLOGI was still ack'ed immediately.
This potentially caused a problem when old session deletion logged
fc_id/loop_id out of FW after new session has been established.

Two work-arounds were attempted before:
1. Dropping PLOGIs until conflicting session goes away.
2. Detecting initiator being logged out of FW and issuing LOGO
to force re-login.

This patch introduces proper solution to the problem where PLOGI
is held until either existing session with same WWN or any
conflicting session goes away. Mechanism supports one session holding
two PLOGI acks as well as one PLOGI ack being held by many sessions.

Signed-off-by: Alexei Potashnik <alexei@purestorage.com>
Acked-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_dbg.c    |    4 +-
 drivers/scsi/qla2xxx/qla_def.h    |    2 +
 drivers/scsi/qla2xxx/qla_os.c     |    1 +
 drivers/scsi/qla2xxx/qla_target.c |  202 +++++++++++++++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_target.h |   18 +++-
 5 files changed, 177 insertions(+), 50 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 02f01be..b303027 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -26,7 +26,7 @@
  * |                              |                    | 0x3036,0x3038  |
  * |                              |                    | 0x303a		|
  * | DPC Thread                   |       0x4023       | 0x4002,0x4013  |
- * | Async Events                 |       0x508a       | 0x502b-0x502f  |
+ * | Async Events                 |       0x5089       | 0x502b-0x502f  |
  * |                              |                    | 0x5084,0x5075	|
  * |                              |                    | 0x503d,0x5044  |
  * |                              |                    | 0x507b,0x505f	|
@@ -63,7 +63,7 @@
  * |                              |                    | 0xd101-0xd1fe	|
  * |                              |                    | 0xd214-0xd2fe	|
  * | Target Mode		  |	  0xe080       |		|
- * | Target Mode Management	  |	  0xf096       | 0xf002		|
+ * | Target Mode Management	  |	  0xf09b       | 0xf002		|
  * |                              |                    | 0xf046-0xf049  |
  * | Target Mode Task Management  |	  0x1000d      |		|
  * ----------------------------------------------------------------------
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 1050fc2..46abba8 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3654,6 +3654,8 @@ typedef struct scsi_qla_host {
 	int			total_fcport_update_gen;
 	/* List of pending LOGOs, protected by tgt_mutex */
 	struct list_head	logo_list;
+	/* List of pending PLOGI acks, protected by hw lock */
+	struct list_head	plogi_ack_list;
 
 	uint32_t	vp_abort_cnt;
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c02cbc6..eb47272 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3919,6 +3919,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
 	INIT_LIST_HEAD(&vha->qla_cmd_list);
 	INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
 	INIT_LIST_HEAD(&vha->logo_list);
+	INIT_LIST_HEAD(&vha->plogi_ack_list);
 
 	spin_lock_init(&vha->work_lock);
 	spin_lock_init(&vha->cmd_list_lock);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 5ef9d4c..57b4294 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -118,10 +118,13 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha,
 	struct imm_ntfy_from_isp *ntfy,
 	uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
 	uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+	struct imm_ntfy_from_isp *imm, int ha_locked);
 /*
  * Global Variables
  */
 static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
+static struct kmem_cache *qla_tgt_plogi_cachep;
 static mempool_t *qla_tgt_mgmt_cmd_mempool;
 static struct workqueue_struct *qla_tgt_wq;
 static DEFINE_MUTEX(qla_tgt_mutex);
@@ -389,6 +392,85 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
 
 }
 
+/*
+ * All qlt_plogi_ack_t operations are protected by hardware_lock
+ */
+
+/*
+ * This is a zero-base ref-counting solution, since hardware_lock
+ * guarantees that ref_count is not modified concurrently.
+ * Upon successful return content of iocb is undefined
+ */
+static qlt_plogi_ack_t *
+qlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id,
+		       struct imm_ntfy_from_isp *iocb)
+{
+	qlt_plogi_ack_t *pla;
+
+	list_for_each_entry(pla, &vha->plogi_ack_list, list) {
+		if (pla->id.b24 == id->b24) {
+			qlt_send_term_imm_notif(vha, &pla->iocb, 1);
+			pla->iocb = *iocb;
+			return pla;
+		}
+	}
+
+	pla = kmem_cache_zalloc(qla_tgt_plogi_cachep, GFP_ATOMIC);
+	if (!pla) {
+		ql_dbg(ql_dbg_async, vha, 0x5088,
+		       "qla_target(%d): Allocation of plogi_ack failed\n",
+		       vha->vp_idx);
+		return NULL;
+	}
+
+	pla->iocb = *iocb;
+	pla->id = *id;
+	list_add_tail(&pla->list, &vha->plogi_ack_list);
+
+	return pla;
+}
+
+static void qlt_plogi_ack_unref(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla)
+{
+	BUG_ON(!pla->ref_count);
+	pla->ref_count--;
+
+	if (pla->ref_count)
+		return;
+
+	ql_dbg(ql_dbg_async, vha, 0x5089,
+	    "Sending PLOGI ACK to wwn %8phC s_id %02x:%02x:%02x loop_id %#04x"
+	    " exch %#x ox_id %#x\n", pla->iocb.u.isp24.port_name,
+	    pla->iocb.u.isp24.port_id[2], pla->iocb.u.isp24.port_id[1],
+	    pla->iocb.u.isp24.port_id[0],
+	    le16_to_cpu(pla->iocb.u.isp24.nport_handle),
+	    pla->iocb.u.isp24.exchange_address, pla->iocb.ox_id);
+	qlt_send_notify_ack(vha, &pla->iocb, 0, 0, 0, 0, 0, 0);
+
+	list_del(&pla->list);
+	kmem_cache_free(qla_tgt_plogi_cachep, pla);
+}
+
+static void
+qlt_plogi_ack_link(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla,
+    struct qla_tgt_sess *sess, qlt_plogi_link_t link)
+{
+	/* Inc ref_count first because link might already be pointing at pla */
+	pla->ref_count++;
+
+	if (sess->plogi_link[link])
+		qlt_plogi_ack_unref(vha, sess->plogi_link[link]);
+
+	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf097,
+	    "Linking sess %p [%d] wwn %8phC with PLOGI ACK to wwn %8phC"
+	    " s_id %02x:%02x:%02x, ref=%d\n", sess, link, sess->port_name,
+	    pla->iocb.u.isp24.port_name, pla->iocb.u.isp24.port_id[2],
+	    pla->iocb.u.isp24.port_id[1], pla->iocb.u.isp24.port_id[0],
+	    pla->ref_count);
+
+	sess->plogi_link[link] = pla;
+}
+
 typedef struct {
 	/* These fields must be initialized by the caller */
 	port_id_t id;
@@ -429,10 +511,10 @@ qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
 	list_del(&logo->list);
 	mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
-	dev_info(&vha->hw->pdev->dev,
-		 "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
-		 logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
-		 logo->cmd_count, res);
+	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf098,
+	    "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
+	    logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
+	    logo->cmd_count, res);
 }
 
 static void qlt_free_session_done(struct work_struct *work)
@@ -448,11 +530,11 @@ static void qlt_free_session_done(struct work_struct *work)
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
 		"%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
-		" s_id %02x:%02x:%02x logout %d keep %d plogi %d els_logo %d\n",
+		" s_id %02x:%02x:%02x logout %d keep %d els_logo %d\n",
 		__func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
 		sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
 		sess->logout_on_delete, sess->keep_nport_handle,
-		sess->plogi_ack_needed, sess->send_els_logo);
+		sess->send_els_logo);
 
 	BUG_ON(!tgt);
 
@@ -508,9 +590,33 @@ static void qlt_free_session_done(struct work_struct *work)
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
-	if (sess->plogi_ack_needed)
-		qlt_send_notify_ack(vha, &sess->tm_iocb,
-				    0, 0, 0, 0, 0, 0);
+	{
+		qlt_plogi_ack_t *own =
+		    sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
+		qlt_plogi_ack_t *con =
+		    sess->plogi_link[QLT_PLOGI_LINK_CONFLICT];
+
+		if (con) {
+			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf099,
+			    "se_sess %p / sess %p port %8phC is gone,"
+			    " %s (ref=%d), releasing PLOGI for %8phC (ref=%d)\n",
+			    sess->se_sess, sess, sess->port_name,
+			    own ? "releasing own PLOGI" :
+			    "no own PLOGI pending",
+			    own ? own->ref_count : -1,
+			    con->iocb.u.isp24.port_name, con->ref_count);
+			qlt_plogi_ack_unref(vha, con);
+		} else {
+			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09a,
+			    "se_sess %p / sess %p port %8phC is gone, %s (ref=%d)\n",
+			    sess->se_sess, sess, sess->port_name,
+			    own ? "releasing own PLOGI" : "no own PLOGI pending",
+			    own ? own->ref_count : -1);
+		}
+
+		if (own)
+			qlt_plogi_ack_unref(vha, own);
+	}
 
 	list_del(&sess->sess_list_entry);
 
@@ -4092,15 +4198,6 @@ void qlt_logo_completion_handler(fc_port_t *fcport, int rc)
 	}
 }
 
-static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
-    struct imm_ntfy_from_isp *b)
-{
-	struct imm_ntfy_from_isp tmp;
-	memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp));
-	memcpy(a, b, sizeof(struct imm_ntfy_from_isp));
-	memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp));
-}
-
 /*
 * ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list)
 *
@@ -4110,11 +4207,13 @@ static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
 */
 static struct qla_tgt_sess *
 qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
-    port_id_t port_id, uint16_t loop_id)
+    port_id_t port_id, uint16_t loop_id, struct qla_tgt_sess **conflict_sess)
 {
 	struct qla_tgt_sess *sess = NULL, *other_sess;
 	uint64_t other_wwn;
 
+	*conflict_sess = NULL;
+
 	list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) {
 
 		other_wwn = wwn_to_u64(other_sess->port_name);
@@ -4142,9 +4241,10 @@ qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
 			} else {
 				/*
 				 * Another wwn used to have our s_id/loop_id
-				 * combo - kill the session, but don't log out
+				 * kill the session, but don't free the loop_id
 				 */
-				sess->logout_on_delete = 0;
+				other_sess->keep_nport_handle = 1;
+				*conflict_sess = other_sess;
 				qlt_schedule_sess_for_deletion(other_sess,
 				    true);
 			}
@@ -4206,12 +4306,13 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 {
 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 	struct qla_hw_data *ha = vha->hw;
-	struct qla_tgt_sess *sess = NULL;
+	struct qla_tgt_sess *sess = NULL, *conflict_sess = NULL;
 	uint64_t wwn;
 	port_id_t port_id;
 	uint16_t loop_id;
 	uint16_t wd3_lo;
 	int res = 0;
+	qlt_plogi_ack_t *pla;
 
 	wwn = wwn_to_u64(iocb->u.isp24.port_name);
 
@@ -4237,25 +4338,15 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 
 		if (wwn)
 			sess = qlt_find_sess_invalidate_other(tgt, wwn,
-			    port_id, loop_id);
+			    port_id, loop_id, &conflict_sess);
 
-		if (!sess || IS_SW_RESV_ADDR(sess->s_id)) {
+		if (IS_SW_RESV_ADDR(port_id) || (!sess && !conflict_sess)) {
 			res = 1;
 			break;
 		}
 
-		if (sess->plogi_ack_needed) {
-			/*
-			 * Initiator sent another PLOGI before last PLOGI could
-			 * finish. Swap plogi iocbs and terminate old one
-			 * without acking, new one will get acked when session
-			 * deletion completes.
-			 */
-			ql_log(ql_log_warn, sess->vha, 0xf094,
-			    "sess %p received double plogi.\n", sess);
-
-			qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb);
-
+		pla = qlt_plogi_ack_find_add(vha, &port_id, iocb);
+		if (!pla) {
 			qlt_send_term_imm_notif(vha, iocb, 1);
 
 			res = 0;
@@ -4264,13 +4355,14 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 
 		res = 0;
 
-		/*
-		 * Save immediate Notif IOCB for Ack when sess is done
-		 * and being deleted.
-		 */
-		memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb));
-		sess->plogi_ack_needed  = 1;
+		if (conflict_sess)
+			qlt_plogi_ack_link(vha, pla, conflict_sess,
+			    QLT_PLOGI_LINK_CONFLICT);
+
+		if (!sess)
+			break;
 
+		qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
 		 /*
 		  * Under normal circumstances we want to release nport handle
 		  * during LOGO process to avoid nport handle leaks inside FW.
@@ -4299,7 +4391,16 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 
 		if (wwn)
 			sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
-			    loop_id);
+			    loop_id, &conflict_sess);
+
+		if (conflict_sess) {
+			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09b,
+			    "PRLI with conflicting sess %p port %8phC\n",
+			    conflict_sess, conflict_sess->port_name);
+			qlt_send_term_imm_notif(vha, iocb, 1);
+			res = 0;
+			break;
+		}
 
 		if (sess != NULL) {
 			if (sess->deleted) {
@@ -6615,13 +6716,23 @@ int __init qlt_init(void)
 		return -ENOMEM;
 	}
 
+	qla_tgt_plogi_cachep = kmem_cache_create("qla_tgt_plogi_cachep",
+						 sizeof(qlt_plogi_ack_t),
+						 __alignof__(qlt_plogi_ack_t), 0, NULL);
+	if (!qla_tgt_plogi_cachep) {
+		ql_log(ql_log_fatal, NULL, 0xe06d,
+		    "kmem_cache_create for qla_tgt_plogi_cachep failed\n");
+		ret = -ENOMEM;
+		goto out_mgmt_cmd_cachep;
+	}
+
 	qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab,
 	    mempool_free_slab, qla_tgt_mgmt_cmd_cachep);
 	if (!qla_tgt_mgmt_cmd_mempool) {
 		ql_log(ql_log_fatal, NULL, 0xe06e,
 		    "mempool_create for qla_tgt_mgmt_cmd_mempool failed\n");
 		ret = -ENOMEM;
-		goto out_mgmt_cmd_cachep;
+		goto out_plogi_cachep;
 	}
 
 	qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0);
@@ -6638,6 +6749,8 @@ int __init qlt_init(void)
 
 out_cmd_mempool:
 	mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+out_plogi_cachep:
+	kmem_cache_destroy(qla_tgt_plogi_cachep);
 out_mgmt_cmd_cachep:
 	kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
 	return ret;
@@ -6650,5 +6763,6 @@ void qlt_exit(void)
 
 	destroy_workqueue(qla_tgt_wq);
 	mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+	kmem_cache_destroy(qla_tgt_plogi_cachep);
 	kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
 }
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index e316d42..0a78545 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -896,6 +896,19 @@ enum qla_sess_deletion {
 	QLA_SESS_DELETION_IN_PROGRESS	= 2,
 };
 
+typedef enum {
+	QLT_PLOGI_LINK_SAME_WWN,
+	QLT_PLOGI_LINK_CONFLICT,
+	QLT_PLOGI_LINK_MAX
+} qlt_plogi_link_t;
+
+typedef struct {
+	struct list_head		list;
+	struct imm_ntfy_from_isp	iocb;
+	port_id_t			id;
+	int				ref_count;
+} qlt_plogi_ack_t;
+
 /*
  * Equivilant to IT Nexus (Initiator-Target)
  */
@@ -907,7 +920,6 @@ struct qla_tgt_sess {
 	unsigned int deleted:2;
 	unsigned int local:1;
 	unsigned int logout_on_delete:1;
-	unsigned int plogi_ack_needed:1;
 	unsigned int keep_nport_handle:1;
 	unsigned int send_els_logo:1;
 
@@ -926,9 +938,7 @@ struct qla_tgt_sess {
 	uint8_t port_name[WWN_SIZE];
 	struct work_struct free_work;
 
-	union {
-		struct imm_ntfy_from_isp tm_iocb;
-	};
+	qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
 };
 
 struct qla_tgt_cmd {
-- 
1.7.7


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

* [PATCH 08/20] qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (6 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 07/20] qla2xxx: Wait for all conflicts before ack'ing PLOGI Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08 16:01   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1 Himanshu Madhani
                   ` (11 subsequent siblings)
  19 siblings, 1 reply; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

Replace QLA_TGT_STATE_ABORTED state with a bit because
the current state of the command is lost when an abort
is requested by upper layer.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_target.c |   23 ++++++++++-------------
 drivers/scsi/qla2xxx/qla_target.h |    3 ++-
 2 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 57b4294..638940f 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -1468,7 +1468,7 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
 
 	list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
 		if (tag == cmd->atio.u.isp24.exchange_addr) {
-			cmd->state = QLA_TGT_STATE_ABORTED;
+			cmd->aborted = 1;
 			spin_unlock(&vha->cmd_list_lock);
 			return 1;
 		}
@@ -1510,7 +1510,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha,
 		cmd_lun = scsilun_to_int(
 			(struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
 		if (cmd_key == key && cmd_lun == lun)
-			cmd->state = QLA_TGT_STATE_ABORTED;
+			cmd->aborted = 1;
 	}
 	spin_unlock(&vha->cmd_list_lock);
 }
@@ -3174,7 +3174,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
 		qlt_alloc_qfull_cmd(vha, atio, 0, 0);
 
 done:
-	if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
+	if (cmd && (!cmd->aborted ||
 	    !cmd->cmd_sent_to_fw)) {
 		if (cmd->sg_mapped)
 			qlt_unmap_sg(vha, cmd);
@@ -3245,7 +3245,7 @@ void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
 	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
 	    se_cmd->tag);
 
-	cmd->state = QLA_TGT_STATE_ABORTED;
+	cmd->aborted = 1;
 	cmd->cmd_flags |= BIT_6;
 
 	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
@@ -3465,9 +3465,6 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
 
 		ha->tgt.tgt_ops->handle_data(cmd);
 		return;
-	} else if (cmd->state == QLA_TGT_STATE_ABORTED) {
-		ql_dbg(ql_dbg_io, vha, 0xff02,
-		    "HOST-ABORT: handle=%d, state=ABORTED.\n", handle);
 	} else {
 		ql_dbg(ql_dbg_io, vha, 0xff03,
 		    "HOST-ABORT: handle=%d, state=BAD(%d).\n", handle,
@@ -3632,14 +3629,14 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
 		}
 
 
-		/* "cmd->state == QLA_TGT_STATE_ABORTED" means
+		/* "cmd->aborted" means
 		 * cmd is already aborted/terminated, we don't
 		 * need to terminate again.  The exchange is already
 		 * cleaned up/freed at FW level.  Just cleanup at driver
 		 * level.
 		 */
 		if ((cmd->state != QLA_TGT_STATE_NEED_DATA) &&
-		    (cmd->state != QLA_TGT_STATE_ABORTED)) {
+		    (!cmd->aborted)) {
 			cmd->cmd_flags |= BIT_13;
 			if (qlt_term_ctio_exchange(vha, ctio, cmd, status))
 				return;
@@ -3657,7 +3654,7 @@ skip_term:
 
 		ha->tgt.tgt_ops->handle_data(cmd);
 		return;
-	} else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+	} else if (cmd->aborted) {
 		cmd->cmd_flags |= BIT_18;
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
 		  "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
@@ -3669,7 +3666,7 @@ skip_term:
 	}
 
 	if (unlikely(status != CTIO_SUCCESS) &&
-		(cmd->state != QLA_TGT_STATE_ABORTED)) {
+		!cmd->aborted) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n");
 		dump_stack();
 	}
@@ -3731,7 +3728,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
 	if (tgt->tgt_stop)
 		goto out_term;
 
-	if (cmd->state == QLA_TGT_STATE_ABORTED) {
+	if (cmd->aborted) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
 		    "cmd with tag %u is aborted\n",
 		    cmd->atio.u.isp24.exchange_addr);
@@ -4289,7 +4286,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id)
 	list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
 		uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
 		if (cmd_key == key) {
-			cmd->state = QLA_TGT_STATE_ABORTED;
+			cmd->aborted = 1;
 			count++;
 		}
 	}
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 0a78545..f5dbeab 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -787,7 +787,7 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
 #define QLA_TGT_STATE_NEED_DATA		1 /* target needs data to continue */
 #define QLA_TGT_STATE_DATA_IN		2 /* Data arrived + target processing */
 #define QLA_TGT_STATE_PROCESSED		3 /* target done processing */
-#define QLA_TGT_STATE_ABORTED		4 /* Command aborted */
+
 
 /* Special handles */
 #define QLA_TGT_NULL_HANDLE	0
@@ -960,6 +960,7 @@ struct qla_tgt_cmd {
 	unsigned int term_exchg:1;
 	unsigned int cmd_sent_to_fw:1;
 	unsigned int cmd_in_wq:1;
+	unsigned int aborted:1;
 
 	struct scatterlist *sg;	/* cmd data buffer SG vector */
 	int sg_cnt;		/* SG segments count */
-- 
1.7.7

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

* [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (7 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 08/20] qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08  2:33   ` Christoph Hellwig
  2015-12-09  6:56   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module Himanshu Madhani
                   ` (10 subsequent siblings)
  19 siblings, 2 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

change tcm_qla2xxx_check_stop_free to always return 1
to prevent transport_cmd_finish_abort from accidently
taking extra kref_put.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 74c6e9b..366142a 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -314,7 +314,8 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd)
 		cmd->cmd_flags |= BIT_14;
 	}
 
-	return target_put_sess_cmd(se_cmd);
+	target_put_sess_cmd(se_cmd);
+	return 1;
 }
 
 /* tcm_qla2xxx_release_cmd - Callback from TCM Core to release underlying
-- 
1.7.7

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

* [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (8 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1 Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08  2:37   ` Christoph Hellwig
  2015-12-09  7:01   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer Himanshu Madhani
                   ` (9 subsequent siblings)
  19 siblings, 2 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

During lun reset, TMR thread from TCM would issue abort
to qla driver.  At abort time, each command is in different
state.  Depending on the state, qla will use the TMR thread
to trigger a command free(cmd_kref--) if command is not
down at firmware.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_target.c  |   60 +++++++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_target.h  |   59 +++++++++++++++++------------
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   73 ++++++++++++++++++++++++++++++++++-
 3 files changed, 147 insertions(+), 45 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 638940f..4d42b79 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -105,7 +105,7 @@ static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
 static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
 	int fn, void *iocb, int flags);
 static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
-	*cmd, struct atio_from_isp *atio, int ha_locked);
+	*cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
 static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
 	struct qla_tgt_srr_imm *imm, int ha_lock);
 static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
@@ -2646,7 +2646,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 			/* no need to terminate. FW already freed exchange. */
 			qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		else
-			qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+			qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return 0;
 	}
@@ -3154,7 +3154,8 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
 }
 
 static void qlt_send_term_exchange(struct scsi_qla_host *vha,
-	struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
+	struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked,
+	int ul_abort)
 {
 	unsigned long flags = 0;
 	int rc;
@@ -3174,8 +3175,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
 		qlt_alloc_qfull_cmd(vha, atio, 0, 0);
 
 done:
-	if (cmd && (!cmd->aborted ||
-	    !cmd->cmd_sent_to_fw)) {
+	if (cmd && !ul_abort && !cmd->aborted) {
 		if (cmd->sg_mapped)
 			qlt_unmap_sg(vha, cmd);
 		vha->hw->tgt.tgt_ops->free_cmd(cmd);
@@ -3234,21 +3234,43 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
 
 }
 
-void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
 {
 	struct qla_tgt *tgt = cmd->tgt;
 	struct scsi_qla_host *vha = tgt->vha;
 	struct se_cmd *se_cmd = &cmd->se_cmd;
+	unsigned long flags,refcount;
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
 	    "qla_target(%d): terminating exchange for aborted cmd=%p "
 	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
 	    se_cmd->tag);
 
+    spin_lock_irqsave(&cmd->cmd_lock, flags);
+    if (cmd->aborted) {
+        spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+        /* It's normal to see 2 calls in this path:
+         *  1) XFER Rdy completion + CMD_T_ABORT
+         *  2) TCM TMR - drain_state_list
+         */
+        refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
+        ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
+               "multiple abort. %p refcount %lx"
+               "transport_state %x, t_state %x, se_cmd_flags %x \n",
+               cmd, refcount,cmd->se_cmd.transport_state,
+               cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+
+        return EIO;
+    }
+
 	cmd->aborted = 1;
 	cmd->cmd_flags |= BIT_6;
+    spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
 
-	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
+	return 0;
 }
 EXPORT_SYMBOL(qlt_abort_cmd);
 
@@ -3263,6 +3285,9 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
 
 	BUG_ON(cmd->cmd_in_wq);
 
+	if (cmd->sg_mapped)
+		qlt_unmap_sg(cmd->vha, cmd);
+
 	if (!cmd->q_full)
 		qlt_decr_num_pend_cmds(cmd->vha);
 
@@ -3380,7 +3405,7 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio,
 		term = 1;
 
 	if (term)
-		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 
 	return term;
 }
@@ -3735,6 +3760,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
 		goto out_term;
 	}
 
+	spin_lock_init(&cmd->cmd_lock);
 	cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
 	cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
 	cmd->unpacked_lun = scsilun_to_int(
@@ -3777,7 +3803,7 @@ out_term:
 	 */
 	cmd->cmd_flags |= BIT_2;
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
+	qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0);
 
 	qlt_decr_num_pend_cmds(vha);
 	percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
@@ -3896,7 +3922,7 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
 
 out_term:
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	qlt_send_term_exchange(vha, NULL, &op->atio, 1);
+	qlt_send_term_exchange(vha, NULL, &op->atio, 1, 0);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 	kfree(op);
 
@@ -4722,7 +4748,7 @@ out_reject:
 		dump_stack();
 	} else {
 		cmd->cmd_flags |= BIT_9;
-		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
@@ -4901,7 +4927,7 @@ static void qlt_prepare_srr_imm(struct scsi_qla_host *vha,
 				    sctio, sctio->srr_id);
 				list_del(&sctio->srr_list_entry);
 				qlt_send_term_exchange(vha, sctio->cmd,
-				    &sctio->cmd->atio, 1);
+				    &sctio->cmd->atio, 1, 0);
 				kfree(sctio);
 			}
 		}
@@ -5071,7 +5097,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
 	    atio->u.isp24.fcp_hdr.s_id);
 	if (!sess) {
-		qlt_send_term_exchange(vha, NULL, atio, 1);
+		qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 		return 0;
 	}
 	/* Sending marker isn't necessary, since we called from ISR */
@@ -5345,7 +5371,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
 				qlt_send_busy(vha, atio, SAM_STAT_BUSY);
 #else
-				qlt_send_term_exchange(vha, NULL, atio, 1);
+				qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 #endif
 			} else {
 				if (tgt->tgt_stop) {
@@ -5446,7 +5472,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
 #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
 				qlt_send_busy(vha, atio, 0);
 #else
-				qlt_send_term_exchange(vha, NULL, atio, 1);
+				qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 #endif
 			} else {
 				if (tgt->tgt_stop) {
@@ -5455,7 +5481,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
 					    "command to target, sending TERM "
 					    "EXCHANGE for rsp\n");
 					qlt_send_term_exchange(vha, NULL,
-					    atio, 1);
+					    atio, 1, 0);
 				} else {
 					ql_dbg(ql_dbg_tgt, vha, 0xe060,
 					    "qla_target(%d): Unable to send "
@@ -5875,7 +5901,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
 	return;
 
 out_term:
-	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
+	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
 	if (sess)
 		ha->tgt.tgt_ops->put_sess(sess);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index f5dbeab..a079c237 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -941,6 +941,36 @@ struct qla_tgt_sess {
 	qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
 };
 
+typedef enum {
+	/*
+	 * BIT_0 - Atio Arrival / schedule to work
+	 * BIT_1 - qlt_do_work
+	 * BIT_2 - qlt_do work failed
+	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
+	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
+	 * BIT_5 - status respond / tcm_qla2xx_queue_status
+	 * BIT_6 - tcm request to abort/Term exchange.
+	 *	pre_xmit_response->qlt_send_term_exchange
+	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
+	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
+	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
+	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
+
+	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
+	 * BIT_13 - Bad completion -
+	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
+	 * BIT_14 - Back end data received/sent.
+	 * BIT_15 - SRR prepare ctio
+	 * BIT_16 - complete free
+	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
+	 * BIT_18 - completion w/abort status
+	 * BIT_19 - completion w/unknown status
+	 * BIT_20 - tcm_qla2xxx_free_cmd
+	 */
+	CMD_FLAG_DATA_WORK = BIT_11,
+	CMD_FLAG_DATA_WORK_FREE = BIT_21,
+} cmd_flags_t;
+
 struct qla_tgt_cmd {
 	struct se_cmd se_cmd;
 	struct qla_tgt_sess *sess;
@@ -950,6 +980,7 @@ struct qla_tgt_cmd {
 	/* Sense buffer that will be mapped into outgoing status */
 	unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
 
+	spinlock_t cmd_lock;
 	/* to save extra sess dereferences */
 	unsigned int conf_compl_supported:1;
 	unsigned int sg_mapped:1;
@@ -984,30 +1015,8 @@ struct qla_tgt_cmd {
 
 	uint64_t jiffies_at_alloc;
 	uint64_t jiffies_at_free;
-	/* BIT_0 - Atio Arrival / schedule to work
-	 * BIT_1 - qlt_do_work
-	 * BIT_2 - qlt_do work failed
-	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
-	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
-	 * BIT_5 - status respond / tcm_qla2xx_queue_status
-	 * BIT_6 - tcm request to abort/Term exchange.
-	 *	pre_xmit_response->qlt_send_term_exchange
-	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
-	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
-	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
-	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
-	 * BIT_11 - Data actually going to TCM : tcm_qla2xx_handle_data_work
-	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
-	 * BIT_13 - Bad completion -
-	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
-	 * BIT_14 - Back end data received/sent.
-	 * BIT_15 - SRR prepare ctio
-	 * BIT_16 - complete free
-	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
-	 * BIT_18 - completion w/abort status
-	 * BIT_19 - completion w/unknown status
-	 */
-	uint32_t cmd_flags;
+
+	cmd_flags_t cmd_flags;
 };
 
 struct qla_tgt_sess_work_param {
@@ -1146,7 +1155,7 @@ static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
 extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
 extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
 extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
-extern void qlt_abort_cmd(struct qla_tgt_cmd *);
+extern int qlt_abort_cmd(struct qla_tgt_cmd *);
 extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 366142a..842fcca 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -298,6 +298,10 @@ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
 {
 	cmd->vha->tgt_counters.core_qla_free_cmd++;
 	cmd->cmd_in_wq = 1;
+
+	BUG_ON(cmd->cmd_flags & BIT_20);
+	cmd->cmd_flags |= BIT_20;
+
 	INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
 	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
 }
@@ -375,6 +379,20 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
+
+	if (cmd->aborted) {
+		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
+		 * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+		 * already kick start the free.
+		 */
+		pr_debug("write_pending aborted cmd[%p] refcount %d "
+			"transport_state %x, t_state %x, se_cmd_flags %x\n",
+			cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+			cmd->se_cmd.transport_state,
+			cmd->se_cmd.t_state,
+			cmd->se_cmd.se_cmd_flags);
+		return 0;
+	}
 	cmd->cmd_flags |= BIT_3;
 	cmd->bufflen = se_cmd->data_length;
 	cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -406,7 +424,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
 	    se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
 		spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
 		wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
-					    3 * HZ);
+						50);
 		return 0;
 	}
 	spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@ -466,13 +484,25 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
 static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 {
 	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+	unsigned long flags;
 
 	/*
 	 * Ensure that the complete FCP WRITE payload has been received.
 	 * Otherwise return an exception via CHECK_CONDITION status.
 	 */
 	cmd->cmd_in_wq = 0;
-	cmd->cmd_flags |= BIT_11;
+
+	spin_lock_irqsave(&cmd->cmd_lock, flags);
+	cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
+	if (cmd->aborted) {
+		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+		tcm_qla2xxx_free_cmd(cmd);
+		return;
+	}
+	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
 	cmd->vha->tgt_counters.qla_core_ret_ctio++;
 	if (!cmd->write_data_transferred) {
 		/*
@@ -547,6 +577,20 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
 
+	if (cmd->aborted) {
+		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
+		 * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+		 * already kick start the free.
+		 */
+		pr_debug("queue_data_in aborted cmd[%p] refcount %d "
+			"transport_state %x, t_state %x, se_cmd_flags %x\n",
+			cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+			cmd->se_cmd.transport_state,
+			cmd->se_cmd.t_state,
+			cmd->se_cmd.se_cmd_flags);
+		return 0;
+	}
+
 	cmd->cmd_flags |= BIT_4;
 	cmd->bufflen = se_cmd->data_length;
 	cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -638,11 +682,34 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
 	qlt_xmit_tm_rsp(mcmd);
 }
 
+
+#define DATA_WORK_NOT_FREE(_flags) \
+	(( _flags & (CMD_FLAG_DATA_WORK|CMD_FLAG_DATA_WORK_FREE)) == \
+	 CMD_FLAG_DATA_WORK)
 static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
-	qlt_abort_cmd(cmd);
+	unsigned long flags;
+
+	if (qlt_abort_cmd(cmd))
+		return;
+
+	spin_lock_irqsave(&cmd->cmd_lock, flags);
+	if ((cmd->state == QLA_TGT_STATE_NEW)||
+		((cmd->state == QLA_TGT_STATE_DATA_IN) &&
+		 DATA_WORK_NOT_FREE(cmd->cmd_flags)) ) {
+
+		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+		/* Cmd have not reached firmware.
+		 * Use this trigger to free it. */
+		tcm_qla2xxx_free_cmd(cmd);
+		return;
+	}
+	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+	return;
+
 }
 
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
-- 
1.7.7


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

* [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (9 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08  2:48   ` Christoph Hellwig
  2015-12-09  7:02   ` Hannes Reinecke
  2015-12-08  0:48 ` [PATCH 12/20] target/tmr: LUN reset cause cmd premature free Himanshu Madhani
                   ` (8 subsequent siblings)
  19 siblings, 2 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

For kernel 3.15 and newer with TCM API change, add detection
for TCM support of TAS.  Instead of default command terminate
for LUN/TARGET reset error handling, allow SCSI status to go
out if we know sequece Initiative is own by FW (cmd_sent_to_fw=0)

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_target.c  |   36 +++++++++++++++++-------------------
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   20 ++++++++++++++++++++
 2 files changed, 37 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 4d42b79..5fca846 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3239,36 +3239,34 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
 	struct qla_tgt *tgt = cmd->tgt;
 	struct scsi_qla_host *vha = tgt->vha;
 	struct se_cmd *se_cmd = &cmd->se_cmd;
-	unsigned long flags,refcount;
+	unsigned long flags, refcount;
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
 	    "qla_target(%d): terminating exchange for aborted cmd=%p "
 	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
 	    se_cmd->tag);
 
-    spin_lock_irqsave(&cmd->cmd_lock, flags);
-    if (cmd->aborted) {
-        spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+	spin_lock_irqsave(&cmd->cmd_lock, flags);
 
-        /* It's normal to see 2 calls in this path:
-         *  1) XFER Rdy completion + CMD_T_ABORT
-         *  2) TCM TMR - drain_state_list
-         */
-        refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
-        ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
-               "multiple abort. %p refcount %lx"
-               "transport_state %x, t_state %x, se_cmd_flags %x \n",
-               cmd, refcount,cmd->se_cmd.transport_state,
-               cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+	if (cmd->aborted) {
+		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+		/* It's normal to see 2 calls in this path:
+		 *  1) XFER Rdy completion + CMD_T_ABORT
+		 *  2) TCM TMR - drain_state_list
+		 */
+		refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
+		ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
+		    "multiple abort. %p refcount %lx"
+		    "transport_state %x, t_state %x, se_cmd_flags %x \n",
+		    cmd, refcount, cmd->se_cmd.transport_state,
+		    cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags);
 
-        return EIO;
-    }
+		return EIO;
+	}
 
 	cmd->aborted = 1;
 	cmd->cmd_flags |= BIT_6;
-    spin_unlock_irqrestore(&cmd->cmd_lock, flags);
-
-	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
+	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
 	return 0;
 }
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 842fcca..2e9c194 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -617,6 +617,26 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
 				struct qla_tgt_cmd, se_cmd);
 	int xmit_type = QLA_TGT_XMIT_STATUS;
 
+	if (se_cmd->transport_state & CMD_T_ABORTED) {
+		/* For TCM TAS support n kernel >= 3.15:
+		 * This cmd is attempting to respond with "Task Aborted Status".
+		 */
+		if (cmd->aborted) {
+			return 0;
+		} else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
+		    cmd->cmd_sent_to_fw) {
+			qlt_abort_cmd(cmd);
+			return 0;
+		} else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
+			if (cmd->cmd_sent_to_fw) {
+				qlt_abort_cmd(cmd);
+				return 0;
+			} else {	/* about to be free */
+				return 0;
+			}
+		}
+	}
+
 	cmd->bufflen = se_cmd->data_length;
 	cmd->sg = NULL;
 	cmd->sg_cnt = 0;
-- 
1.7.7

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

* [PATCH 12/20] target/tmr: LUN reset cause cmd premature free.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (10 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer Himanshu Madhani
@ 2015-12-08  0:48 ` Himanshu Madhani
  2015-12-08  2:48   ` Christoph Hellwig
  2015-12-09  7:03   ` Hannes Reinecke
  2015-12-08  0:49 ` [PATCH 13/20] qla2xxx: Remove dependency on hardware_lock to reduce lock contention Himanshu Madhani
                   ` (7 subsequent siblings)
  19 siblings, 2 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:48 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

During LUN/Target reset, the TMR code attempt to intercept
cmds and try to aborted them.  Current code assume cmds are
always intercepted at the back end device.  The cleanup code
would issue a "queue_status() & check_stop_free()" to terminate
the command.  However, when a cmd is intercepted at the front
end/Fabric layer, current code introduce premature free or
cause Fabric to double free.

When command is intercepted at Fabric layer, it means a
check_stop_free(cmd_kref--) has been called.  The extra
check_stop_free in the Lun Reset cleanup code causes early
free.  When a cmd in the Fabric layer is completed, the normal
free code adds another another free which introduce a double free.

To fix the issue:
- add a new flag/CMD_T_SENT_STATUS to track command that have
 made it down to fabric layer after back end good/bad completion.
- if cmd reach Fabric Layer at Lun Reset time, add an extra
 cmd_kref count to prevent premature free.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/target/target_core_tmr.c       |   33 +++++++++++++++++++++++++++++++-
 drivers/target/target_core_transport.c |   30 +++++++++++++++++++++++++++++
 include/target/target_core_base.h      |    1 +
 3 files changed, 63 insertions(+), 1 deletions(-)

diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 28fb301..41f8b57 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -243,7 +243,9 @@ static void core_tmr_drain_state_list(
 {
 	LIST_HEAD(drain_task_list);
 	struct se_cmd *cmd, *next;
-	unsigned long flags;
+	unsigned long flags, flags2;
+	int rmkref;
+	struct se_session *se_sess;
 
 	/*
 	 * Complete outstanding commands with TASK_ABORTED SAM status.
@@ -282,6 +284,16 @@ static void core_tmr_drain_state_list(
 		if (prout_cmd == cmd)
 			continue;
 
+		se_sess = cmd->se_sess;
+		/* take an extra kref to prevent cmd free race condition. */
+		spin_lock_irqsave(&se_sess->sess_cmd_lock, flags2);
+		if (!kref_get_unless_zero(&cmd->cmd_kref)) {
+			/* cmd is already in the free process */
+			spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags2);
+			continue;
+		}
+		spin_unlock_irqrestore(&se_sess->sess_cmd_lock,	flags2);
+
 		list_move_tail(&cmd->state_list, &drain_task_list);
 		cmd->state_active = false;
 	}
@@ -320,9 +332,28 @@ static void core_tmr_drain_state_list(
 		target_stop_cmd(cmd, &flags);
 
 		cmd->transport_state |= CMD_T_ABORTED;
+
+		/* CMD_T_SENT_STATUS: cmd is down in fabric layer.
+		 * A check stop has been called.  Keep the extra kref
+		 * from above because core_tmr_handle_tas_abort will
+		 * generate another check_stop.
+		 *
+		 * !CMD_T_SENT_STATUS: cmd intercepted at back end.
+		 * Remove the extra kref from above because only
+		 * 1 check_stop is required or generated by
+		 * core_tmr_handle_tas_abort()
+		 */
+		rmkref = 0;
+		if (!((cmd->t_state == TRANSPORT_COMPLETE) &&
+		    (cmd->transport_state & CMD_T_SENT_STATUS)))
+			rmkref = 1;
+
 		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
 		core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
+
+		if (rmkref)
+			target_put_sess_cmd(cmd);
 	}
 }
 
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 4fdcee2..cdd18bf 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -639,9 +639,14 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 static void target_complete_failure_work(struct work_struct *work)
 {
 	struct se_cmd *cmd = container_of(work, struct se_cmd, work);
+	unsigned long flags;
 
 	transport_generic_request_failure(cmd,
 			TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	cmd->transport_state |= CMD_T_SENT_STATUS;
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 }
 
 /*
@@ -1659,6 +1664,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
 		sense_reason_t sense_reason)
 {
 	int ret = 0, post_ret = 0;
+	unsigned long flags;
 
 	pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx"
 		" CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]);
@@ -1670,6 +1676,10 @@ void transport_generic_request_failure(struct se_cmd *cmd,
 		(cmd->transport_state & CMD_T_STOP) != 0,
 		(cmd->transport_state & CMD_T_SENT) != 0);
 
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	cmd->transport_state |= CMD_T_SENT_STATUS;
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
 	/*
 	 * For SAM Task Attribute emulation for failed struct se_cmd
 	 */
@@ -1951,6 +1961,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
 static void transport_complete_qf(struct se_cmd *cmd)
 {
 	int ret = 0;
+	unsigned long flags;
 
 	transport_complete_task_attr(cmd);
 
@@ -1986,6 +1997,10 @@ out:
 	}
 	transport_lun_remove_cmd(cmd);
 	transport_cmd_check_stop_to_fabric(cmd);
+
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	cmd->transport_state |= CMD_T_SENT_STATUS;
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 }
 
 static void transport_handle_queue_full(
@@ -2032,6 +2047,7 @@ static void target_complete_ok_work(struct work_struct *work)
 {
 	struct se_cmd *cmd = container_of(work, struct se_cmd, work);
 	int ret;
+	unsigned long flags;
 
 	/*
 	 * Check if we need to move delayed/dormant tasks from cmds on the
@@ -2060,6 +2076,10 @@ static void target_complete_ok_work(struct work_struct *work)
 
 		transport_lun_remove_cmd(cmd);
 		transport_cmd_check_stop_to_fabric(cmd);
+
+		spin_lock_irqsave(&cmd->t_state_lock, flags);
+		cmd->transport_state |= CMD_T_SENT_STATUS;
+		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 		return;
 	}
 	/*
@@ -2086,6 +2106,11 @@ static void target_complete_ok_work(struct work_struct *work)
 
 			transport_lun_remove_cmd(cmd);
 			transport_cmd_check_stop_to_fabric(cmd);
+
+			spin_lock_irqsave(&cmd->t_state_lock, flags);
+			cmd->transport_state |= CMD_T_SENT_STATUS;
+			spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
 			return;
 		}
 	}
@@ -2136,6 +2161,7 @@ queue_rsp:
 		ret = cmd->se_tfo->queue_status(cmd);
 		if (ret == -EAGAIN || ret == -ENOMEM)
 			goto queue_full;
+
 		break;
 	default:
 		break;
@@ -2143,6 +2169,10 @@ queue_rsp:
 
 	transport_lun_remove_cmd(cmd);
 	transport_cmd_check_stop_to_fabric(cmd);
+
+	spin_lock_irqsave(&cmd->t_state_lock, flags);
+	cmd->transport_state |= CMD_T_SENT_STATUS;
+	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 	return;
 
 queue_full:
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index aabf0ac..efccd71 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -490,6 +490,7 @@ struct se_cmd {
 #define CMD_T_DEV_ACTIVE	(1 << 7)
 #define CMD_T_REQUEST_STOP	(1 << 8)
 #define CMD_T_BUSY		(1 << 9)
+#define CMD_T_SENT_STATUS (1 << 10)
 	spinlock_t		t_state_lock;
 	struct kref		cmd_kref;
 	struct completion	t_transport_stop_comp;
-- 
1.7.7

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

* [PATCH 13/20] qla2xxx: Remove dependency on hardware_lock to reduce lock contention.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (11 preceding siblings ...)
  2015-12-08  0:48 ` [PATCH 12/20] target/tmr: LUN reset cause cmd premature free Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 14/20] qla2xxx: Add irq affinity notification Himanshu Madhani
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

Sessions management (add, deleted, modify) currently are serialized
through the hardware_lock.  Hardware_lock is a high traffic lock.
This lock is accessed by both the transmit & receive sides.

Sessions management is now moved off to another lock call sess_lock.
This is done to reduce lock contention and increase traffic throughput.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_def.h     |    1 +
 drivers/scsi/qla2xxx/qla_os.c      |    1 +
 drivers/scsi/qla2xxx/qla_target.c  |  131 ++++++++++++++++++++++++------------
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   28 ++++----
 4 files changed, 105 insertions(+), 56 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 46abba8..7c6369b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2929,6 +2929,7 @@ struct qlt_hw_data {
 	uint32_t num_qfull_cmds_dropped;
 	spinlock_t q_full_lock;
 	uint32_t leak_exchg_thresh_hold;
+	spinlock_t sess_lock;
 };
 
 #define MAX_QFULL_CMDS_ALLOC	8192
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index eb47272..8b45642 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2336,6 +2336,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	ha->tgt.enable_class_2 = ql2xenableclass2;
 	INIT_LIST_HEAD(&ha->tgt.q_full_list);
 	spin_lock_init(&ha->tgt.q_full_lock);
+	spin_lock_init(&ha->tgt.sess_lock);
 
 	/* Clear our data area */
 	ha->bars = bars;
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 5fca846..d4b7e25 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -635,7 +635,7 @@ static void qlt_free_session_done(struct work_struct *work)
 		wake_up_all(&tgt->waitQ);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 void qlt_unreg_sess(struct qla_tgt_sess *sess)
 {
 	struct scsi_qla_host *vha = sess->vha;
@@ -651,7 +651,7 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess)
 }
 EXPORT_SYMBOL(qlt_unreg_sess);
 
-/* ha->hardware_lock supposed to be held on entry */
+
 static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 {
 	struct qla_hw_data *ha = vha->hw;
@@ -661,12 +661,15 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 	int res = 0;
 	struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb;
 	struct atio_from_isp *a = (struct atio_from_isp *)iocb;
+	unsigned long flags;
 
 	loop_id = le16_to_cpu(n->u.isp24.nport_handle);
 	if (loop_id == 0xFFFF) {
 		/* Global event */
 		atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 		qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 #if 0 /* FIXME: do we need to choose a session here? */
 		if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
 			sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
@@ -693,7 +696,9 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 			sess = NULL;
 #endif
 	} else {
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 		sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	}
 
 	ql_dbg(ql_dbg_tgt, vha, 0xe000,
@@ -715,7 +720,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 	    iocb, QLA24XX_MGMT_SEND_NACK);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
 	bool immediate)
 {
@@ -759,7 +764,7 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
 		    sess->expires - jiffies);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_clear_tgt_db(struct qla_tgt *tgt)
 {
 	struct qla_tgt_sess *sess;
@@ -819,7 +824,7 @@ out_free_id_list:
 	return res;
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_undelete_sess(struct qla_tgt_sess *sess)
 {
 	BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
@@ -837,7 +842,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
 	struct qla_tgt_sess *sess;
 	unsigned long flags, elapsed;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	while (!list_empty(&tgt->del_sess_list)) {
 		sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
 		    del_list_entry);
@@ -858,7 +863,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 /*
@@ -876,7 +881,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 	unsigned char be_sid[3];
 
 	/* Check to avoid double sessions */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	list_for_each_entry(sess, &vha->vha_tgt.qla_tgt->sess_list,
 				sess_list_entry) {
 		if (!memcmp(sess->port_name, fcport->port_name, WWN_SIZE)) {
@@ -891,7 +896,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 
 			/* Cannot undelete at this point */
 			if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
-				spin_unlock_irqrestore(&ha->hardware_lock,
+				spin_unlock_irqrestore(&ha->tgt.sess_lock,
 				    flags);
 				return NULL;
 			}
@@ -908,12 +913,12 @@ static struct qla_tgt_sess *qlt_create_sess(
 
 			qlt_do_generation_tick(vha, &sess->generation);
 
-			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+			spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 			return sess;
 		}
 	}
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
 	if (!sess) {
@@ -958,7 +963,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 	}
 	/*
 	 * Take an extra reference to ->sess_kref here to handle qla_tgt_sess
-	 * access across ->hardware_lock reaquire.
+	 * access across ->tgt.sess_lock reaquire.
 	 */
 	kref_get(&sess->se_sess->sess_kref);
 
@@ -966,11 +971,11 @@ static struct qla_tgt_sess *qlt_create_sess(
 	BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name));
 	memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
 	vha->vha_tgt.qla_tgt->sess_count++;
 	qlt_do_generation_tick(vha, &sess->generation);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
 	    "qla_target(%d): %ssession for wwn %8phC (loop_id %d, "
@@ -1001,23 +1006,23 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
 	if (qla_ini_mode_enabled(vha))
 		return;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	if (tgt->tgt_stop) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 		return;
 	}
 	sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
 	if (!sess) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 		mutex_lock(&vha->vha_tgt.tgt_mutex);
 		sess = qlt_create_sess(vha, fcport, false);
 		mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	} else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
 		/* Point of no return */
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 		return;
 	} else {
 		kref_get(&sess->se_sess->sess_kref);
@@ -1046,7 +1051,7 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
 		sess->local = 0;
 	}
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 /*
@@ -1058,6 +1063,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
 {
 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 	struct qla_tgt_sess *sess;
+	unsigned long flags;
 
 	if (!vha->hw->tgt.tgt_ops)
 		return;
@@ -1065,11 +1071,14 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
 	if (!tgt)
 		return;
 
+	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
 	if (tgt->tgt_stop) {
+		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 		return;
 	}
 	sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
 	if (!sess) {
+		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 		return;
 	}
 
@@ -1086,6 +1095,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
 
 	sess->local = 1;
 	qlt_schedule_sess_for_deletion(sess, false);
+	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 }
 
 static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -1143,10 +1153,10 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
 	 * Lock is needed, because we still can get an incoming packet.
 	 */
 	mutex_lock(&vha->vha_tgt.tgt_mutex);
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	tgt->tgt_stop = 1;
 	qlt_clear_tgt_db(tgt);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	mutex_unlock(&vha->vha_tgt.tgt_mutex);
 	mutex_unlock(&qla_tgt_mutex);
 
@@ -1594,6 +1604,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
 	uint32_t tag = abts->exchange_addr_to_abort;
 	uint8_t s_id[3];
 	int rc;
+	unsigned long flags;
 
 	if (le32_to_cpu(abts->fcp_hdr_le.parameter) & ABTS_PARAM_ABORT_SEQ) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053,
@@ -1621,6 +1632,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
 	s_id[1] = abts->fcp_hdr_le.s_id[1];
 	s_id[2] = abts->fcp_hdr_le.s_id[0];
 
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
 	if (!sess) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012,
@@ -1628,12 +1640,17 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
 		    vha->vp_idx);
 		rc = qlt_sched_sess_work(vha->vha_tgt.qla_tgt,
 		    QLA_TGT_SESS_WORK_ABORT, abts, sizeof(*abts));
+
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 		if (rc != 0) {
 			qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED,
 			    false);
 		}
 		return;
 	}
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 
 	if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
 		qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false);
@@ -3788,9 +3805,9 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
 	/*
 	 * Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
 	 */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	return;
 
 out_term:
@@ -3805,8 +3822,11 @@ out_term:
 
 	qlt_decr_num_pend_cmds(vha);
 	percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
-	ha->tgt.tgt_ops->put_sess(sess);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+	ha->tgt.tgt_ops->put_sess(sess);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 static void qlt_do_work(struct work_struct *work)
@@ -4114,13 +4134,18 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb)
 	struct qla_tgt_sess *sess;
 	uint32_t lun, unpacked_lun;
 	int fn;
+	unsigned long flags;
 
 	tgt = vha->vha_tgt.qla_tgt;
 
 	lun = a->u.isp24.fcp_cmnd.lun;
 	fn = a->u.isp24.fcp_cmnd.task_mgmt_flags;
+
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
 	    a->u.isp24.fcp_hdr.s_id);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 	unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
 
 	if (!sess) {
@@ -4184,10 +4209,14 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
 	struct qla_hw_data *ha = vha->hw;
 	struct qla_tgt_sess *sess;
 	int loop_id;
+	unsigned long flags;
 
 	loop_id = GET_TARGET_ID(ha, (struct atio_from_isp *)iocb);
 
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
 	if (sess == NULL) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025,
 		    "qla_target(%d): task abort for unexisting "
@@ -4334,6 +4363,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 	uint16_t wd3_lo;
 	int res = 0;
 	qlt_plogi_ack_t *pla;
+	unsigned long flags;
 
 	wwn = wwn_to_u64(iocb->u.isp24.port_name);
 
@@ -4357,9 +4387,12 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 		/* Mark all stale commands in qla_tgt_wq for deletion */
 		abort_cmds_for_s_id(vha, &port_id);
 
-		if (wwn)
+		if (wwn) {
+			spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
 			sess = qlt_find_sess_invalidate_other(tgt, wwn,
 			    port_id, loop_id, &conflict_sess);
+			spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+		}
 
 		if (IS_SW_RESV_ADDR(port_id) || (!sess && !conflict_sess)) {
 			res = 1;
@@ -4410,9 +4443,12 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
 	case ELS_PRLI:
 		wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
 
-		if (wwn)
+		if (wwn) {
+			spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
 			sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
 			    loop_id, &conflict_sess);
+			spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+		}
 
 		if (conflict_sess) {
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09b,
@@ -5091,9 +5127,12 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
 	struct qla_hw_data *ha = vha->hw;
 	request_t *pkt;
 	struct qla_tgt_sess *sess = NULL;
+	unsigned long flags;
 
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
 	    atio->u.isp24.fcp_hdr.s_id);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	if (!sess) {
 		qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 		return 0;
@@ -5794,15 +5833,15 @@ static void qlt_abort_work(struct qla_tgt *tgt,
 	struct scsi_qla_host *vha = tgt->vha;
 	struct qla_hw_data *ha = vha->hw;
 	struct qla_tgt_sess *sess = NULL;
-	unsigned long flags;
+	unsigned long flags = 0, flags2 = 0;
 	uint32_t be_s_id;
 	uint8_t s_id[3];
 	int rc;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
 
 	if (tgt->tgt_stop)
-		goto out_term;
+		goto out_term2;
 
 	s_id[0] = prm->abts.fcp_hdr_le.s_id[2];
 	s_id[1] = prm->abts.fcp_hdr_le.s_id[1];
@@ -5811,39 +5850,47 @@ static void qlt_abort_work(struct qla_tgt *tgt,
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
 	    (unsigned char *)&be_s_id);
 	if (!sess) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 
 		sess = qlt_make_local_sess(vha, s_id);
 		/* sess has got an extra creation ref */
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
 		if (!sess)
-			goto out_term;
+			goto out_term2;
 	} else {
 		if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
 			sess = NULL;
-			goto out_term;
+			goto out_term2;
 		}
 
 		kref_get(&sess->se_sess->sess_kref);
 	}
 
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
 	if (tgt->tgt_stop)
 		goto out_term;
 
 	rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
 	if (rc != 0)
 		goto out_term;
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 	return;
 
+out_term2:
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
 out_term:
 	qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
 	if (sess)
 		ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 }
 
 static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -5860,7 +5907,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
 	int fn;
 	void *iocb;
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 
 	if (tgt->tgt_stop)
 		goto out_term;
@@ -5868,12 +5915,12 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
 	s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id;
 	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
 	if (!sess) {
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
 		sess = qlt_make_local_sess(vha, s_id);
 		/* sess has got an extra creation ref */
 
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+		spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 		if (!sess)
 			goto out_term;
 	} else {
@@ -5895,14 +5942,14 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
 		goto out_term;
 
 	ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	return;
 
 out_term:
-	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
+	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 0, 0);
 	if (sess)
 		ha->tgt.tgt_ops->put_sess(sess);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 static void qlt_sess_work_fn(struct work_struct *work)
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 2e9c194..833dec2 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -349,9 +349,9 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess)
 	BUG_ON(!sess);
 	vha = sess->vha;
 
-	spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
 	target_sess_cmd_list_set_waiting(se_sess);
-	spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
 	return 1;
 }
@@ -365,9 +365,9 @@ static void tcm_qla2xxx_close_session(struct se_session *se_sess)
 	BUG_ON(!sess);
 	vha = sess->vha;
 
-	spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
 	qlt_unreg_sess(sess);
-	spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 }
 
 static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
@@ -735,7 +735,7 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
 			struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *);
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess)
 {
@@ -789,13 +789,13 @@ static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
 	if (!sess)
 		return;
 
-	assert_spin_locked(&sess->vha->hw->hardware_lock);
+	assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
 	kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
 }
 
 static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess)
 {
-	assert_spin_locked(&sess->vha->hw->hardware_lock);
+	assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
 	target_sess_cmd_list_set_waiting(sess->se_sess);
 }
 
@@ -1169,7 +1169,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
 	scsi_qla_host_t *vha,
@@ -1208,7 +1208,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static void tcm_qla2xxx_set_sess_by_s_id(
 	struct tcm_qla2xxx_lport *lport,
@@ -1274,7 +1274,7 @@ static void tcm_qla2xxx_set_sess_by_s_id(
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
 	scsi_qla_host_t *vha,
@@ -1313,7 +1313,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
 }
 
 /*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
  */
 static void tcm_qla2xxx_set_sess_by_loop_id(
 	struct tcm_qla2xxx_lport *lport,
@@ -1377,7 +1377,7 @@ static void tcm_qla2xxx_set_sess_by_loop_id(
 }
 
 /*
- * Should always be called with qla_hw_data->hardware_lock held.
+ * Should always be called with qla_hw_data->tgt.sess_lock held.
  */
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *lport,
 		struct tcm_qla2xxx_nacl *nacl, struct qla_tgt_sess *sess)
@@ -1493,12 +1493,12 @@ static int tcm_qla2xxx_check_initiator_node_acl(
 	 * And now setup the new se_nacl and session pointers into our HW lport
 	 * mappings for fabric S_ID and LOOP_ID.
 	 */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 	tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess,
 			qla_tgt_sess, s_id);
 	tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, se_sess,
 			qla_tgt_sess, loop_id);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 	/*
 	 * Finally register the new FC Nexus with TCM
 	 */
-- 
1.7.7

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

* [PATCH 14/20] qla2xxx: Add irq affinity notification
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (12 preceding siblings ...)
  2015-12-08  0:49 ` [PATCH 13/20] qla2xxx: Remove dependency on hardware_lock to reduce lock contention Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 15/20] qla2xxx: Add selective command queuing Himanshu Madhani
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

Register to receive notification of when irq setting change
occured.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_def.h    |    6 +++
 drivers/scsi/qla2xxx/qla_isr.c    |   76 ++++++++++++++++++++++++++++++++++++-
 drivers/scsi/qla2xxx/qla_target.c |   11 +++++
 3 files changed, 92 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 7c6369b..9165732 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2714,11 +2714,16 @@ struct isp_operations {
 
 struct scsi_qla_host;
 
+
+#define QLA83XX_RSPQ_MSIX_ENTRY_NUMBER 1 /* refer to qla83xx_msix_entries */
+
 struct qla_msix_entry {
 	int have_irq;
 	uint32_t vector;
 	uint16_t entry;
 	struct rsp_que *rsp;
+	struct irq_affinity_notify irq_notify;
+	int cpuid;
 };
 
 #define	WATCH_INTERVAL		1       /* number of seconds */
@@ -2930,6 +2935,7 @@ struct qlt_hw_data {
 	spinlock_t q_full_lock;
 	uint32_t leak_exchg_thresh_hold;
 	spinlock_t sess_lock;
+	int rspq_vector_cpuid;
 };
 
 #define MAX_QFULL_CMDS_ALLOC	8192
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ea7e8e8..e879802d 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -18,6 +18,10 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
 static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
 static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
 	sts_entry_t *);
+static void qla_irq_affinity_notify(struct irq_affinity_notify *,
+    const cpumask_t *);
+static void qla_irq_affinity_release(struct kref *);
+
 
 /**
  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -2548,6 +2552,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 	if (!vha->flags.online)
 		return;
 
+	if (rsp->msix->cpuid != smp_processor_id()) {
+		/* if kernel does not notify qla of IRQ's CPU change,
+		 * then set it here.
+		 */
+		rsp->msix->cpuid = smp_processor_id();
+		ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
+	}
+
 	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
 		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
 
@@ -2979,8 +2991,11 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
 
 	for (i = 0; i < ha->msix_count; i++) {
 		qentry = &ha->msix_entries[i];
-		if (qentry->have_irq)
+		if (qentry->have_irq) {
+			/* un-register irq cpu affinity notification */
+			irq_set_affinity_notifier(qentry->vector, NULL);
 			free_irq(qentry->vector, qentry->rsp);
+		}
 	}
 	pci_disable_msix(ha->pdev);
 	kfree(ha->msix_entries);
@@ -3043,6 +3058,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
 		qentry->entry = entries[i].entry;
 		qentry->have_irq = 0;
 		qentry->rsp = NULL;
+		qentry->irq_notify.notify  = qla_irq_affinity_notify;
+		qentry->irq_notify.release = qla_irq_affinity_release;
+		qentry->cpuid = -1;
 	}
 
 	/* Enable MSI-X vectors for the base queue */
@@ -3061,6 +3079,18 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
 		qentry->have_irq = 1;
 		qentry->rsp = rsp;
 		rsp->msix = qentry;
+
+		/* Register for CPU affinity notification. */
+		irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
+
+		/* Schedule work (ie. trigger a notification) to read cpu
+		 * mask for this specific irq.
+		 * kref_get is required because
+		* irq_affinity_notify() will do
+		* kref_put().
+		*/
+		kref_get(&qentry->irq_notify.kref);
+		schedule_work(&qentry->irq_notify.work);
 	}
 
 	/*
@@ -3240,3 +3270,47 @@ int qla25xx_request_irq(struct rsp_que *rsp)
 	msix->rsp = rsp;
 	return ret;
 }
+
+
+/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
+static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
+	const cpumask_t *mask)
+{
+	struct qla_msix_entry *e =
+		container_of(notify, struct qla_msix_entry, irq_notify);
+	struct qla_hw_data *ha;
+	struct scsi_qla_host *base_vha;
+
+	/* user is recommended to set mask to just 1 cpu */
+	e->cpuid = cpumask_first(mask);
+
+	ha = e->rsp->hw;
+	base_vha = pci_get_drvdata(ha->pdev);
+
+	ql_dbg(ql_dbg_init, base_vha, 0xffff,
+		"%s: host %ld : vector %d cpu %d \n", __func__,
+		base_vha->host_no, e->vector, e->cpuid);
+
+	if (e->have_irq) {
+		if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
+		    (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) {
+			ha->tgt.rspq_vector_cpuid = e->cpuid;
+			ql_dbg(ql_dbg_init, base_vha, 0xffff,
+			    "%s: host%ld: rspq vector %d cpu %d  runtime change\n",
+			    __func__, base_vha->host_no, e->vector, e->cpuid);
+		}
+	}
+}
+
+void qla_irq_affinity_release(struct kref *ref)
+{
+	struct irq_affinity_notify *notify =
+		container_of(ref, struct irq_affinity_notify, kref);
+	struct qla_msix_entry *e =
+		container_of(notify, struct qla_msix_entry, irq_notify);
+	struct scsi_qla_host *base_vha = pci_get_drvdata(e->rsp->hw->pdev);
+
+	ql_dbg(ql_dbg_init, base_vha, 0xffff,
+	    "%s: host%ld: vector %d cpu %d \n", __func__,
+	    base_vha->host_no, e->vector, e->cpuid);
+}
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index d4b7e25..dc6ac4e 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -6272,6 +6272,17 @@ qlt_enable_vha(struct scsi_qla_host *vha)
 		qla24xx_disable_vp(vha);
 		qla24xx_enable_vp(vha);
 	} else {
+		if (ha->msix_entries) {
+			ql_dbg(ql_dbg_tgt, vha, 0xffff,
+			    "%s: host%ld : vector %d cpu %d\n",
+			    __func__, vha->host_no,
+			    ha->msix_entries[QLA83XX_RSPQ_MSIX_ENTRY_NUMBER].vector,
+			    ha->msix_entries[QLA83XX_RSPQ_MSIX_ENTRY_NUMBER].cpuid);
+
+			ha->tgt.rspq_vector_cpuid =
+			ha->msix_entries[QLA83XX_RSPQ_MSIX_ENTRY_NUMBER].cpuid;
+		}
+
 		set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
 		qla2xxx_wake_dpc(base_vha);
 		qla2x00_wait_for_hba_online(base_vha);
-- 
1.7.7

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

* [PATCH 15/20] qla2xxx: Add selective command queuing
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (13 preceding siblings ...)
  2015-12-08  0:49 ` [PATCH 14/20] qla2xxx: Add irq affinity notification Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 16/20] qla2xxx: Move atioq to a different lock to reduce lock contention Himanshu Madhani
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

queue work element to specific process lessen cache miss

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_isr.c         |    2 +-
 drivers/scsi/qla2xxx/qla_target.c      |   13 ++++++++++++-
 drivers/scsi/qla2xxx/tcm_qla2xxx.c     |    4 ++--
 drivers/target/target_core_transport.c |    5 ++++-
 include/target/target_core_base.h      |    1 +
 5 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index e879802d..26fa4d8 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -3302,7 +3302,7 @@ static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
 	}
 }
 
-void qla_irq_affinity_release(struct kref *ref)
+static void qla_irq_affinity_release(struct kref *ref)
 {
 	struct irq_affinity_notify *notify =
 		container_of(ref, struct irq_affinity_notify, kref);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index dc6ac4e..b33c018 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -4004,13 +4004,24 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 
 	cmd->cmd_in_wq = 1;
 	cmd->cmd_flags |= BIT_0;
+	cmd->se_cmd.cpuid = -1;
 
 	spin_lock(&vha->cmd_list_lock);
 	list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
 	spin_unlock(&vha->cmd_list_lock);
 
 	INIT_WORK(&cmd->work, qlt_do_work);
-	queue_work(qla_tgt_wq, &cmd->work);
+	if (ha->msix_count) {
+		cmd->se_cmd.cpuid = ha->tgt.rspq_vector_cpuid;
+		if (cmd->atio.u.isp24.fcp_cmnd.rddata)
+			queue_work_on(smp_processor_id(), qla_tgt_wq,
+			    &cmd->work);
+		else
+			queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq,
+			    &cmd->work);
+	} else {
+		queue_work(qla_tgt_wq, &cmd->work);
+	}
 	return 0;
 
 }
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 833dec2..d7a34d1 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -303,7 +303,7 @@ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
 	cmd->cmd_flags |= BIT_20;
 
 	INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
-	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+	queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
 }
 
 /*
@@ -535,7 +535,7 @@ static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
 	cmd->cmd_flags |= BIT_10;
 	cmd->cmd_in_wq = 1;
 	INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work);
-	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+	queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
 }
 
 static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index cdd18bf..a37db6d 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -720,7 +720,10 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
 	cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
 	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-	queue_work(target_completion_wq, &cmd->work);
+	if (cmd->cpuid == -1)
+		queue_work(target_completion_wq, &cmd->work);
+	else
+		queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
 }
 EXPORT_SYMBOL(target_complete_cmd);
 
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index efccd71..ce26a3a 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -527,6 +527,7 @@ struct se_cmd {
 	unsigned int		t_prot_nents;
 	sense_reason_t		pi_err;
 	sector_t		bad_sector;
+	int cpuid;
 };
 
 struct se_ua {
-- 
1.7.7


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

* [PATCH 16/20] qla2xxx: Move atioq to a different lock to reduce lock contention
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (14 preceding siblings ...)
  2015-12-08  0:49 ` [PATCH 15/20] qla2xxx: Add selective command queuing Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 17/20] qla2xxx: Disable ZIO at start time Himanshu Madhani
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

99% of the time the ATIOQ has SCSI command.  The other 1% of time
is something else.  Most of the time this interrupt does not need
to hold the hardware_lock.  We're moving the ATIO interrupt thread
to a different lock to reduce lock contention.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_def.h    |    1 +
 drivers/scsi/qla2xxx/qla_gbl.h    |    1 +
 drivers/scsi/qla2xxx/qla_init.c   |    6 ++-
 drivers/scsi/qla2xxx/qla_isr.c    |   44 +++++++++++++----
 drivers/scsi/qla2xxx/qla_os.c     |    2 +
 drivers/scsi/qla2xxx/qla_target.c |   97 +++++++++++++++++++++++++++++++------
 drivers/scsi/qla2xxx/qla_target.h |    4 +-
 7 files changed, 127 insertions(+), 28 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 9165732..0ddb2de 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2936,6 +2936,7 @@ struct qlt_hw_data {
 	uint32_t leak_exchg_thresh_hold;
 	spinlock_t sess_lock;
 	int rspq_vector_cpuid;
+	spinlock_t atio_lock ____cacheline_aligned;
 };
 
 #define MAX_QFULL_CMDS_ALLOC	8192
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 2e91966..5496e0a 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -779,5 +779,6 @@ extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
 extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
 extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha,
     dma_addr_t phys_addr);
+extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *);
 
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 35d1ea8..993dd25 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4919,7 +4919,7 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 	struct rsp_que *rsp = ha->rsp_q_map[0];
-	unsigned long flags;
+	unsigned long flags, flags2;
 
 	/* If firmware needs to be loaded */
 	if (qla2x00_isp_firmware(vha)) {
@@ -4948,8 +4948,10 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
 			 * while we weren't online.
 			 */
 			spin_lock_irqsave(&ha->hardware_lock, flags);
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
 			if (qla_tgt_mode_enabled(vha))
-				qlt_24xx_process_atio_queue(vha);
+				qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
 			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 			set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 26fa4d8..72d1cdc 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2605,8 +2605,14 @@ process_err:
 			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
 			break;
 		case ABTS_RECV_24XX:
-			/* ensure that the ATIO queue is empty */
-			qlt_24xx_process_atio_queue(vha);
+			if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+				/* ensure that the ATIO queue is empty */
+				qlt_handle_abts_recv(vha, (response_t *)pkt);
+				break;
+			} else {
+				/* drop through */
+				qlt_24xx_process_atio_queue(vha, 1);
+			}
 		case ABTS_RESP_24XX:
 		case CTIO_TYPE7:
 		case NOTIFY_ACK_TYPE:
@@ -2773,13 +2779,22 @@ qla24xx_intr_handler(int irq, void *dev_id)
 		case INTR_RSP_QUE_UPDATE_83XX:
 			qla24xx_process_response_queue(vha, rsp);
 			break;
-		case INTR_ATIO_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		case INTR_ATIO_QUE_UPDATE:{
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
 			break;
-		case INTR_ATIO_RSP_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		}
+		case INTR_ATIO_RSP_QUE_UPDATE: {
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
 			qla24xx_process_response_queue(vha, rsp);
 			break;
+		}
 		default:
 			ql_dbg(ql_dbg_async, vha, 0x504f,
 			    "Unrecognized interrupt type (%d).\n", stat * 0xff);
@@ -2938,13 +2953,22 @@ qla24xx_msix_default(int irq, void *dev_id)
 		case INTR_RSP_QUE_UPDATE_83XX:
 			qla24xx_process_response_queue(vha, rsp);
 			break;
-		case INTR_ATIO_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		case INTR_ATIO_QUE_UPDATE:{
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
 			break;
-		case INTR_ATIO_RSP_QUE_UPDATE:
-			qlt_24xx_process_atio_queue(vha);
+		}
+		case INTR_ATIO_RSP_QUE_UPDATE: {
+			unsigned long flags2;
+			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+			qlt_24xx_process_atio_queue(vha, 1);
+			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
 			qla24xx_process_response_queue(vha, rsp);
 			break;
+		}
 		default:
 			ql_dbg(ql_dbg_async, vha, 0x5051,
 			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 8b45642..b350905 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2337,6 +2337,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	INIT_LIST_HEAD(&ha->tgt.q_full_list);
 	spin_lock_init(&ha->tgt.q_full_lock);
 	spin_lock_init(&ha->tgt.sess_lock);
+	spin_lock_init(&ha->tgt.atio_lock);
+
 
 	/* Clear our data area */
 	ha->bars = bars;
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index b33c018..69f88d3 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -100,7 +100,7 @@ enum fcp_resp_rsp_codes {
  */
 /* Predefs for callbacks handed to qla2xxx LLD */
 static void qlt_24xx_atio_pkt(struct scsi_qla_host *ha,
-	struct atio_from_isp *pkt);
+	struct atio_from_isp *pkt, uint8_t);
 static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
 static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
 	int fn, void *iocb, int flags);
@@ -230,7 +230,7 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha)
 }
 
 static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
-	struct atio_from_isp *atio)
+	struct atio_from_isp *atio, uint8_t ha_locked)
 {
 	ql_dbg(ql_dbg_tgt, vha, 0xe072,
 		"%s: qla_target(%d): type %x ox_id %04x\n",
@@ -251,7 +251,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
 			    atio->u.isp24.fcp_hdr.d_id[2]);
 			break;
 		}
-		qlt_24xx_atio_pkt(host, atio);
+		qlt_24xx_atio_pkt(host, atio, ha_locked);
 		break;
 	}
 
@@ -274,7 +274,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
 				break;
 			}
 		}
-		qlt_24xx_atio_pkt(host, atio);
+		qlt_24xx_atio_pkt(host, atio, ha_locked);
 		break;
 	}
 
@@ -1209,7 +1209,7 @@ void qlt_stop_phase2(struct qla_tgt *tgt)
 
 	mutex_lock(&vha->vha_tgt.tgt_mutex);
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	while (tgt->irq_cmd_count != 0) {
+	while ((tgt->irq_cmd_count != 0) || (tgt->atio_irq_cmd_count != 0)) {
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		udelay(2);
 		spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -5372,11 +5372,12 @@ qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha,
 /* ha->hardware_lock supposed to be held on entry */
 /* called via callback from qla2xxx */
 static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
-	struct atio_from_isp *atio)
+	struct atio_from_isp *atio, uint8_t ha_locked)
 {
 	struct qla_hw_data *ha = vha->hw;
 	struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 	int rc;
+	unsigned long flags;
 
 	if (unlikely(tgt == NULL)) {
 		ql_dbg(ql_dbg_io, vha, 0x3064,
@@ -5388,7 +5389,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 	 * Otherwise, some commands can stuck.
 	 */
 
-	tgt->irq_cmd_count++;
+	tgt->atio_irq_cmd_count++;
 
 	switch (atio->u.raw.entry_type) {
 	case ATIO_TYPE7:
@@ -5398,7 +5399,11 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 			    "qla_target(%d): ATIO_TYPE7 "
 			    "received with UNKNOWN exchange address, "
 			    "sending QUEUE_FULL\n", vha->vp_idx);
+			if (!ha_locked)
+				spin_lock_irqsave(&ha->hardware_lock, flags);
 			qlt_send_busy(vha, atio, SAM_STAT_TASK_SET_FULL);
+			if (!ha_locked)
+				spin_unlock_irqrestore(&ha->hardware_lock, flags);
 			break;
 		}
 
@@ -5407,7 +5412,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 		if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) {
 			rc = qlt_chk_qfull_thresh_hold(vha, atio);
 			if (rc != 0) {
-				tgt->irq_cmd_count--;
+				tgt->atio_irq_cmd_count--;
 				return;
 			}
 			rc = qlt_handle_cmd_for_atio(vha, atio);
@@ -5416,11 +5421,18 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 		}
 		if (unlikely(rc != 0)) {
 			if (rc == -ESRCH) {
+				if (!ha_locked)
+					spin_lock_irqsave(&ha->hardware_lock, flags);
+
 #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
 				qlt_send_busy(vha, atio, SAM_STAT_BUSY);
 #else
 				qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 #endif
+
+				if (!ha_locked)
+					spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
 			} else {
 				if (tgt->tgt_stop) {
 					ql_dbg(ql_dbg_tgt, vha, 0xe059,
@@ -5432,7 +5444,13 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 					    "qla_target(%d): Unable to send "
 					    "command to target, sending BUSY "
 					    "status.\n", vha->vp_idx);
+					if (!ha_locked)
+						spin_lock_irqsave(
+						    &ha->hardware_lock, flags);
 					qlt_send_busy(vha, atio, SAM_STAT_BUSY);
+					if (!ha_locked)
+						spin_unlock_irqrestore(
+						    &ha->hardware_lock, flags);
 				}
 			}
 		}
@@ -5449,7 +5467,12 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 			break;
 		}
 		ql_dbg(ql_dbg_tgt, vha, 0xe02e, "%s", "IMMED_NOTIFY ATIO");
+
+		if (!ha_locked)
+			spin_lock_irqsave(&ha->hardware_lock, flags);
 		qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)atio);
+		if (!ha_locked)
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		break;
 	}
 
@@ -5460,7 +5483,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 		break;
 	}
 
-	tgt->irq_cmd_count--;
+	tgt->atio_irq_cmd_count--;
 }
 
 /* ha->hardware_lock supposed to be held on entry */
@@ -6405,7 +6428,7 @@ qlt_init_atio_q_entries(struct scsi_qla_host *vha)
  * @ha: SCSI driver HA context
  */
 void
-qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
+qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked)
 {
 	struct qla_hw_data *ha = vha->hw;
 	struct atio_from_isp *pkt;
@@ -6418,7 +6441,8 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
 		pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr;
 		cnt = pkt->u.raw.entry_count;
 
-		qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt);
+		qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt,
+		    ha_locked);
 
 		for (i = 0; i < cnt; i++) {
 			ha->tgt.atio_ring_index++;
@@ -6702,16 +6726,59 @@ qla83xx_msix_atio_q(int irq, void *dev_id)
 	ha = rsp->hw;
 	vha = pci_get_drvdata(ha->pdev);
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&ha->tgt.atio_lock, flags);
 
-	qlt_24xx_process_atio_queue(vha);
-	qla24xx_process_response_queue(vha, rsp);
+	qlt_24xx_process_atio_queue(vha, 0);
 
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
 
 	return IRQ_HANDLED;
 }
 
+static void
+qlt_handle_abts_recv_work(struct work_struct *work)
+{
+	struct qla_tgt_sess_op *op = container_of(work,
+		struct qla_tgt_sess_op, work);
+	scsi_qla_host_t *vha = op->vha;
+	struct qla_hw_data *ha = vha->hw;
+	unsigned long flags;
+
+	if (qla2x00_reset_active(vha) || (op->chip_reset != ha->chip_reset))
+		return;
+
+	spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+	qlt_24xx_process_atio_queue(vha, 0);
+	spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	qlt_response_pkt_all_vps(vha, (response_t *)&op->atio);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qlt_handle_abts_recv(struct scsi_qla_host *vha, response_t *pkt)
+{
+	struct qla_tgt_sess_op *op;
+
+	op = kzalloc(sizeof(*op), GFP_ATOMIC);
+
+	if (!op) {
+		/* do not reach for ATIO queue here.  This is best effort err
+		 * recovery at this point.
+		 */
+		qlt_response_pkt_all_vps(vha, pkt);
+		return;
+	}
+
+	memcpy(&op->atio, pkt, sizeof(*pkt));
+	op->vha = vha;
+	op->chip_reset = vha->hw->chip_reset;
+	INIT_WORK(&op->work, qlt_handle_abts_recv_work);
+	queue_work(qla_tgt_wq, &op->work);
+	return;
+}
+
 int
 qlt_mem_alloc(struct qla_hw_data *ha)
 {
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index a079c237..22a6a76 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -835,6 +835,7 @@ struct qla_tgt {
 	 * HW lock.
 	 */
 	int irq_cmd_count;
+	int atio_irq_cmd_count;
 
 	int datasegs_per_cmd, datasegs_per_cont, sg_tablesize;
 
@@ -883,6 +884,7 @@ struct qla_tgt {
 
 struct qla_tgt_sess_op {
 	struct scsi_qla_host *vha;
+	uint32_t chip_reset;
 	struct atio_from_isp atio;
 	struct work_struct work;
 	struct list_head cmd_list;
@@ -1164,7 +1166,7 @@ extern void qlt_enable_vha(struct scsi_qla_host *);
 extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
 extern void qlt_rff_id(struct scsi_qla_host *, struct ct_sns_req *);
 extern void qlt_init_atio_q_entries(struct scsi_qla_host *);
-extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *);
+extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *, uint8_t);
 extern void qlt_24xx_config_rings(struct scsi_qla_host *);
 extern void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *,
 	struct nvram_24xx *);
-- 
1.7.7


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

* [PATCH 17/20] qla2xxx: Disable ZIO at start time.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (15 preceding siblings ...)
  2015-12-08  0:49 ` [PATCH 16/20] qla2xxx: Move atioq to a different lock to reduce lock contention Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 18/20] qla2xxx: Set all queues to 4k Himanshu Madhani
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_target.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 69f88d3..f8f2b8a 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -6563,10 +6563,21 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha,
 {
 	struct qla_hw_data *ha = vha->hw;
 
+	if (!QLA_TGT_MODE_ENABLED())
+		return;
+
 	if (ha->tgt.node_name_set) {
 		memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
 		icb->firmware_options_1 |= cpu_to_le32(BIT_14);
 	}
+
+	/* disable ZIO at start time. */
+	if (!vha->flags.init_done) {
+		uint32_t tmp;
+		tmp = le32_to_cpu(icb->firmware_options_2);
+		tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+		icb->firmware_options_2 = cpu_to_le32(tmp);
+	}
 }
 
 void
@@ -6657,6 +6668,15 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha,
 		memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
 		icb->firmware_options_1 |= cpu_to_le32(BIT_14);
 	}
+
+	/* disable ZIO at start time. */
+	if (!vha->flags.init_done) {
+		uint32_t tmp;
+		tmp = le32_to_cpu(icb->firmware_options_2);
+		tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+		icb->firmware_options_2 = cpu_to_le32(tmp);
+	}
+
 }
 
 void
-- 
1.7.7

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

* [PATCH 18/20] qla2xxx: Set all queues to 4k
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (16 preceding siblings ...)
  2015-12-08  0:49 ` [PATCH 17/20] qla2xxx: Disable ZIO at start time Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 19/20] qla2xxx: Add bulk send for atio & ctio completion paths Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 20/20] qla2xxx: Check for online flag instead of active reset when transmitting responses Himanshu Madhani
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

set ATIO/Request/Response Queues and Default number
of outstanding command to 4k.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_def.h |    3 ++-
 drivers/scsi/qla2xxx/qla_os.c  |    6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 0ddb2de..141a6ba 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -259,7 +259,7 @@
 #define LOOP_DOWN_TIME			255	/* 240 */
 #define	LOOP_DOWN_RESET			(LOOP_DOWN_TIME - 30)
 
-#define DEFAULT_OUTSTANDING_COMMANDS	1024
+#define DEFAULT_OUTSTANDING_COMMANDS	4096
 #define MIN_OUTSTANDING_COMMANDS	128
 
 /* ISP request and response entry counts (37-65535) */
@@ -267,6 +267,7 @@
 #define REQUEST_ENTRY_CNT_2200		2048	/* Number of request entries. */
 #define REQUEST_ENTRY_CNT_24XX		2048	/* Number of request entries. */
 #define REQUEST_ENTRY_CNT_83XX		8192	/* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_83XX		4096	/* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_2100		64	/* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_2300		512	/* Number of response entries.*/
 #define RESPONSE_ENTRY_CNT_MQ		128	/* Number of response entries.*/
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b350905..0fcc838 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2483,7 +2483,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
 		req_length = REQUEST_ENTRY_CNT_83XX;
-		rsp_length = RESPONSE_ENTRY_CNT_2300;
+		rsp_length = RESPONSE_ENTRY_CNT_83XX;
 		ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
 		ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
 		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -2513,8 +2513,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		ha->portnum = PCI_FUNC(ha->pdev->devfn);
 		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
-		req_length = REQUEST_ENTRY_CNT_24XX;
-		rsp_length = RESPONSE_ENTRY_CNT_2300;
+		req_length = REQUEST_ENTRY_CNT_83XX;
+		rsp_length = RESPONSE_ENTRY_CNT_83XX;
 		ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
 		ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
 		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
-- 
1.7.7

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

* [PATCH 19/20] qla2xxx: Add bulk send for atio & ctio completion paths.
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (17 preceding siblings ...)
  2015-12-08  0:49 ` [PATCH 18/20] qla2xxx: Set all queues to 4k Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  2015-12-08  0:49 ` [PATCH 20/20] qla2xxx: Check for online flag instead of active reset when transmitting responses Himanshu Madhani
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Quinn Tran <quinn.tran@qlogic.com>

At high traffic, the work queue can become a bottle neck.
Instead of putting each command on the work queue as 1 work
element, the fix would daisy chain a list of commands that came
from FW/interrupt under 1 work element to reduce lock contention.

Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_def.h     |    3 +
 drivers/scsi/qla2xxx/qla_isr.c     |    3 +
 drivers/scsi/qla2xxx/qla_target.c  |   65 ++++++++++++++++++++++++++-----
 drivers/scsi/qla2xxx/qla_target.h  |    2 +
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   75 +++++++++++++++++++++++++++++++++--
 5 files changed, 133 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 141a6ba..b731eef 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2937,6 +2937,9 @@ struct qlt_hw_data {
 	uint32_t leak_exchg_thresh_hold;
 	spinlock_t sess_lock;
 	int rspq_vector_cpuid;
+
+	void *ctio_for_bulk_process;
+	void *atio_for_bulk_process;
 	spinlock_t atio_lock ____cacheline_aligned;
 };
 
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 72d1cdc..d2bbcbb 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2646,6 +2646,9 @@ process_err:
 		WRT_REG_DWORD(&reg->rsp_q_out[0], rsp->ring_index);
 	} else
 		WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
+
+	if (ha->tgt.ctio_for_bulk_process)
+		vha->hw->tgt.tgt_ops->handle_bulk(vha);
 }
 
 static void
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index f8f2b8a..9cf812f 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3834,12 +3834,23 @@ static void qlt_do_work(struct work_struct *work)
 	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
 	scsi_qla_host_t *vha = cmd->vha;
 	unsigned long flags;
+	struct list_head h;
+	struct qla_tgt_cmd *c = NULL, *tc = NULL;
 
 	spin_lock_irqsave(&vha->cmd_list_lock, flags);
 	list_del(&cmd->cmd_list);
 	spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
 
+	INIT_LIST_HEAD(&h);
+	if (!list_empty(&cmd->bulk_process_list))
+		list_splice_init(&cmd->bulk_process_list, &h);
+
 	__qlt_do_work(cmd);
+
+	list_for_each_entry_safe(c, tc, &h, bulk_process_list) {
+		list_del_init(&c->bulk_process_list);
+		c->work.func(&c->work);
+	}
 }
 
 static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
@@ -3871,6 +3882,7 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
 	cmd->jiffies_at_alloc = get_jiffies_64();
 
 	cmd->reset_count = vha->hw->chip_reset;
+	INIT_LIST_HEAD(&cmd->bulk_process_list);
 
 	return cmd;
 }
@@ -3930,6 +3942,7 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
 		kfree(op);
 		return;
 	}
+
 	/*
 	 * __qlt_do_work() will call ha->tgt.tgt_ops->put_sess() to release
 	 * the extra reference taken above by qlt_make_local_sess()
@@ -3946,6 +3959,40 @@ out_term:
 
 }
 
+static void qlt_add_cmd_to_bulk_list(struct qla_tgt_cmd *cmd)
+{
+	struct qla_hw_data *ha = cmd->tgt->ha;
+	struct qla_tgt_cmd *hc = (struct qla_tgt_cmd *)
+		ha->tgt.atio_for_bulk_process;
+
+	if (IS_QLA27XX(ha) || IS_QLA83XX(ha))
+		/* We are running under atio_lock protection here. */
+		assert_spin_locked(&ha->tgt.atio_lock);
+	else
+		assert_spin_locked(&ha->hardware_lock);
+
+	if (hc)
+		list_add_tail(&cmd->bulk_process_list, &hc->bulk_process_list);
+	else
+		ha->tgt.atio_for_bulk_process = (void *)cmd;
+}
+
+static void qlt_send_atio_bulk(struct qla_hw_data *ha)
+{
+	struct qla_tgt_cmd *cmd =
+		(struct qla_tgt_cmd *)ha->tgt.atio_for_bulk_process;
+
+	if (IS_QLA27XX(ha) || IS_QLA83XX(ha))
+		/*We are running under atio_lock protection here */
+		assert_spin_locked(&ha->tgt.atio_lock);
+	else
+		assert_spin_locked(&ha->hardware_lock);
+
+	ha->tgt.atio_for_bulk_process = NULL;
+	queue_work_on(smp_processor_id(), qla_tgt_wq, &cmd->work);
+}
+
+
 /* ha->hardware_lock supposed to be held on entry */
 static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 	struct atio_from_isp *atio)
@@ -4011,17 +4058,11 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 	spin_unlock(&vha->cmd_list_lock);
 
 	INIT_WORK(&cmd->work, qlt_do_work);
-	if (ha->msix_count) {
+	if (ha->msix_count)
 		cmd->se_cmd.cpuid = ha->tgt.rspq_vector_cpuid;
-		if (cmd->atio.u.isp24.fcp_cmnd.rddata)
-			queue_work_on(smp_processor_id(), qla_tgt_wq,
-			    &cmd->work);
-		else
-			queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq,
-			    &cmd->work);
-	} else {
-		queue_work(qla_tgt_wq, &cmd->work);
-	}
+
+	qlt_add_cmd_to_bulk_list(cmd);
+
 	return 0;
 
 }
@@ -5256,6 +5297,7 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
 
 	qlt_incr_num_pend_cmds(vha);
 	INIT_LIST_HEAD(&cmd->cmd_list);
+	INIT_LIST_HEAD(&cmd->bulk_process_list);
 	memcpy(&cmd->atio, atio, sizeof(*atio));
 
 	cmd->tgt = vha->vha_tgt.qla_tgt;
@@ -6461,6 +6503,9 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked)
 	/* Adjust ring index */
 	WRT_REG_DWORD(ISP_ATIO_Q_OUT(vha), ha->tgt.atio_ring_index);
 	RD_REG_DWORD_RELAXED(ISP_ATIO_Q_OUT(vha));
+
+	if (ha->tgt.atio_for_bulk_process)
+		qlt_send_atio_bulk(ha);
 }
 
 void
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 22a6a76..66c3ede 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -740,6 +740,7 @@ struct qla_tgt_func_tmpl {
 	void (*clear_nacl_from_fcport_map)(struct qla_tgt_sess *);
 	void (*put_sess)(struct qla_tgt_sess *);
 	void (*shutdown_sess)(struct qla_tgt_sess *);
+	void (*handle_bulk)(struct scsi_qla_host *);
 };
 
 int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
@@ -1007,6 +1008,7 @@ struct qla_tgt_cmd {
 	struct qla_tgt *tgt;	/* to save extra sess dereferences */
 	struct scsi_qla_host *vha;
 	struct list_head cmd_list;
+	struct list_head bulk_process_list;
 
 	struct atio_from_isp atio;
 	/* t10dif */
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index d7a34d1..2594341 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -279,6 +279,12 @@ static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd)
 static void tcm_qla2xxx_complete_free(struct work_struct *work)
 {
 	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+	struct list_head h;
+	struct qla_tgt_cmd *c = NULL, *tc = NULL;
+
+	INIT_LIST_HEAD(&h);
+	if (!list_empty(&cmd->bulk_process_list))
+		list_splice_init(&cmd->bulk_process_list, &h);
 
 	cmd->cmd_in_wq = 0;
 
@@ -287,6 +293,45 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
 	cmd->vha->tgt_counters.qla_core_ret_sta_ctio++;
 	cmd->cmd_flags |= BIT_16;
 	transport_generic_free_cmd(&cmd->se_cmd, 0);
+
+	list_for_each_entry_safe(c, tc, &h, bulk_process_list) {
+		list_del_init(&c->bulk_process_list);
+		c->work.func(&c->work);
+	}
+}
+
+static void tcm_qla2xxx_add_cmd_to_bulk_list(struct qla_tgt_cmd *cmd)
+{
+	struct qla_hw_data *ha = cmd->tgt->ha;
+	struct qla_tgt_cmd *hc;
+	unsigned long flags;
+
+	/* borrowing q_full_lock.  it's not being used very often. */
+	spin_lock_irqsave(&ha->tgt.q_full_lock, flags);
+	hc = (struct qla_tgt_cmd *)ha->tgt.ctio_for_bulk_process;
+
+	if (hc)
+		list_add_tail(&cmd->bulk_process_list, &hc->bulk_process_list);
+	else
+		ha->tgt.ctio_for_bulk_process = (void *)cmd;
+	spin_unlock_irqrestore(&ha->tgt.q_full_lock, flags);
+}
+
+static void tcm_qla2xxx_handle_bulk(struct scsi_qla_host *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+	struct qla_tgt_cmd *cmd;
+	unsigned long flags;
+
+	/* borrowing q_full_lock.  it's not being used very often. */
+	spin_lock_irqsave(&ha->tgt.q_full_lock, flags);
+	cmd = (struct qla_tgt_cmd *)ha->tgt.ctio_for_bulk_process;
+	ha->tgt.ctio_for_bulk_process = NULL;
+	spin_unlock_irqrestore(&ha->tgt.q_full_lock, flags);
+
+	if (cmd)
+		queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq,
+		    &cmd->work);
 }
 
 /*
@@ -485,6 +530,13 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 {
 	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
 	unsigned long flags;
+	struct list_head h;
+	struct qla_tgt_cmd *c = NULL, *tc = NULL;
+	struct scsi_qla_host *vha = cmd->vha;
+
+	INIT_LIST_HEAD(&h);
+	if (!list_empty(&cmd->bulk_process_list))
+		list_splice_init(&cmd->bulk_process_list, &h);
 
 	/*
 	 * Ensure that the complete FCP WRITE payload has been received.
@@ -499,7 +551,8 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
 		tcm_qla2xxx_free_cmd(cmd);
-		return;
+		tcm_qla2xxx_handle_bulk(vha);
+		goto process_bulk;
 	}
 	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
@@ -511,7 +564,7 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 		 */
 		if (cmd->se_cmd.transport_state & CMD_T_ABORTED) {
 			complete(&cmd->se_cmd.t_transport_stop_comp);
-			return;
+			goto process_bulk;
 		}
 
 		if (cmd->se_cmd.pi_err)
@@ -521,10 +574,18 @@ static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 			transport_generic_request_failure(&cmd->se_cmd,
 				TCM_CHECK_CONDITION_ABORT_CMD);
 
-		return;
+		goto process_bulk;
 	}
 
-	return target_execute_cmd(&cmd->se_cmd);
+	target_execute_cmd(&cmd->se_cmd);
+
+process_bulk:
+	list_for_each_entry_safe(c, tc, &h, bulk_process_list) {
+		list_del_init(&c->bulk_process_list);
+		c->work.func(&c->work);
+	}
+
+	return;
 }
 
 /*
@@ -535,7 +596,7 @@ static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
 	cmd->cmd_flags |= BIT_10;
 	cmd->cmd_in_wq = 1;
 	INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work);
-	queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
+	tcm_qla2xxx_add_cmd_to_bulk_list(cmd);
 }
 
 static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
@@ -611,6 +672,7 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
 				se_cmd->scsi_status);
 }
 
+
 static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
 {
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
@@ -711,6 +773,7 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 	struct qla_tgt_cmd *cmd = container_of(se_cmd,
 				struct qla_tgt_cmd, se_cmd);
 	unsigned long flags;
+	struct scsi_qla_host *vha = cmd->vha;
 
 	if (qlt_abort_cmd(cmd))
 		return;
@@ -725,6 +788,7 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 		/* Cmd have not reached firmware.
 		 * Use this trigger to free it. */
 		tcm_qla2xxx_free_cmd(cmd);
+		tcm_qla2xxx_handle_bulk(vha);
 		return;
 	}
 	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
@@ -1598,6 +1662,7 @@ static struct qla_tgt_func_tmpl tcm_qla2xxx_template = {
 	.clear_nacl_from_fcport_map = tcm_qla2xxx_clear_nacl_from_fcport_map,
 	.put_sess		= tcm_qla2xxx_put_sess,
 	.shutdown_sess		= tcm_qla2xxx_shutdown_sess,
+	.handle_bulk	= tcm_qla2xxx_handle_bulk,
 };
 
 static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport)
-- 
1.7.7


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

* [PATCH 20/20] qla2xxx: Check for online flag instead of active reset when transmitting responses
  2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
                   ` (18 preceding siblings ...)
  2015-12-08  0:49 ` [PATCH 19/20] qla2xxx: Add bulk send for atio & ctio completion paths Himanshu Madhani
@ 2015-12-08  0:49 ` Himanshu Madhani
  19 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08  0:49 UTC (permalink / raw)
  To: target-devel, nab; +Cc: giridhar.malavali, linux-scsi, himanshu.madhani

From: Dilip Kumar Uppugandla <dilip@purestorage.com>

Driver has following initialization sequence for Target mode

1. Driver initialization starts

2. ISP Abort is scheduled when the target is enabled.

qla2xxx [0000:04:00.0]-4807:25: ISP abort scheduled
qla2xxx [0000:04:00.0]-00af:25: Performing ISP error recovery - ha=ffff880caa9e0000.

3. DPC thread starts the ISP Abort

4. While DPC is resetting the chip and initializing the firmware, we get
   async events from the firmware about P2P mode, LOOP UP and PORT UPDATE.

5. PRLI from a initiator is delivered to us followed by a PLOGI and then a
   SCSI command which creates a session.

6. If the SCSI command is a WRITE in this case, we issue XFR RDY and it
   gets dropped as can be seen with messages RESET-XFR because ISP Abort
   is still active

qla2xxx [0000:04:00.0]-e902:25: RESET-XFR active/old-count/new-count = 1/1/1.

7. If the SCSI command is a READ, we issue RESPONSE and they get dropped
   as well because Abort is still active.

qla2xxx [0000:04:00.0]-e901:25: RESET-RSP active/old-count/new-count = 1/1/1

8. Now eventually, ISP Abort finishes clearing the DPC flags.

qla2xxx [0000:04:00.0]-8822:25: qla2x00_abort_isp succeeded.
qla2xxx [0000:04:00.0]-4808:25: ISP abort end.

9. Since we dropped SCSI commands silently (without any responses sent
   to the initiator) initiator waits for a SCSI timeout (which is 60
   seconds in our case), Sends an ABTS which fails since there
   no se_cmd found for the tag that ABTS is referencing as the
   commands were cleaned up in Step 6 and 7.

10. Initiator send an IO after the ABTS which succeed fine.

To fix the above case, the following changes have been made:
  - To prevent target from dropping commands silently, use the online flag
    instead to check for an active chip reset. Once the port is online during
    a chip reset phase, we are good to process the commands.
  - Clean up qla2x00_restart_isp to not set the online flag and process ATIO
    as it is unnecessary. During a chip reset, interrupts are enabled only
    after setting the online flag to 1, so ATIO's won't be missed and hence
    no need to process ATIO's after setting the online flag.

Signed-off-by: Dilip Kumar Uppugandla <dilip@purestorage.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_init.c   |   34 ++++++++++++++++++++--------------
 drivers/scsi/qla2xxx/qla_target.c |   34 +++++++++++++++++-----------------
 2 files changed, 37 insertions(+), 31 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 993dd25..52a8765 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3065,6 +3065,26 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
 			atomic_set(&vha->loop_state, LOOP_READY);
 			ql_dbg(ql_dbg_disc, vha, 0x2069,
 			    "LOOP READY.\n");
+
+			/*
+			 * Process any ATIO queue entries that came in
+			 * while we weren't online.
+			 */
+			if (qla_tgt_mode_enabled(vha)) {
+				if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+					spin_lock_irqsave(&ha->tgt.atio_lock,
+					    flags);
+					qlt_24xx_process_atio_queue(vha, 0);
+					spin_unlock_irqrestore(
+					    &ha->tgt.atio_lock, flags);
+				} else {
+					spin_lock_irqsave(&ha->hardware_lock,
+					    flags);
+					qlt_24xx_process_atio_queue(vha, 1);
+					spin_unlock_irqrestore(
+					    &ha->hardware_lock, flags);
+				}
+			}
 		}
 	}
 
@@ -4919,7 +4939,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 	struct rsp_que *rsp = ha->rsp_q_map[0];
-	unsigned long flags, flags2;
 
 	/* If firmware needs to be loaded */
 	if (qla2x00_isp_firmware(vha)) {
@@ -4941,19 +4960,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
 			/* Issue a marker after FW becomes ready. */
 			qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
 
-			vha->flags.online = 1;
-
-			/*
-			 * Process any ATIO queue entries that came in
-			 * while we weren't online.
-			 */
-			spin_lock_irqsave(&ha->hardware_lock, flags);
-			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
-			if (qla_tgt_mode_enabled(vha))
-				qlt_24xx_process_atio_queue(vha, 1);
-			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
-			spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
 			set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
 		}
 
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 9cf812f..81dd308 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -229,7 +229,7 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha)
 	spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
 }
 
-static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
+static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
 	struct atio_from_isp *atio, uint8_t ha_locked)
 {
 	ql_dbg(ql_dbg_tgt, vha, 0xe072,
@@ -285,7 +285,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
 		break;
 	}
 
-	return;
+	return false;
 }
 
 void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
@@ -1736,15 +1736,15 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
-	if (qla2x00_reset_active(vha) || mcmd->reset_count != ha->chip_reset) {
+	if (!vha->flags.online || mcmd->reset_count != ha->chip_reset) {
 		/*
-		 * Either a chip reset is active or this request was from
+		 * Either the port is not online or this request was from
 		 * previous life, just abort the processing.
 		 */
 		ql_dbg(ql_dbg_async, vha, 0xe100,
-			"RESET-TMR active/old-count/new-count = %d/%d/%d.\n",
-			qla2x00_reset_active(vha), mcmd->reset_count,
-			ha->chip_reset);
+			"RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+			vha->flags.online, qla2x00_reset_active(vha),
+			mcmd->reset_count, ha->chip_reset);
 		ha->tgt.tgt_ops->free_mcmd(mcmd);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return;
@@ -2691,17 +2691,17 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
 	else
 		vha->tgt_counters.core_qla_que_buf++;
 
-	if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+	if (!vha->flags.online || cmd->reset_count != ha->chip_reset) {
 		/*
-		 * Either a chip reset is active or this request was from
+		 * Either the port is not online or this request was from
 		 * previous life, just abort the processing.
 		 */
 		cmd->state = QLA_TGT_STATE_PROCESSED;
 		qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		ql_dbg(ql_dbg_async, vha, 0xe101,
-			"RESET-RSP active/old-count/new-count = %d/%d/%d.\n",
-			qla2x00_reset_active(vha), cmd->reset_count,
-			ha->chip_reset);
+			"RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
+			vha->flags.online, qla2x00_reset_active(vha),
+			cmd->reset_count, ha->chip_reset);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return 0;
 	}
@@ -2832,18 +2832,18 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
-	if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+	if (!vha->flags.online || (cmd->reset_count != ha->chip_reset) ||
 	    (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
 		/*
-		 * Either a chip reset is active or this request was from
+		 * Either the port is not online or this request was from
 		 * previous life, just abort the processing.
 		 */
 		cmd->state = QLA_TGT_STATE_NEED_DATA;
 		qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
 		ql_dbg(ql_dbg_async, vha, 0xe102,
-			"RESET-XFR active/old-count/new-count = %d/%d/%d.\n",
-			qla2x00_reset_active(vha), cmd->reset_count,
-			ha->chip_reset);
+			"RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+			vha->flags.online, qla2x00_reset_active(vha),
+			cmd->reset_count, ha->chip_reset);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 		return 0;
 	}
-- 
1.7.7


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

* Re: [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW
  2015-12-08  0:48 ` [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW Himanshu Madhani
@ 2015-12-08  1:41   ` kbuild test robot
  2015-12-08 15:58   ` Hannes Reinecke
  1 sibling, 0 replies; 51+ messages in thread
From: kbuild test robot @ 2015-12-08  1:41 UTC (permalink / raw)
  Cc: kbuild-all, target-devel, nab, giridhar.malavali, linux-scsi,
	himanshu.madhani

[-- Attachment #1: Type: text/plain, Size: 2049 bytes --]

Hi Alexei,

[auto build test WARNING on target/master]
[also build test WARNING on v4.4-rc4 next-20151207]
[cannot apply to scsi/for-next]

url:    https://github.com/0day-ci/linux/commits/Himanshu-Madhani/qla2xxx-Patches-for-target-pending-branch/20151208-093328
base:   https://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
config: i386-randconfig-x007-12070758 (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   drivers/scsi/qla2xxx/qla_target.c: In function 'qlt_do_ctio_completion':
>> drivers/scsi/qla2xxx/qla_target.c:3465:20: warning: comparison of constant '41' with boolean expression is always false [-Wbool-compare]
           (logged_out == CTIO_PORT_LOGGED_OUT) ?
                       ^

vim +/41 +3465 drivers/scsi/qla2xxx/qla_target.c

  3449				/* They are OK */
  3450				ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058,
  3451				    "qla_target(%d): CTIO with "
  3452				    "status %#x received, state %x, se_cmd %p, "
  3453				    "(LIP_RESET=e, ABORTED=2, TARGET_RESET=17, "
  3454				    "TIMEOUT=b, INVALID_RX_ID=8)\n", vha->vp_idx,
  3455				    status, cmd->state, se_cmd);
  3456				break;
  3457	
  3458			case CTIO_PORT_LOGGED_OUT:
  3459			case CTIO_PORT_UNAVAILABLE:
  3460			{
  3461				bool logged_out = (status & 0xFFFF);
  3462				ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
  3463				    "qla_target(%d): CTIO with %s status %x "
  3464				    "received (state %x, se_cmd %p)\n", vha->vp_idx,
> 3465				    (logged_out == CTIO_PORT_LOGGED_OUT) ?
  3466				    "PORT LOGGED OUT" : "PORT UNAVAILABLE",
  3467				    status, cmd->state, se_cmd);
  3468	
  3469				if (logged_out && cmd->sess) {
  3470					/*
  3471					 * Session is already logged out, but we need
  3472					 * to notify initiator, who's not aware of this
  3473					 */

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 26411 bytes --]

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

* Re: [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver.
  2015-12-08  0:48 ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Himanshu Madhani
@ 2015-12-08  2:10   ` kbuild test robot
  2015-12-08  2:10   ` [PATCH] qla2xxx: fix ifnullfree.cocci warnings kbuild test robot
  2015-12-08 15:54   ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Hannes Reinecke
  2 siblings, 0 replies; 51+ messages in thread
From: kbuild test robot @ 2015-12-08  2:10 UTC (permalink / raw)
  Cc: kbuild-all, target-devel, nab, giridhar.malavali, linux-scsi,
	himanshu.madhani

Hi Himanshu,

[auto build test WARNING on target/master]
[also build test WARNING on v4.4-rc4 next-20151207]
[cannot apply to scsi/for-next]

url:    https://github.com/0day-ci/linux/commits/Himanshu-Madhani/qla2xxx-Patches-for-target-pending-branch/20151208-093328
base:   https://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master


coccinelle warnings: (new ones prefixed by >>)

>> drivers/scsi/qla2xxx/qla_iocb.c:2022:2-7: WARNING: NULL check before freeing functions like kfree, debugfs_remove, debugfs_remove_recursive or usb_free_urb is not needed. Maybe consider reorganizing relevant code to avoid passing NULL values.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

* [PATCH] qla2xxx: fix ifnullfree.cocci warnings
  2015-12-08  0:48 ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Himanshu Madhani
  2015-12-08  2:10   ` kbuild test robot
@ 2015-12-08  2:10   ` kbuild test robot
  2015-12-08 15:54   ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Hannes Reinecke
  2 siblings, 0 replies; 51+ messages in thread
From: kbuild test robot @ 2015-12-08  2:10 UTC (permalink / raw)
  Cc: kbuild-all, target-devel, nab, giridhar.malavali, linux-scsi,
	himanshu.madhani

drivers/scsi/qla2xxx/qla_iocb.c:2022:2-7: WARNING: NULL check before freeing functions like kfree, debugfs_remove, debugfs_remove_recursive or usb_free_urb is not needed. Maybe consider reorganizing relevant code to avoid passing NULL values.

 NULL check before some freeing functions is not needed.

 Based on checkpatch warning
 "kfree(NULL) is safe this check is probably not required"
 and kfreeaddr.cocci by Julia Lawall.

Generated by: scripts/coccinelle/free/ifnullfree.cocci

CC: Himanshu Madhani <himanshu.madhani@qlogic.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 qla_iocb.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2018,8 +2018,7 @@ qla2x00_els_dcmd_sp_free(void *ptr, void
 	srb_t *sp = (srb_t *)data;
 	struct srb_iocb *elsio = &sp->u.iocb_cmd;
 
-	if (sp->fcport)
-		kfree(sp->fcport);
+	kfree(sp->fcport);
 
 	if (elsio->u.els_logo.els_logo_pyld)
 		dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,

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

* Re: [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1
  2015-12-08  0:48 ` [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1 Himanshu Madhani
@ 2015-12-08  2:33   ` Christoph Hellwig
  2015-12-09  6:56   ` Hannes Reinecke
  1 sibling, 0 replies; 51+ messages in thread
From: Christoph Hellwig @ 2015-12-08  2:33 UTC (permalink / raw)
  To: Himanshu Madhani; +Cc: target-devel, nab, giridhar.malavali, linux-scsi

On Mon, Dec 07, 2015 at 07:48:56PM -0500, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> change tcm_qla2xxx_check_stop_free to always return 1
> to prevent transport_cmd_finish_abort from accidently
> taking extra kref_put.

This looks a bit fishy.  Even if this was the right behavior it's
something all something all drivers returning the value of
target_put_sess_cmd in their check_stop_free would need to do.

Can you explain the issue you're trying to address in a little more
detail?

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

* Re: [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  2015-12-08  0:48 ` [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module Himanshu Madhani
@ 2015-12-08  2:37   ` Christoph Hellwig
  2015-12-09 22:07     ` Quinn Tran
  2015-12-09  7:01   ` Hannes Reinecke
  1 sibling, 1 reply; 51+ messages in thread
From: Christoph Hellwig @ 2015-12-08  2:37 UTC (permalink / raw)
  To: Himanshu Madhani; +Cc: target-devel, nab, giridhar.malavali, linux-scsi

> -void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
> +int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
>  {
>  	struct qla_tgt *tgt = cmd->tgt;
>  	struct scsi_qla_host *vha = tgt->vha;
>  	struct se_cmd *se_cmd = &cmd->se_cmd;
> +	unsigned long flags,refcount;
>  
>  	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
>  	    "qla_target(%d): terminating exchange for aborted cmd=%p "
>  	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
>  	    se_cmd->tag);
>  
> +    spin_lock_irqsave(&cmd->cmd_lock, flags);
> +    if (cmd->aborted) {
> +        spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +
> +        /* It's normal to see 2 calls in this path:
> +         *  1) XFER Rdy completion + CMD_T_ABORT
> +         *  2) TCM TMR - drain_state_list
> +         */
> +        refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
> +        ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
> +               "multiple abort. %p refcount %lx"
> +               "transport_state %x, t_state %x, se_cmd_flags %x \n",
> +               cmd, refcount,cmd->se_cmd.transport_state,
> +               cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
> +
> +        return EIO;
> +    }

Err, no.  Looking into the refcount inside a kref is never the
right thing to do.

> +typedef enum {
> +	/*
> +	 * BIT_0 - Atio Arrival / schedule to work
> +	 * BIT_1 - qlt_do_work
> +	 * BIT_2 - qlt_do work failed
> +	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
> +	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
> +	 * BIT_5 - status respond / tcm_qla2xx_queue_status
> +	 * BIT_6 - tcm request to abort/Term exchange.
> +	 *	pre_xmit_response->qlt_send_term_exchange
> +	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
> +	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
> +	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
> +	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
> +
> +	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
> +	 * BIT_13 - Bad completion -
> +	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
> +	 * BIT_14 - Back end data received/sent.
> +	 * BIT_15 - SRR prepare ctio
> +	 * BIT_16 - complete free
> +	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
> +	 * BIT_18 - completion w/abort status
> +	 * BIT_19 - completion w/unknown status
> +	 * BIT_20 - tcm_qla2xxx_free_cmd

Please use descriptive names for these flags in the source code!

> +	BUG_ON(cmd->cmd_flags & BIT_20);
> +	cmd->cmd_flags |= BIT_20;
> +

And no crazieness like this.  While we're at it: what synchronizes
access to ->cmd_flags?

> @@ -466,13 +484,25 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
>  static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
>  {
>  	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
> +	unsigned long flags;
>  
>  	/*
>  	 * Ensure that the complete FCP WRITE payload has been received.
>  	 * Otherwise return an exception via CHECK_CONDITION status.
>  	 */
>  	cmd->cmd_in_wq = 0;
> -	cmd->cmd_flags |= BIT_11;
> +
> +	spin_lock_irqsave(&cmd->cmd_lock, flags);
> +	cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
> +	if (cmd->aborted) {
> +		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
> +		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +
> +		tcm_qla2xxx_free_cmd(cmd);
> +		return;
> +	}
> +	spin_unlock_irqrestore(&cmd->cmd_lock, flags);

All these abort flag hacks look very suspicios.  Can you explain the
exact theory of operation behind them?


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

* Re: [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer
  2015-12-08  0:48 ` [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer Himanshu Madhani
@ 2015-12-08  2:48   ` Christoph Hellwig
  2015-12-09 20:24     ` Quinn Tran
  2015-12-09  7:02   ` Hannes Reinecke
  1 sibling, 1 reply; 51+ messages in thread
From: Christoph Hellwig @ 2015-12-08  2:48 UTC (permalink / raw)
  To: Himanshu Madhani; +Cc: target-devel, nab, giridhar.malavali, linux-scsi

> diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> index 842fcca..2e9c194 100644
> --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> @@ -617,6 +617,26 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
>  				struct qla_tgt_cmd, se_cmd);
>  	int xmit_type = QLA_TGT_XMIT_STATUS;
>  
> +	if (se_cmd->transport_state & CMD_T_ABORTED) {
> +		/* For TCM TAS support n kernel >= 3.15:
> +		 * This cmd is attempting to respond with "Task Aborted Status".
> +		 */
> +		if (cmd->aborted) {
> +			return 0;
> +		} else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
> +		    cmd->cmd_sent_to_fw) {
> +			qlt_abort_cmd(cmd);
> +			return 0;
> +		} else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
> +			if (cmd->cmd_sent_to_fw) {
> +				qlt_abort_cmd(cmd);
> +				return 0;
> +			} else {	/* about to be free */
> +				return 0;
> +			}
> +		}
> +	}
> +

This is really something that should be explicitly communicated
from the core instead of having to second guess it.

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

* Re: [PATCH 12/20] target/tmr: LUN reset cause cmd premature free.
  2015-12-08  0:48 ` [PATCH 12/20] target/tmr: LUN reset cause cmd premature free Himanshu Madhani
@ 2015-12-08  2:48   ` Christoph Hellwig
  2015-12-09 20:11     ` Quinn Tran
  2016-01-04  7:44     ` Bart Van Assche
  2015-12-09  7:03   ` Hannes Reinecke
  1 sibling, 2 replies; 51+ messages in thread
From: Christoph Hellwig @ 2015-12-08  2:48 UTC (permalink / raw)
  To: Himanshu Madhani; +Cc: target-devel, nab, giridhar.malavali, linux-scsi

On Mon, Dec 07, 2015 at 07:48:59PM -0500, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> During LUN/Target reset, the TMR code attempt to intercept
> cmds and try to aborted them.  Current code assume cmds are
> always intercepted at the back end device.  The cleanup code
> would issue a "queue_status() & check_stop_free()" to terminate
> the command.  However, when a cmd is intercepted at the front
> end/Fabric layer, current code introduce premature free or
> cause Fabric to double free.
> 
> When command is intercepted at Fabric layer, it means a
> check_stop_free(cmd_kref--) has been called.  The extra
> check_stop_free in the Lun Reset cleanup code causes early
> free.  When a cmd in the Fabric layer is completed, the normal
> free code adds another another free which introduce a double free.
> 
> To fix the issue:
> - add a new flag/CMD_T_SENT_STATUS to track command that have
>  made it down to fabric layer after back end good/bad completion.
> - if cmd reach Fabric Layer at Lun Reset time, add an extra
>  cmd_kref count to prevent premature free.

This seems lke something solved by Bart's abort rewrite in a much nicer
way.  All this special casing based on magic flags isn't maintainable
in the long run.

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

* Re: [PATCH 01/20] qla2xxx: Enable Extended Login support
  2015-12-08  0:48 ` [PATCH 01/20] qla2xxx: Enable Extended Login support Himanshu Madhani
@ 2015-12-08 15:51   ` Hannes Reinecke
  2015-12-08 19:35     ` Himanshu Madhani
  0 siblings, 1 reply; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 15:51 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
> ---
A patch description would be nice; ATM it doesn't look
as if this interface is used anywhere...

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)

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

* Re: [PATCH 02/20] qla2xxx: Enable Exchange offload support.
  2015-12-08  0:48 ` [PATCH 02/20] qla2xxx: Enable Exchange offload support Himanshu Madhani
@ 2015-12-08 15:52   ` Hannes Reinecke
  0 siblings, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 15:52 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
> ---
Same here.
Please add a patch description.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 03/20] qla2xxx: Enable Target counters in DebugFS.
  2015-12-08  0:48 ` [PATCH 03/20] qla2xxx: Enable Target counters in DebugFS Himanshu Madhani
@ 2015-12-08 15:52   ` Hannes Reinecke
  0 siblings, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 15:52 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> Following counters are added in target mode to help debugging efforts.
> 
> Target Counters
> 
> qla_core_sbt_cmd = 0
> qla_core_ret_sta_ctio = 0
> qla_core_ret_ctio = 0
> core_qla_que_buf = 0
> core_qla_snd_status = 0
> core_qla_free_cmd = 0
> num alloc iocb failed = 0
> num term exchange sent = 0
> num Q full sent = 0
> 
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
> ---
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 04/20] qla2xxx: Add FW resource count in DebugFS.
  2015-12-08  0:48 ` [PATCH 04/20] qla2xxx: Add FW resource count " Himanshu Madhani
@ 2015-12-08 15:53   ` Hannes Reinecke
  0 siblings, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 15:53 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> DebugFS now will show fw_resource_count node.
> 
> FW Resource count
> 
> Original TGT exchg count[0]
> current TGT exchg count[0]
> original Initiator Exchange count[2048]
> Current Initiator Exchange count[2048]
> Original IOCB count[2078]
> Current IOCB count[2067]
> MAX VP count[254]
> MAX FCF count[0]
> 
> Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver.
  2015-12-08  0:48 ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Himanshu Madhani
  2015-12-08  2:10   ` kbuild test robot
  2015-12-08  2:10   ` [PATCH] qla2xxx: fix ifnullfree.cocci warnings kbuild test robot
@ 2015-12-08 15:54   ` Hannes Reinecke
  2 siblings, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 15:54 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
> ---
>  drivers/scsi/qla2xxx/qla_attr.c   |   36 +++++++
>  drivers/scsi/qla2xxx/qla_dbg.c    |    5 +-
>  drivers/scsi/qla2xxx/qla_def.h    |   19 ++++-
>  drivers/scsi/qla2xxx/qla_gbl.h    |    2 +
>  drivers/scsi/qla2xxx/qla_inline.h |    2 +
>  drivers/scsi/qla2xxx/qla_iocb.c   |  189 +++++++++++++++++++++++++++++++++++++
>  drivers/scsi/qla2xxx/qla_isr.c    |    6 +
>  7 files changed, 255 insertions(+), 4 deletions(-)
> 
Well, this isn't actually an interface to send generic ELS commands,
it's an interface to send an explicit LOGO using ELS.
Personally, I'd prefer to have a 'real' ELS interface using bsg,
and map the explicit LOGO based on that.

Alternatively please fixup the description.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)

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

* Re: [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW
  2015-12-08  0:48 ` [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW Himanshu Madhani
  2015-12-08  1:41   ` kbuild test robot
@ 2015-12-08 15:58   ` Hannes Reinecke
  1 sibling, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 15:58 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Alexei Potashnik <alexei@purestorage.com>
> 
> 1. Initiator A is logged in with fc_id(1)/loop_id(1)
> 2. Initiator A re-logs in with fc_id(2)/loop_id(2)
> 3. Part of old session deletion async logoout for 1/1 is queued
> 4. Initiator B logs in with fc_id(1)/loop_id(1), starts
>    passing data and creates session.
> 5. Async logo from 3 is processed by DPC and sent to FW
> 
> Now initiator B has the session but is logged out from FW.
> 
> This condition is detected first with CTIO error 29 at which
> point we should delete current session. During session
> deletion we will send LOGO to initiator to force re-login.
> 
> Under rare circumstances initiator might be logged out of FW,
> not have driver session, but still think it's logged in.
> E.g. the above sequence plus session deletion due to re-config.
> Incoming commands will fail to create local session because
> initiator is not found in FW. In this case we also issue LOGO
> to initiator to force him re-login.
> 
> Finally this patch fixes exchange leak when commands where
> received in logged out state. In this case loop_id must be
> set to FFFF when corresponding exchange is terminated. The
> patch modifies exchange termination to always use FFFF,
> since in certain scenarios it's impossible to tell whether
> command was received in logged in or logged out state.
> 
> Signed-off-by: Alexei Potashnik <alexei@purestorage.com>
> Acked-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 07/20] qla2xxx: Wait for all conflicts before ack'ing PLOGI
  2015-12-08  0:48 ` [PATCH 07/20] qla2xxx: Wait for all conflicts before ack'ing PLOGI Himanshu Madhani
@ 2015-12-08 16:00   ` Hannes Reinecke
  0 siblings, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 16:00 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Alexei Potashnik <alexei@purestorage.com>
> 
> Until now ack'ing of a new PLOGI has only been delayed if there
> was an existing session for the same WWN. Ack was released when
> the session deletion completed.
> 
> If there was another WWN session with the same fc_id/loop_id pair
> (aka "conflicting session"), PLOGI was still ack'ed immediately.
> This potentially caused a problem when old session deletion logged
> fc_id/loop_id out of FW after new session has been established.
> 
> Two work-arounds were attempted before:
> 1. Dropping PLOGIs until conflicting session goes away.
> 2. Detecting initiator being logged out of FW and issuing LOGO
> to force re-login.
> 
> This patch introduces proper solution to the problem where PLOGI
> is held until either existing session with same WWN or any
> conflicting session goes away. Mechanism supports one session holding
> two PLOGI acks as well as one PLOGI ack being held by many sessions.
> 
> Signed-off-by: Alexei Potashnik <alexei@purestorage.com>
> Acked-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)

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

* Re: [PATCH 08/20] qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit.
  2015-12-08  0:48 ` [PATCH 08/20] qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit Himanshu Madhani
@ 2015-12-08 16:01   ` Hannes Reinecke
  0 siblings, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-08 16:01 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> Replace QLA_TGT_STATE_ABORTED state with a bit because
> the current state of the command is lost when an abort
> is requested by upper layer.
> 
> Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)

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

* Re: [PATCH 01/20] qla2xxx: Enable Extended Login support
  2015-12-08 15:51   ` Hannes Reinecke
@ 2015-12-08 19:35     ` Himanshu Madhani
  0 siblings, 0 replies; 51+ messages in thread
From: Himanshu Madhani @ 2015-12-08 19:35 UTC (permalink / raw)
  To: Hannes Reinecke, target-devel, nab; +Cc: Giridhar Malavali, linux-scsi

[-- Attachment #1: Type: text/plain, Size: 679 bytes --]

On 12/8/15, 7:51 AM, "Hannes Reinecke" <hare@suse.de> wrote:


>On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
>> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
>> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
>> ---
>A patch description would be nice; ATM it doesn't look
>as if this interface is used anywhere...

I¹ll update patch with description of the feature.

>
>Cheers,
>
>Hannes
>-- 
>Dr. Hannes Reinecke		      zSeries & Storage
>hare@suse.de			      +49 911 74053 688
>SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
>GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)

Thanks,
Himanshu


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 4317 bytes --]

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

* Re: [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1
  2015-12-08  0:48 ` [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1 Himanshu Madhani
  2015-12-08  2:33   ` Christoph Hellwig
@ 2015-12-09  6:56   ` Hannes Reinecke
  2015-12-10  1:06     ` Quinn Tran
  1 sibling, 1 reply; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-09  6:56 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> change tcm_qla2xxx_check_stop_free to always return 1
> to prevent transport_cmd_finish_abort from accidently
> taking extra kref_put.
> 
> Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
>  drivers/scsi/qla2xxx/tcm_qla2xxx.c |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> index 74c6e9b..366142a 100644
> --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> @@ -314,7 +314,8 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd)
>  		cmd->cmd_flags |= BIT_14;
>  	}
>  
> -	return target_put_sess_cmd(se_cmd);
> +	target_put_sess_cmd(se_cmd);
> +	return 1;
>  }
>  
>  /* tcm_qla2xxx_release_cmd - Callback from TCM Core to release underlying
> 
Odd. I would have expected target_put_sess_cmd() to never fail.
But if it does, doesn't it mean that the command is hosed, and we should
have accessed it in the first place?
Very suspicious.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  2015-12-08  0:48 ` [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module Himanshu Madhani
  2015-12-08  2:37   ` Christoph Hellwig
@ 2015-12-09  7:01   ` Hannes Reinecke
  2015-12-09 22:41     ` Quinn Tran
  1 sibling, 1 reply; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-09  7:01 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> During lun reset, TMR thread from TCM would issue abort
> to qla driver.  At abort time, each command is in different
> state.  Depending on the state, qla will use the TMR thread
> to trigger a command free(cmd_kref--) if command is not
> down at firmware.
> 
> Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
>  drivers/scsi/qla2xxx/qla_target.c  |   60 +++++++++++++++++++++--------
>  drivers/scsi/qla2xxx/qla_target.h  |   59 +++++++++++++++++------------
>  drivers/scsi/qla2xxx/tcm_qla2xxx.c |   73 ++++++++++++++++++++++++++++++++++-
>  3 files changed, 147 insertions(+), 45 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
> index 638940f..4d42b79 100644
> --- a/drivers/scsi/qla2xxx/qla_target.c
> +++ b/drivers/scsi/qla2xxx/qla_target.c
> @@ -105,7 +105,7 @@ static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
>  static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
>  	int fn, void *iocb, int flags);
>  static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
> -	*cmd, struct atio_from_isp *atio, int ha_locked);
> +	*cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
>  static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
>  	struct qla_tgt_srr_imm *imm, int ha_lock);
>  static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
> @@ -2646,7 +2646,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
>  			/* no need to terminate. FW already freed exchange. */
>  			qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
>  		else
> -			qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
> +			qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
>  		spin_unlock_irqrestore(&ha->hardware_lock, flags);
>  		return 0;
>  	}
> @@ -3154,7 +3154,8 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
>  }
>  
>  static void qlt_send_term_exchange(struct scsi_qla_host *vha,
> -	struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
> +	struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked,
> +	int ul_abort)
>  {
>  	unsigned long flags = 0;
>  	int rc;
> @@ -3174,8 +3175,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
>  		qlt_alloc_qfull_cmd(vha, atio, 0, 0);
>  
>  done:
> -	if (cmd && (!cmd->aborted ||
> -	    !cmd->cmd_sent_to_fw)) {
> +	if (cmd && !ul_abort && !cmd->aborted) {
>  		if (cmd->sg_mapped)
>  			qlt_unmap_sg(vha, cmd);
>  		vha->hw->tgt.tgt_ops->free_cmd(cmd);
> @@ -3234,21 +3234,43 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
>  
>  }
>  
> -void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
> +int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
>  {
>  	struct qla_tgt *tgt = cmd->tgt;
>  	struct scsi_qla_host *vha = tgt->vha;
>  	struct se_cmd *se_cmd = &cmd->se_cmd;
> +	unsigned long flags,refcount;
>  
>  	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
>  	    "qla_target(%d): terminating exchange for aborted cmd=%p "
>  	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
>  	    se_cmd->tag);
>  
> +    spin_lock_irqsave(&cmd->cmd_lock, flags);
> +    if (cmd->aborted) {
> +        spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +
> +        /* It's normal to see 2 calls in this path:
> +         *  1) XFER Rdy completion + CMD_T_ABORT
> +         *  2) TCM TMR - drain_state_list
> +         */
> +        refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
> +        ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
> +               "multiple abort. %p refcount %lx"
> +               "transport_state %x, t_state %x, se_cmd_flags %x \n",
> +               cmd, refcount,cmd->se_cmd.transport_state,
> +               cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
> +
> +        return EIO;
> +    }
> +
>  	cmd->aborted = 1;
>  	cmd->cmd_flags |= BIT_6;
> +    spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +
> +	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
>  
> -	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
> +	return 0;
>  }
>  EXPORT_SYMBOL(qlt_abort_cmd);
>  
> @@ -3263,6 +3285,9 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
>  
>  	BUG_ON(cmd->cmd_in_wq);
>  
> +	if (cmd->sg_mapped)
> +		qlt_unmap_sg(cmd->vha, cmd);
> +
>  	if (!cmd->q_full)
>  		qlt_decr_num_pend_cmds(cmd->vha);
>  
> @@ -3380,7 +3405,7 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio,
>  		term = 1;
>  
>  	if (term)
> -		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
> +		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
>  
>  	return term;
>  }
> @@ -3735,6 +3760,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
>  		goto out_term;
>  	}
>  
> +	spin_lock_init(&cmd->cmd_lock);
>  	cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
>  	cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
>  	cmd->unpacked_lun = scsilun_to_int(
> @@ -3777,7 +3803,7 @@ out_term:
>  	 */
>  	cmd->cmd_flags |= BIT_2;
>  	spin_lock_irqsave(&ha->hardware_lock, flags);
> -	qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
> +	qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0);
>  
>  	qlt_decr_num_pend_cmds(vha);
>  	percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
> @@ -3896,7 +3922,7 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
>  
>  out_term:
>  	spin_lock_irqsave(&ha->hardware_lock, flags);
> -	qlt_send_term_exchange(vha, NULL, &op->atio, 1);
> +	qlt_send_term_exchange(vha, NULL, &op->atio, 1, 0);
>  	spin_unlock_irqrestore(&ha->hardware_lock, flags);
>  	kfree(op);
>  
> @@ -4722,7 +4748,7 @@ out_reject:
>  		dump_stack();
>  	} else {
>  		cmd->cmd_flags |= BIT_9;
> -		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
> +		qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
>  	}
>  	spin_unlock_irqrestore(&ha->hardware_lock, flags);
>  }
> @@ -4901,7 +4927,7 @@ static void qlt_prepare_srr_imm(struct scsi_qla_host *vha,
>  				    sctio, sctio->srr_id);
>  				list_del(&sctio->srr_list_entry);
>  				qlt_send_term_exchange(vha, sctio->cmd,
> -				    &sctio->cmd->atio, 1);
> +				    &sctio->cmd->atio, 1, 0);
>  				kfree(sctio);
>  			}
>  		}
> @@ -5071,7 +5097,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
>  	sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
>  	    atio->u.isp24.fcp_hdr.s_id);
>  	if (!sess) {
> -		qlt_send_term_exchange(vha, NULL, atio, 1);
> +		qlt_send_term_exchange(vha, NULL, atio, 1, 0);
>  		return 0;
>  	}
>  	/* Sending marker isn't necessary, since we called from ISR */
> @@ -5345,7 +5371,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
>  #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
>  				qlt_send_busy(vha, atio, SAM_STAT_BUSY);
>  #else
> -				qlt_send_term_exchange(vha, NULL, atio, 1);
> +				qlt_send_term_exchange(vha, NULL, atio, 1, 0);
>  #endif
>  			} else {
>  				if (tgt->tgt_stop) {
> @@ -5446,7 +5472,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
>  #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
>  				qlt_send_busy(vha, atio, 0);
>  #else
> -				qlt_send_term_exchange(vha, NULL, atio, 1);
> +				qlt_send_term_exchange(vha, NULL, atio, 1, 0);
>  #endif
>  			} else {
>  				if (tgt->tgt_stop) {
> @@ -5455,7 +5481,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
>  					    "command to target, sending TERM "
>  					    "EXCHANGE for rsp\n");
>  					qlt_send_term_exchange(vha, NULL,
> -					    atio, 1);
> +					    atio, 1, 0);
>  				} else {
>  					ql_dbg(ql_dbg_tgt, vha, 0xe060,
>  					    "qla_target(%d): Unable to send "
> @@ -5875,7 +5901,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
>  	return;
>  
>  out_term:
> -	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
> +	qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
>  	if (sess)
>  		ha->tgt.tgt_ops->put_sess(sess);
>  	spin_unlock_irqrestore(&ha->hardware_lock, flags);
> diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
> index f5dbeab..a079c237 100644
> --- a/drivers/scsi/qla2xxx/qla_target.h
> +++ b/drivers/scsi/qla2xxx/qla_target.h
> @@ -941,6 +941,36 @@ struct qla_tgt_sess {
>  	qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
>  };
>  
> +typedef enum {
> +	/*
> +	 * BIT_0 - Atio Arrival / schedule to work
> +	 * BIT_1 - qlt_do_work
> +	 * BIT_2 - qlt_do work failed
> +	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
> +	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
> +	 * BIT_5 - status respond / tcm_qla2xx_queue_status
> +	 * BIT_6 - tcm request to abort/Term exchange.
> +	 *	pre_xmit_response->qlt_send_term_exchange
> +	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
> +	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
> +	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
> +	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
> +
> +	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
> +	 * BIT_13 - Bad completion -
> +	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
> +	 * BIT_14 - Back end data received/sent.
> +	 * BIT_15 - SRR prepare ctio
> +	 * BIT_16 - complete free
> +	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
> +	 * BIT_18 - completion w/abort status
> +	 * BIT_19 - completion w/unknown status
> +	 * BIT_20 - tcm_qla2xxx_free_cmd
> +	 */
> +	CMD_FLAG_DATA_WORK = BIT_11,
> +	CMD_FLAG_DATA_WORK_FREE = BIT_21,
> +} cmd_flags_t;
> +
>  struct qla_tgt_cmd {
>  	struct se_cmd se_cmd;
>  	struct qla_tgt_sess *sess;
> @@ -950,6 +980,7 @@ struct qla_tgt_cmd {
>  	/* Sense buffer that will be mapped into outgoing status */
>  	unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
>  
> +	spinlock_t cmd_lock;
>  	/* to save extra sess dereferences */
>  	unsigned int conf_compl_supported:1;
>  	unsigned int sg_mapped:1;
> @@ -984,30 +1015,8 @@ struct qla_tgt_cmd {
>  
>  	uint64_t jiffies_at_alloc;
>  	uint64_t jiffies_at_free;
> -	/* BIT_0 - Atio Arrival / schedule to work
> -	 * BIT_1 - qlt_do_work
> -	 * BIT_2 - qlt_do work failed
> -	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
> -	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
> -	 * BIT_5 - status respond / tcm_qla2xx_queue_status
> -	 * BIT_6 - tcm request to abort/Term exchange.
> -	 *	pre_xmit_response->qlt_send_term_exchange
> -	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
> -	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
> -	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
> -	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
> -	 * BIT_11 - Data actually going to TCM : tcm_qla2xx_handle_data_work
> -	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
> -	 * BIT_13 - Bad completion -
> -	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
> -	 * BIT_14 - Back end data received/sent.
> -	 * BIT_15 - SRR prepare ctio
> -	 * BIT_16 - complete free
> -	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
> -	 * BIT_18 - completion w/abort status
> -	 * BIT_19 - completion w/unknown status
> -	 */
> -	uint32_t cmd_flags;
> +
> +	cmd_flags_t cmd_flags;
>  };
>  
>  struct qla_tgt_sess_work_param {
> @@ -1146,7 +1155,7 @@ static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
>  extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
>  extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
>  extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
> -extern void qlt_abort_cmd(struct qla_tgt_cmd *);
> +extern int qlt_abort_cmd(struct qla_tgt_cmd *);
>  extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
>  extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
>  extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
> diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> index 366142a..842fcca 100644
> --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> @@ -298,6 +298,10 @@ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
>  {
>  	cmd->vha->tgt_counters.core_qla_free_cmd++;
>  	cmd->cmd_in_wq = 1;
> +
> +	BUG_ON(cmd->cmd_flags & BIT_20);
> +	cmd->cmd_flags |= BIT_20;
> +
>  	INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
>  	queue_work(tcm_qla2xxx_free_wq, &cmd->work);
>  }
Why not test_and_set_bit()?

> @@ -375,6 +379,20 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
>  {
>  	struct qla_tgt_cmd *cmd = container_of(se_cmd,
>  				struct qla_tgt_cmd, se_cmd);
> +
> +	if (cmd->aborted) {
> +		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
> +		 * can get ahead of this cmd. tcm_qla2xxx_aborted_task
> +		 * already kick start the free.
> +		 */
> +		pr_debug("write_pending aborted cmd[%p] refcount %d "
> +			"transport_state %x, t_state %x, se_cmd_flags %x\n",
> +			cmd,cmd->se_cmd.cmd_kref.refcount.counter,
> +			cmd->se_cmd.transport_state,
> +			cmd->se_cmd.t_state,
> +			cmd->se_cmd.se_cmd_flags);
> +		return 0;
> +	}
>  	cmd->cmd_flags |= BIT_3;
>  	cmd->bufflen = se_cmd->data_length;
>  	cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
> @@ -406,7 +424,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
>  	    se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
>  		spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
>  		wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
> -					    3 * HZ);
> +						50);
>  		return 0;
>  	}
>  	spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
> @@ -466,13 +484,25 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
>  static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
>  {
>  	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
> +	unsigned long flags;
>  
>  	/*
>  	 * Ensure that the complete FCP WRITE payload has been received.
>  	 * Otherwise return an exception via CHECK_CONDITION status.
>  	 */
>  	cmd->cmd_in_wq = 0;
> -	cmd->cmd_flags |= BIT_11;
> +
> +	spin_lock_irqsave(&cmd->cmd_lock, flags);
> +	cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
> +	if (cmd->aborted) {
> +		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
> +		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +
> +		tcm_qla2xxx_free_cmd(cmd);
> +		return;
> +	}
> +	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +
>  	cmd->vha->tgt_counters.qla_core_ret_ctio++;
>  	if (!cmd->write_data_transferred) {
>  		/*
> @@ -547,6 +577,20 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
>  	struct qla_tgt_cmd *cmd = container_of(se_cmd,
>  				struct qla_tgt_cmd, se_cmd);
>  
> +	if (cmd->aborted) {
> +		/* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
> +		 * can get ahead of this cmd. tcm_qla2xxx_aborted_task
> +		 * already kick start the free.
> +		 */
> +		pr_debug("queue_data_in aborted cmd[%p] refcount %d "
> +			"transport_state %x, t_state %x, se_cmd_flags %x\n",
> +			cmd,cmd->se_cmd.cmd_kref.refcount.counter,
> +			cmd->se_cmd.transport_state,
> +			cmd->se_cmd.t_state,
> +			cmd->se_cmd.se_cmd_flags);
> +		return 0;
> +	}
> +
>  	cmd->cmd_flags |= BIT_4;
>  	cmd->bufflen = se_cmd->data_length;
>  	cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
> @@ -638,11 +682,34 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
>  	qlt_xmit_tm_rsp(mcmd);
>  }
>  
> +
> +#define DATA_WORK_NOT_FREE(_flags) \
> +	(( _flags & (CMD_FLAG_DATA_WORK|CMD_FLAG_DATA_WORK_FREE)) == \
> +	 CMD_FLAG_DATA_WORK)
>  static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
>  {
>  	struct qla_tgt_cmd *cmd = container_of(se_cmd,
>  				struct qla_tgt_cmd, se_cmd);
> -	qlt_abort_cmd(cmd);
> +	unsigned long flags;
> +
> +	if (qlt_abort_cmd(cmd))
> +		return;
> +
> +	spin_lock_irqsave(&cmd->cmd_lock, flags);
> +	if ((cmd->state == QLA_TGT_STATE_NEW)||
> +		((cmd->state == QLA_TGT_STATE_DATA_IN) &&
> +		 DATA_WORK_NOT_FREE(cmd->cmd_flags)) ) {
> +
> +		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
> +		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +		/* Cmd have not reached firmware.
> +		 * Use this trigger to free it. */
> +		tcm_qla2xxx_free_cmd(cmd);
> +		return;
> +	}
> +	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +	return;
> +
>  }
>  
>  static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
> 
Have you considered moving to bit ops when modifying cmd_flags?
I guess you can also move the ->aborted bit into the bit field, and
could get rid of some of the spinlocks ...

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer
  2015-12-08  0:48 ` [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer Himanshu Madhani
  2015-12-08  2:48   ` Christoph Hellwig
@ 2015-12-09  7:02   ` Hannes Reinecke
  1 sibling, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-09  7:02 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> For kernel 3.15 and newer with TCM API change, add detection
> for TCM support of TAS.  Instead of default command terminate
> for LUN/TARGET reset error handling, allow SCSI status to go
> out if we know sequece Initiative is own by FW (cmd_sent_to_fw=0)
> 
> Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
>  drivers/scsi/qla2xxx/qla_target.c  |   36 +++++++++++++++++-------------------
>  drivers/scsi/qla2xxx/tcm_qla2xxx.c |   20 ++++++++++++++++++++
>  2 files changed, 37 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
> index 4d42b79..5fca846 100644
> --- a/drivers/scsi/qla2xxx/qla_target.c
> +++ b/drivers/scsi/qla2xxx/qla_target.c
> @@ -3239,36 +3239,34 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
>  	struct qla_tgt *tgt = cmd->tgt;
>  	struct scsi_qla_host *vha = tgt->vha;
>  	struct se_cmd *se_cmd = &cmd->se_cmd;
> -	unsigned long flags,refcount;
> +	unsigned long flags, refcount;
>  
>  	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
>  	    "qla_target(%d): terminating exchange for aborted cmd=%p "
>  	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
>  	    se_cmd->tag);
>  
> -    spin_lock_irqsave(&cmd->cmd_lock, flags);
> -    if (cmd->aborted) {
> -        spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +	spin_lock_irqsave(&cmd->cmd_lock, flags);
>  
> -        /* It's normal to see 2 calls in this path:
> -         *  1) XFER Rdy completion + CMD_T_ABORT
> -         *  2) TCM TMR - drain_state_list
> -         */
> -        refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
> -        ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
> -               "multiple abort. %p refcount %lx"
> -               "transport_state %x, t_state %x, se_cmd_flags %x \n",
> -               cmd, refcount,cmd->se_cmd.transport_state,
> -               cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
> +	if (cmd->aborted) {
> +		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> +		/* It's normal to see 2 calls in this path:
> +		 *  1) XFER Rdy completion + CMD_T_ABORT
> +		 *  2) TCM TMR - drain_state_list
> +		 */
> +		refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
> +		ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
> +		    "multiple abort. %p refcount %lx"
> +		    "transport_state %x, t_state %x, se_cmd_flags %x \n",
> +		    cmd, refcount, cmd->se_cmd.transport_state,
> +		    cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags);
>  
> -        return EIO;
> -    }
> +		return EIO;
> +	}
>  
>  	cmd->aborted = 1;
>  	cmd->cmd_flags |= BIT_6;
> -    spin_unlock_irqrestore(&cmd->cmd_lock, flags);
> -
> -	qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
> +	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
>  
>  	return 0;
>  }
> diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> index 842fcca..2e9c194 100644
> --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> @@ -617,6 +617,26 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
>  				struct qla_tgt_cmd, se_cmd);
>  	int xmit_type = QLA_TGT_XMIT_STATUS;
>  
> +	if (se_cmd->transport_state & CMD_T_ABORTED) {
> +		/* For TCM TAS support n kernel >= 3.15:
> +		 * This cmd is attempting to respond with "Task Aborted Status".
> +		 */
> +		if (cmd->aborted) {
> +			return 0;
> +		} else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
> +		    cmd->cmd_sent_to_fw) {
> +			qlt_abort_cmd(cmd);
> +			return 0;
> +		} else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
> +			if (cmd->cmd_sent_to_fw) {
> +				qlt_abort_cmd(cmd);
> +				return 0;
> +			} else {	/* about to be free */
> +				return 0;
> +			}
> +		}
> +	}
> +
>  	cmd->bufflen = se_cmd->data_length;
>  	cmd->sg = NULL;
>  	cmd->sg_cnt = 0;
> 
Reviewed-by: Hannes Reinecke <hare@suse.com>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)

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

* Re: [PATCH 12/20] target/tmr: LUN reset cause cmd premature free.
  2015-12-08  0:48 ` [PATCH 12/20] target/tmr: LUN reset cause cmd premature free Himanshu Madhani
  2015-12-08  2:48   ` Christoph Hellwig
@ 2015-12-09  7:03   ` Hannes Reinecke
  1 sibling, 0 replies; 51+ messages in thread
From: Hannes Reinecke @ 2015-12-09  7:03 UTC (permalink / raw)
  To: Himanshu Madhani, target-devel, nab; +Cc: giridhar.malavali, linux-scsi

On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
> From: Quinn Tran <quinn.tran@qlogic.com>
> 
> During LUN/Target reset, the TMR code attempt to intercept
> cmds and try to aborted them.  Current code assume cmds are
> always intercepted at the back end device.  The cleanup code
> would issue a "queue_status() & check_stop_free()" to terminate
> the command.  However, when a cmd is intercepted at the front
> end/Fabric layer, current code introduce premature free or
> cause Fabric to double free.
> 
> When command is intercepted at Fabric layer, it means a
> check_stop_free(cmd_kref--) has been called.  The extra
> check_stop_free in the Lun Reset cleanup code causes early
> free.  When a cmd in the Fabric layer is completed, the normal
> free code adds another another free which introduce a double free.
> 
> To fix the issue:
> - add a new flag/CMD_T_SENT_STATUS to track command that have
>  made it down to fabric layer after back end good/bad completion.
> - if cmd reach Fabric Layer at Lun Reset time, add an extra
>  cmd_kref count to prevent premature free.
> 
> Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
> ---
>  drivers/target/target_core_tmr.c       |   33 +++++++++++++++++++++++++++++++-
>  drivers/target/target_core_transport.c |   30 +++++++++++++++++++++++++++++
>  include/target/target_core_base.h      |    1 +
>  3 files changed, 63 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
> index 28fb301..41f8b57 100644
> --- a/drivers/target/target_core_tmr.c
> +++ b/drivers/target/target_core_tmr.c
> @@ -243,7 +243,9 @@ static void core_tmr_drain_state_list(
>  {
>  	LIST_HEAD(drain_task_list);
>  	struct se_cmd *cmd, *next;
> -	unsigned long flags;
> +	unsigned long flags, flags2;
> +	int rmkref;
> +	struct se_session *se_sess;
>  
>  	/*
>  	 * Complete outstanding commands with TASK_ABORTED SAM status.
> @@ -282,6 +284,16 @@ static void core_tmr_drain_state_list(
>  		if (prout_cmd == cmd)
>  			continue;
>  
> +		se_sess = cmd->se_sess;
> +		/* take an extra kref to prevent cmd free race condition. */
> +		spin_lock_irqsave(&se_sess->sess_cmd_lock, flags2);
> +		if (!kref_get_unless_zero(&cmd->cmd_kref)) {
> +			/* cmd is already in the free process */
> +			spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags2);
> +			continue;
> +		}
> +		spin_unlock_irqrestore(&se_sess->sess_cmd_lock,	flags2);
> +
>  		list_move_tail(&cmd->state_list, &drain_task_list);
>  		cmd->state_active = false;
>  	}
> @@ -320,9 +332,28 @@ static void core_tmr_drain_state_list(
>  		target_stop_cmd(cmd, &flags);
>  
>  		cmd->transport_state |= CMD_T_ABORTED;
> +
> +		/* CMD_T_SENT_STATUS: cmd is down in fabric layer.
> +		 * A check stop has been called.  Keep the extra kref
> +		 * from above because core_tmr_handle_tas_abort will
> +		 * generate another check_stop.
> +		 *
> +		 * !CMD_T_SENT_STATUS: cmd intercepted at back end.
> +		 * Remove the extra kref from above because only
> +		 * 1 check_stop is required or generated by
> +		 * core_tmr_handle_tas_abort()
> +		 */
> +		rmkref = 0;
> +		if (!((cmd->t_state == TRANSPORT_COMPLETE) &&
> +		    (cmd->transport_state & CMD_T_SENT_STATUS)))
> +			rmkref = 1;
> +
>  		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
>  
>  		core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
> +
> +		if (rmkref)
> +			target_put_sess_cmd(cmd);
>  	}
>  }
>  
> diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
> index 4fdcee2..cdd18bf 100644
> --- a/drivers/target/target_core_transport.c
> +++ b/drivers/target/target_core_transport.c
> @@ -639,9 +639,14 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
>  static void target_complete_failure_work(struct work_struct *work)
>  {
>  	struct se_cmd *cmd = container_of(work, struct se_cmd, work);
> +	unsigned long flags;
>  
>  	transport_generic_request_failure(cmd,
>  			TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);
> +
> +	spin_lock_irqsave(&cmd->t_state_lock, flags);
> +	cmd->transport_state |= CMD_T_SENT_STATUS;
> +	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
>  }
>  
>  /*
> @@ -1659,6 +1664,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
>  		sense_reason_t sense_reason)
>  {
>  	int ret = 0, post_ret = 0;
> +	unsigned long flags;
>  
>  	pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx"
>  		" CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]);
> @@ -1670,6 +1676,10 @@ void transport_generic_request_failure(struct se_cmd *cmd,
>  		(cmd->transport_state & CMD_T_STOP) != 0,
>  		(cmd->transport_state & CMD_T_SENT) != 0);
>  
> +	spin_lock_irqsave(&cmd->t_state_lock, flags);
> +	cmd->transport_state |= CMD_T_SENT_STATUS;
> +	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
> +
>  	/*
>  	 * For SAM Task Attribute emulation for failed struct se_cmd
>  	 */
> @@ -1951,6 +1961,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
>  static void transport_complete_qf(struct se_cmd *cmd)
>  {
>  	int ret = 0;
> +	unsigned long flags;
>  
>  	transport_complete_task_attr(cmd);
>  
> @@ -1986,6 +1997,10 @@ out:
>  	}
>  	transport_lun_remove_cmd(cmd);
>  	transport_cmd_check_stop_to_fabric(cmd);
> +
> +	spin_lock_irqsave(&cmd->t_state_lock, flags);
> +	cmd->transport_state |= CMD_T_SENT_STATUS;
> +	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
>  }
>  
>  static void transport_handle_queue_full(
> @@ -2032,6 +2047,7 @@ static void target_complete_ok_work(struct work_struct *work)
>  {
>  	struct se_cmd *cmd = container_of(work, struct se_cmd, work);
>  	int ret;
> +	unsigned long flags;
>  
>  	/*
>  	 * Check if we need to move delayed/dormant tasks from cmds on the
> @@ -2060,6 +2076,10 @@ static void target_complete_ok_work(struct work_struct *work)
>  
>  		transport_lun_remove_cmd(cmd);
>  		transport_cmd_check_stop_to_fabric(cmd);
> +
> +		spin_lock_irqsave(&cmd->t_state_lock, flags);
> +		cmd->transport_state |= CMD_T_SENT_STATUS;
> +		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
>  		return;
>  	}
>  	/*
> @@ -2086,6 +2106,11 @@ static void target_complete_ok_work(struct work_struct *work)
>  
>  			transport_lun_remove_cmd(cmd);
>  			transport_cmd_check_stop_to_fabric(cmd);
> +
> +			spin_lock_irqsave(&cmd->t_state_lock, flags);
> +			cmd->transport_state |= CMD_T_SENT_STATUS;
> +			spin_unlock_irqrestore(&cmd->t_state_lock, flags);
> +
>  			return;
>  		}
>  	}
> @@ -2136,6 +2161,7 @@ queue_rsp:
>  		ret = cmd->se_tfo->queue_status(cmd);
>  		if (ret == -EAGAIN || ret == -ENOMEM)
>  			goto queue_full;
> +
>  		break;
>  	default:
>  		break;
> @@ -2143,6 +2169,10 @@ queue_rsp:
>  
>  	transport_lun_remove_cmd(cmd);
>  	transport_cmd_check_stop_to_fabric(cmd);
> +
> +	spin_lock_irqsave(&cmd->t_state_lock, flags);
> +	cmd->transport_state |= CMD_T_SENT_STATUS;
> +	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
>  	return;
>  
>  queue_full:
> diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
> index aabf0ac..efccd71 100644
> --- a/include/target/target_core_base.h
> +++ b/include/target/target_core_base.h
> @@ -490,6 +490,7 @@ struct se_cmd {
>  #define CMD_T_DEV_ACTIVE	(1 << 7)
>  #define CMD_T_REQUEST_STOP	(1 << 8)
>  #define CMD_T_BUSY		(1 << 9)
> +#define CMD_T_SENT_STATUS (1 << 10)
>  	spinlock_t		t_state_lock;
>  	struct kref		cmd_kref;
>  	struct completion	t_transport_stop_comp;
> 
Same here: using bitops would save you taking the spinlock when
modifying flags.

Cheers,

Hannes
-- 
Dr. Hannes Reinecke		      zSeries & Storage
hare@suse.de			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 12/20] target/tmr: LUN reset cause cmd premature free.
  2015-12-08  2:48   ` Christoph Hellwig
@ 2015-12-09 20:11     ` Quinn Tran
  2016-01-04  7:44     ` Bart Van Assche
  1 sibling, 0 replies; 51+ messages in thread
From: Quinn Tran @ 2015-12-09 20:11 UTC (permalink / raw)
  To: Christoph Hellwig, Hannes Reinecke
  Cc: target-devel, nab, Giridhar Malavali, linux-scsi, Himanshu Madhani

[-- Attachment #1: Type: text/plain, Size: 1907 bytes --]

Christoph, 

Understood.  I was not sure which way the community is swinging.
For what it¹s worth, this fix was required to stabilize one of our
customer environment in the older kernel.

Regards,
Quinn Tran




On 12/7/15, 6:48 PM, "target-devel-owner@vger.kernel.org on behalf of
Christoph Hellwig" <target-devel-owner@vger.kernel.org on behalf of
hch@infradead.org> wrote:

>On Mon, Dec 07, 2015 at 07:48:59PM -0500, Himanshu Madhani wrote:
>> From: Quinn Tran <quinn.tran@qlogic.com>
>> 
>> During LUN/Target reset, the TMR code attempt to intercept
>> cmds and try to aborted them.  Current code assume cmds are
>> always intercepted at the back end device.  The cleanup code
>> would issue a "queue_status() & check_stop_free()" to terminate
>> the command.  However, when a cmd is intercepted at the front
>> end/Fabric layer, current code introduce premature free or
>> cause Fabric to double free.
>> 
>> When command is intercepted at Fabric layer, it means a
>> check_stop_free(cmd_kref--) has been called.  The extra
>> check_stop_free in the Lun Reset cleanup code causes early
>> free.  When a cmd in the Fabric layer is completed, the normal
>> free code adds another another free which introduce a double free.
>> 
>> To fix the issue:
>> - add a new flag/CMD_T_SENT_STATUS to track command that have
>>  made it down to fabric layer after back end good/bad completion.
>> - if cmd reach Fabric Layer at Lun Reset time, add an extra
>>  cmd_kref count to prevent premature free.
>
>This seems lke something solved by Bart's abort rewrite in a much nicer
>way.  All this special casing based on magic flags isn't maintainable
>in the long run.
>--
>To unsubscribe from this list: send the line "unsubscribe target-devel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 4974 bytes --]

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

* Re: [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer
  2015-12-08  2:48   ` Christoph Hellwig
@ 2015-12-09 20:24     ` Quinn Tran
  2015-12-14 10:37       ` Christoph Hellwig
  0 siblings, 1 reply; 51+ messages in thread
From: Quinn Tran @ 2015-12-09 20:24 UTC (permalink / raw)
  To: Christoph Hellwig, Himanshu Madhani
  Cc: target-devel, nab, Giridhar Malavali, linux-scsi

[-- Attachment #1: Type: text/plain, Size: 1572 bytes --]


On 12/7/15, 6:48 PM, "target-devel-owner@vger.kernel.org on behalf of
Christoph Hellwig" <target-devel-owner@vger.kernel.org on behalf of
hch@infradead.org> wrote:

>> diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>>b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>> index 842fcca..2e9c194 100644
>> --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>> +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>> @@ -617,6 +617,26 @@ static int tcm_qla2xxx_queue_status(struct se_cmd
>>*se_cmd)
>>  				struct qla_tgt_cmd, se_cmd);
>>  	int xmit_type = QLA_TGT_XMIT_STATUS;
>>  
>> +	if (se_cmd->transport_state & CMD_T_ABORTED) {
>> +		/* For TCM TAS support n kernel >= 3.15:
>> +		 * This cmd is attempting to respond with "Task Aborted Status".
>> +		 */
>> +		if (cmd->aborted) {
>> +			return 0;
>> +		} else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
>> +		    cmd->cmd_sent_to_fw) {
>> +			qlt_abort_cmd(cmd);
>> +			return 0;
>> +		} else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
>> +			if (cmd->cmd_sent_to_fw) {
>> +				qlt_abort_cmd(cmd);
>> +				return 0;
>> +			} else {	/* about to be free */
>> +				return 0;
>> +			}
>> +		}
>> +	}
>> +
>
>This is really something that should be explicitly communicated
>from the core instead of having to second guess it.

QT> The extra protection of the code here is to reduce erroneous error
message and interaction error with our firmware. I think communicating
back to the core at this stage might add undue complication.  It¹s best to
allow the initiator to re-drive the command at this point.


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 4717 bytes --]

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

* Re: [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  2015-12-08  2:37   ` Christoph Hellwig
@ 2015-12-09 22:07     ` Quinn Tran
  2015-12-14 10:34       ` Christoph Hellwig
  0 siblings, 1 reply; 51+ messages in thread
From: Quinn Tran @ 2015-12-09 22:07 UTC (permalink / raw)
  To: Christoph Hellwig, Himanshu Madhani
  Cc: target-devel, nab, Giridhar Malavali, linux-scsi

[-- Attachment #1: Type: text/plain, Size: 5041 bytes --]


On 12/7/15, 6:37 PM, "target-devel-owner@vger.kernel.org on behalf of
Christoph Hellwig" <target-devel-owner@vger.kernel.org on behalf of
hch@infradead.org> wrote:

>> -void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
>> +int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
>>  {
>>  	struct qla_tgt *tgt = cmd->tgt;
>>  	struct scsi_qla_host *vha = tgt->vha;
>>  	struct se_cmd *se_cmd = &cmd->se_cmd;
>> +	unsigned long flags,refcount;
>>  
>>  	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
>>  	    "qla_target(%d): terminating exchange for aborted cmd=%p "
>>  	    "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
>>  	    se_cmd->tag);
>>  
>> +    spin_lock_irqsave(&cmd->cmd_lock, flags);
>> +    if (cmd->aborted) {
>> +        spin_unlock_irqrestore(&cmd->cmd_lock, flags);
>> +
>> +        /* It's normal to see 2 calls in this path:
>> +         *  1) XFER Rdy completion + CMD_T_ABORT
>> +         *  2) TCM TMR - drain_state_list
>> +         */
>> +        refcount = atomic_read(&cmd->se_cmd.cmd_kref.refcount);
>> +        ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
>> +               "multiple abort. %p refcount %lx"
>> +               "transport_state %x, t_state %x, se_cmd_flags %x \n",
>> +               cmd, refcount,cmd->se_cmd.transport_state,
>> +               cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
>> +
>> +        return EIO;
>> +    }
>
>Err, no.  Looking into the refcount inside a kref is never the
>right thing to do.

QT> even for debug purpose??

>
>> +typedef enum {
>> +	/*
>> +	 * BIT_0 - Atio Arrival / schedule to work
>> +	 * BIT_1 - qlt_do_work
>> +	 * BIT_2 - qlt_do work failed
>> +	 * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
>> +	 * BIT_4 - read respond/tcm_qla2xx_queue_data_in
>> +	 * BIT_5 - status respond / tcm_qla2xx_queue_status
>> +	 * BIT_6 - tcm request to abort/Term exchange.
>> +	 *	pre_xmit_response->qlt_send_term_exchange
>> +	 * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
>> +	 * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
>> +	 * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
>> +	 * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
>> +
>> +	 * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
>> +	 * BIT_13 - Bad completion -
>> +	 *	qlt_ctio_do_completion --> qlt_term_ctio_exchange
>> +	 * BIT_14 - Back end data received/sent.
>> +	 * BIT_15 - SRR prepare ctio
>> +	 * BIT_16 - complete free
>> +	 * BIT_17 - flush - qlt_abort_cmd_on_host_reset
>> +	 * BIT_18 - completion w/abort status
>> +	 * BIT_19 - completion w/unknown status
>> +	 * BIT_20 - tcm_qla2xxx_free_cmd
>
>Please use descriptive names for these flags in the source code!

QT> ACK.  We¹ll change the bits to more descriptive name in a ³follow on²
patch.

>
>> +	BUG_ON(cmd->cmd_flags & BIT_20);
>> +	cmd->cmd_flags |= BIT_20;
>> +
>
>And no crazieness like this.  While we're at it: what synchronizes
>access to ->cmd_flags?

QT> These bits provide indication as to where the command has traversed in
the QLA code.  Each bit is set one time. Due to the async nature of the
TMR code, it triggers QLA driver to repeat this specific free path in the
double free case.  This BUG_ON allows us trap it early on.

In one of the corner case (below), I need to overloaded it + lock for the
cleanup process.

>
>> @@ -466,13 +484,25 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t
>>*vha, struct qla_tgt_cmd *cmd,
>>  static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
>>  {
>>  	struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd,
>>work);
>> +	unsigned long flags;
>>  
>>  	/*
>>  	 * Ensure that the complete FCP WRITE payload has been received.
>>  	 * Otherwise return an exception via CHECK_CONDITION status.
>>  	 */
>>  	cmd->cmd_in_wq = 0;
>> -	cmd->cmd_flags |= BIT_11;
>> +
>> +	spin_lock_irqsave(&cmd->cmd_lock, flags);
>> +	cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
>> +	if (cmd->aborted) {
>> +		cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
>> +		spin_unlock_irqrestore(&cmd->cmd_lock, flags);
>> +
>> +		tcm_qla2xxx_free_cmd(cmd);
>> +		return;
>> +	}
>> +	spin_unlock_irqrestore(&cmd->cmd_lock, flags);
>
>All these abort flag hacks look very suspicios.  Can you explain the
>exact theory of operation behind them?

QT> The cmd->aborted flag is used to track the CMD_T_ABORT flag at TCM
level.  If the command have been requested to be aborted by TCM or already
aborted, we advance it to the ³free" state because our hardware have
already started freeing up resources associated to this command/exchange.
In this specific case(above), a XFER RDY was aborted by the TMR.
Returning the cmd to TCM to generate SCSI Status would generate erroneous
HW error due to freed resource.


>
>--
>To unsubscribe from this list: send the line "unsubscribe target-devel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 6520 bytes --]

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

* Re: [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  2015-12-09  7:01   ` Hannes Reinecke
@ 2015-12-09 22:41     ` Quinn Tran
  0 siblings, 0 replies; 51+ messages in thread
From: Quinn Tran @ 2015-12-09 22:41 UTC (permalink / raw)
  To: Hannes Reinecke, Himanshu Madhani, target-devel, nab
  Cc: Giridhar Malavali, linux-scsi

Hannes,

ACK.  We¹ll move the flags to bitops in the "follow on" patch to clean it
up.  Those flags was introduced from a different patch. Will move the few
overloaded flag to bit field.

However, getting rid of the spin lock would prove tricky because the code
is trying to serialize the cleanup.  With out the lock, we kept hitting
multiple free problem.

Regards,
Quinn Tran




On 12/8/15, 11:01 PM, "target-devel-owner@vger.kernel.org on behalf of
Hannes Reinecke" <target-devel-owner@vger.kernel.org on behalf of
hare@suse.de> wrote:

>>+
>>  }
>>  
>>  static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
>Have you considered moving to bit ops when modifying cmd_flags?
>I guess you can also move the ->aborted bit into the bit field, and
>could get rid of some of the spinlocks ...
>
>Cheers,
>
>Hannes
>-- 
>Dr. Hannes Reinecke		      zSeries & Storage
>hare@suse.de			      +49 911 74053 688
>SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
>GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
>--

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

* Re: [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1
  2015-12-09  6:56   ` Hannes Reinecke
@ 2015-12-10  1:06     ` Quinn Tran
  0 siblings, 0 replies; 51+ messages in thread
From: Quinn Tran @ 2015-12-10  1:06 UTC (permalink / raw)
  To: Hannes Reinecke, Christoph Hellwig
  Cc: Giridhar Malavali, linux-scsi, target-devel, nab, Himanshu Madhani


On 12/8/15, 10:56 PM, "target-devel-owner@vger.kernel.org on behalf of
Hannes Reinecke" <target-devel-owner@vger.kernel.org on behalf of
hare@suse.de> wrote:

>On 12/08/2015 01:48 AM, Himanshu Madhani wrote:
>> From: Quinn Tran <quinn.tran@qlogic.com>
>> 
>> change tcm_qla2xxx_check_stop_free to always return 1
>> to prevent transport_cmd_finish_abort from accidently
>> taking extra kref_put.
>> 
>> Signed-off-by: Quinn Tran <quinn.tran@qlogic.com>
>> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com>
>> ---
>>  drivers/scsi/qla2xxx/tcm_qla2xxx.c |    3 ++-
>>  1 files changed, 2 insertions(+), 1 deletions(-)
>> 
>> diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>>b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>> index 74c6e9b..366142a 100644
>> --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>> +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
>> @@ -314,7 +314,8 @@ static int tcm_qla2xxx_check_stop_free(struct
>>se_cmd *se_cmd)
>>  		cmd->cmd_flags |= BIT_14;
>>  	}
>>  
>> -	return target_put_sess_cmd(se_cmd);
>> +	target_put_sess_cmd(se_cmd);
>> +	return 1;
>>  }
>>  
>>  /* tcm_qla2xxx_release_cmd - Callback from TCM Core to release
>>underlying
>> 
>Odd. I would have expected target_put_sess_cmd() to never fail.

QT> It does not failed under normal usage.

>But if it does, doesn't it mean that the command is hosed, and we should
>have accessed it in the first place?
>Very suspicious.

QT> here are the cases I see.  Note: The patch series is in reference of
pre-Bart¹s fix.

- cmd_kref 2 -> 1, target_put_sess_cmd return true. This is Normal case.
Backend finished with the command and send it to the Front end.

- cmd_kref 1 -> 0, target_put_sess_cmd return true.
Case 1: Early free by TCM/TMR thread.  TMR thread call 2nd check_stop.

core_tmr_drain_tmr_list->transport_cmd_finish_abort->
transport_cmd_check_stop_to_fabric

- cmd_kref 0 -> -1, target_put_sess_cmd return false.   QLA does not call
³check_stop² in either cases below.
Case 1: QLA cause double free the command as the command is coming out of
HW queue. In other word QLA access stale pointer during cleanup/free.
Case 2: QLA driver beat TMR thread by a few nano second by freeing the
command 1st(cmd_kref=0).  TMR thread call the extra check_stop(cmd_kref =
-1).  transport_cmd_finish_abort do additional kref_put (cmd_kref = -2).

void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
{
    if (transport_cmd_check_stop_to_fabric(cmd))
        return;
    if (remove)
        transport_put_cmd(cmd);
}




>
>Cheers,
>
>Hannes
>-- 
>Dr. Hannes Reinecke		      zSeries & Storage
>hare@suse.de			      +49 911 74053 688
>SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
>GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
>--
>To unsubscribe from this list: send the line "unsubscribe target-devel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  2015-12-09 22:07     ` Quinn Tran
@ 2015-12-14 10:34       ` Christoph Hellwig
  2015-12-14 21:59         ` Quinn Tran
  0 siblings, 1 reply; 51+ messages in thread
From: Christoph Hellwig @ 2015-12-14 10:34 UTC (permalink / raw)
  To: Quinn Tran
  Cc: Christoph Hellwig, Himanshu Madhani, target-devel, nab,
	Giridhar Malavali, linux-scsi

On Wed, Dec 09, 2015 at 10:07:32PM +0000, Quinn Tran wrote:
> >Err, no.  Looking into the refcount inside a kref is never the
> >right thing to do.
> 
> QT> even for debug purpose??

No.  Please treat struct kref as opaque.

> QT> These bits provide indication as to where the command has traversed in
> the QLA code.  Each bit is set one time. Due to the async nature of the
> TMR code, it triggers QLA driver to repeat this specific free path in the
> double free case.  This BUG_ON allows us trap it early on.
> 
> In one of the corner case (below), I need to overloaded it + lock for the
> cleanup process.

Setting bits fundamentaly is a read/modify/write cycle.  You either
need to use {set,clear,test}_bit or lock around these manipulations.

> QT> The cmd->aborted flag is used to track the CMD_T_ABORT flag at TCM
> level.  If the command have been requested to be aborted by TCM or already
> aborted, we advance it to the ?free" state because our hardware have
> already started freeing up resources associated to this command/exchange.
> In this specific case(above), a XFER RDY was aborted by the TMR.
> Returning the cmd to TCM to generate SCSI Status would generate erroneous
> HW error due to freed resource.

I really think this nees to be updated on top of Bat's changes as a
start and re-reviewed.  The amoutn of special casing and second guessing
here is simply not sustainable in the long run.

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

* Re: [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer
  2015-12-09 20:24     ` Quinn Tran
@ 2015-12-14 10:37       ` Christoph Hellwig
  2015-12-14 22:00         ` Quinn Tran
  0 siblings, 1 reply; 51+ messages in thread
From: Christoph Hellwig @ 2015-12-14 10:37 UTC (permalink / raw)
  To: Quinn Tran
  Cc: Christoph Hellwig, Himanshu Madhani, target-devel, nab,
	Giridhar Malavali, linux-scsi

On Wed, Dec 09, 2015 at 08:24:57PM +0000, Quinn Tran wrote:
> >> +	if (se_cmd->transport_state & CMD_T_ABORTED) {
> >> +		/* For TCM TAS support n kernel >= 3.15:
> >> +		 * This cmd is attempting to respond with "Task Aborted Status".
> >> +		 */
> >> +		if (cmd->aborted) {
> >> +			return 0;
> >> +		} else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
> >> +		    cmd->cmd_sent_to_fw) {
> >> +			qlt_abort_cmd(cmd);
> >> +			return 0;
> >> +		} else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
> >> +			if (cmd->cmd_sent_to_fw) {
> >> +				qlt_abort_cmd(cmd);
> >> +				return 0;
> >> +			} else {	/* about to be free */
> >> +				return 0;
> >> +			}
> >> +		}
> >> +	}
> >> +
> >
> >This is really something that should be explicitly communicated
> >from the core instead of having to second guess it.
> 
> QT> The extra protection of the code here is to reduce erroneous error
> message and interaction error with our firmware. I think communicating
> back to the core at this stage might add undue complication.  It?s best to
> allow the initiator to re-drive the command at this point.

I agree with that statement, just not how it's done.  Having parallel
command state machines in the driver and core isn't something that's
maintainable.  We need to attack the root cause instead of trying
to hack around it in drivers.

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

* Re: [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  2015-12-14 10:34       ` Christoph Hellwig
@ 2015-12-14 21:59         ` Quinn Tran
  0 siblings, 0 replies; 51+ messages in thread
From: Quinn Tran @ 2015-12-14 21:59 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Himanshu Madhani, target-devel, nab, Giridhar Malavali, linux-scsi

[-- Attachment #1: Type: text/plain, Size: 1716 bytes --]

Christoph,  Thanks for reviewing.  I¹ll withdraw this patch.  Will rework
with new code and submit at a later time.

Regards,
Quinn Tran




On 12/14/15, 2:34 AM, "Christoph Hellwig" <hch@infradead.org> wrote:

>On Wed, Dec 09, 2015 at 10:07:32PM +0000, Quinn Tran wrote:
>> >Err, no.  Looking into the refcount inside a kref is never the
>> >right thing to do.
>> 
>> QT> even for debug purpose??
>
>No.  Please treat struct kref as opaque.
>
>> QT> These bits provide indication as to where the command has traversed
>>in
>> the QLA code.  Each bit is set one time. Due to the async nature of the
>> TMR code, it triggers QLA driver to repeat this specific free path in
>>the
>> double free case.  This BUG_ON allows us trap it early on.
>> 
>> In one of the corner case (below), I need to overloaded it + lock for
>>the
>> cleanup process.
>
>Setting bits fundamentaly is a read/modify/write cycle.  You either
>need to use {set,clear,test}_bit or lock around these manipulations.
>
>> QT> The cmd->aborted flag is used to track the CMD_T_ABORT flag at TCM
>> level.  If the command have been requested to be aborted by TCM or
>>already
>> aborted, we advance it to the ?free" state because our hardware have
>> already started freeing up resources associated to this
>>command/exchange.
>> In this specific case(above), a XFER RDY was aborted by the TMR.
>> Returning the cmd to TCM to generate SCSI Status would generate
>>erroneous
>> HW error due to freed resource.
>
>I really think this nees to be updated on top of Bat's changes as a
>start and re-reviewed.  The amoutn of special casing and second guessing
>here is simply not sustainable in the long run.


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 5204 bytes --]

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

* Re: [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer
  2015-12-14 10:37       ` Christoph Hellwig
@ 2015-12-14 22:00         ` Quinn Tran
  0 siblings, 0 replies; 51+ messages in thread
From: Quinn Tran @ 2015-12-14 22:00 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Himanshu Madhani, target-devel, nab, Giridhar Malavali, linux-scsi

[-- Attachment #1: Type: text/plain, Size: 1633 bytes --]

Christoph,  Thanks for reviewing.  I¹ll withdraw this patch.  Will rework
with new code and submit at a later time.



Regards,
Quinn Tran




On 12/14/15, 2:37 AM, "Christoph Hellwig" <hch@infradead.org> wrote:

>On Wed, Dec 09, 2015 at 08:24:57PM +0000, Quinn Tran wrote:
>> >> +	if (se_cmd->transport_state & CMD_T_ABORTED) {
>> >> +		/* For TCM TAS support n kernel >= 3.15:
>> >> +		 * This cmd is attempting to respond with "Task Aborted Status".
>> >> +		 */
>> >> +		if (cmd->aborted) {
>> >> +			return 0;
>> >> +		} else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
>> >> +		    cmd->cmd_sent_to_fw) {
>> >> +			qlt_abort_cmd(cmd);
>> >> +			return 0;
>> >> +		} else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
>> >> +			if (cmd->cmd_sent_to_fw) {
>> >> +				qlt_abort_cmd(cmd);
>> >> +				return 0;
>> >> +			} else {	/* about to be free */
>> >> +				return 0;
>> >> +			}
>> >> +		}
>> >> +	}
>> >> +
>> >
>> >This is really something that should be explicitly communicated
>> >from the core instead of having to second guess it.
>> 
>> QT> The extra protection of the code here is to reduce erroneous error
>> message and interaction error with our firmware. I think communicating
>> back to the core at this stage might add undue complication.  It?s best
>>to
>> allow the initiator to re-drive the command at this point.
>
>I agree with that statement, just not how it's done.  Having parallel
>command state machines in the driver and core isn't something that's
>maintainable.  We need to attack the root cause instead of trying
>to hack around it in drivers.


[-- Attachment #2: winmail.dat --]
[-- Type: application/ms-tnef, Size: 4941 bytes --]

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

* Re: [PATCH 12/20] target/tmr: LUN reset cause cmd premature free.
  2015-12-08  2:48   ` Christoph Hellwig
  2015-12-09 20:11     ` Quinn Tran
@ 2016-01-04  7:44     ` Bart Van Assche
  1 sibling, 0 replies; 51+ messages in thread
From: Bart Van Assche @ 2016-01-04  7:44 UTC (permalink / raw)
  To: Christoph Hellwig, Himanshu Madhani
  Cc: target-devel, nab, giridhar.malavali, linux-scsi

On 12/08/2015 03:48 AM, Christoph Hellwig wrote:
> On Mon, Dec 07, 2015 at 07:48:59PM -0500, Himanshu Madhani wrote:
>> From: Quinn Tran <quinn.tran@qlogic.com>
>>
>> During LUN/Target reset, the TMR code attempt to intercept
>> cmds and try to aborted them.  Current code assume cmds are
>> always intercepted at the back end device.  The cleanup code
>> would issue a "queue_status() & check_stop_free()" to terminate
>> the command.  However, when a cmd is intercepted at the front
>> end/Fabric layer, current code introduce premature free or
>> cause Fabric to double free.
>>
>> When command is intercepted at Fabric layer, it means a
>> check_stop_free(cmd_kref--) has been called.  The extra
>> check_stop_free in the Lun Reset cleanup code causes early
>> free.  When a cmd in the Fabric layer is completed, the normal
>> free code adds another another free which introduce a double free.
>>
>> To fix the issue:
>> - add a new flag/CMD_T_SENT_STATUS to track command that have
>>   made it down to fabric layer after back end good/bad completion.
>> - if cmd reach Fabric Layer at Lun Reset time, add an extra
>>   cmd_kref count to prevent premature free.
>
> This seems lke something solved by Bart's abort rewrite in a much nicer
> way.  All this special casing based on magic flags isn't maintainable
> in the long run.

Hello Himanshu and Christoph,

I am currently working on addressing the review comments on my target 
core patch series and will repost that patch series this week.

Bart.

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

end of thread, other threads:[~2016-01-04  7:44 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-08  0:48 [PATCH 00/20] qla2xxx: Patches for target-pending branch Himanshu Madhani
2015-12-08  0:48 ` [PATCH 01/20] qla2xxx: Enable Extended Login support Himanshu Madhani
2015-12-08 15:51   ` Hannes Reinecke
2015-12-08 19:35     ` Himanshu Madhani
2015-12-08  0:48 ` [PATCH 02/20] qla2xxx: Enable Exchange offload support Himanshu Madhani
2015-12-08 15:52   ` Hannes Reinecke
2015-12-08  0:48 ` [PATCH 03/20] qla2xxx: Enable Target counters in DebugFS Himanshu Madhani
2015-12-08 15:52   ` Hannes Reinecke
2015-12-08  0:48 ` [PATCH 04/20] qla2xxx: Add FW resource count " Himanshu Madhani
2015-12-08 15:53   ` Hannes Reinecke
2015-12-08  0:48 ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Himanshu Madhani
2015-12-08  2:10   ` kbuild test robot
2015-12-08  2:10   ` [PATCH] qla2xxx: fix ifnullfree.cocci warnings kbuild test robot
2015-12-08 15:54   ` [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver Hannes Reinecke
2015-12-08  0:48 ` [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW Himanshu Madhani
2015-12-08  1:41   ` kbuild test robot
2015-12-08 15:58   ` Hannes Reinecke
2015-12-08  0:48 ` [PATCH 07/20] qla2xxx: Wait for all conflicts before ack'ing PLOGI Himanshu Madhani
2015-12-08 16:00   ` Hannes Reinecke
2015-12-08  0:48 ` [PATCH 08/20] qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit Himanshu Madhani
2015-12-08 16:01   ` Hannes Reinecke
2015-12-08  0:48 ` [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1 Himanshu Madhani
2015-12-08  2:33   ` Christoph Hellwig
2015-12-09  6:56   ` Hannes Reinecke
2015-12-10  1:06     ` Quinn Tran
2015-12-08  0:48 ` [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module Himanshu Madhani
2015-12-08  2:37   ` Christoph Hellwig
2015-12-09 22:07     ` Quinn Tran
2015-12-14 10:34       ` Christoph Hellwig
2015-12-14 21:59         ` Quinn Tran
2015-12-09  7:01   ` Hannes Reinecke
2015-12-09 22:41     ` Quinn Tran
2015-12-08  0:48 ` [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer Himanshu Madhani
2015-12-08  2:48   ` Christoph Hellwig
2015-12-09 20:24     ` Quinn Tran
2015-12-14 10:37       ` Christoph Hellwig
2015-12-14 22:00         ` Quinn Tran
2015-12-09  7:02   ` Hannes Reinecke
2015-12-08  0:48 ` [PATCH 12/20] target/tmr: LUN reset cause cmd premature free Himanshu Madhani
2015-12-08  2:48   ` Christoph Hellwig
2015-12-09 20:11     ` Quinn Tran
2016-01-04  7:44     ` Bart Van Assche
2015-12-09  7:03   ` Hannes Reinecke
2015-12-08  0:49 ` [PATCH 13/20] qla2xxx: Remove dependency on hardware_lock to reduce lock contention Himanshu Madhani
2015-12-08  0:49 ` [PATCH 14/20] qla2xxx: Add irq affinity notification Himanshu Madhani
2015-12-08  0:49 ` [PATCH 15/20] qla2xxx: Add selective command queuing Himanshu Madhani
2015-12-08  0:49 ` [PATCH 16/20] qla2xxx: Move atioq to a different lock to reduce lock contention Himanshu Madhani
2015-12-08  0:49 ` [PATCH 17/20] qla2xxx: Disable ZIO at start time Himanshu Madhani
2015-12-08  0:49 ` [PATCH 18/20] qla2xxx: Set all queues to 4k Himanshu Madhani
2015-12-08  0:49 ` [PATCH 19/20] qla2xxx: Add bulk send for atio & ctio completion paths Himanshu Madhani
2015-12-08  0:49 ` [PATCH 20/20] qla2xxx: Check for online flag instead of active reset when transmitting responses Himanshu Madhani

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.