All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] qla2xxx driver enhancements
@ 2021-01-05  6:03 Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

Martin,

Please apply the qla2xxx driver enhancements to the scsi tree at your
earliest convenience.

v2:
Fix warning reported by kernel test robot.

Thanks,
Nilesh

Bikash Hazarika (1):
  qla2xxx: Wait for ABTS response on I/O timeouts for NVMe

Nilesh Javali (1):
  qla2xxx: Update version to 10.02.00.105-k

Quinn Tran (1):
  qla2xxx: Fix mailbox Ch erroneous error

Saurav Kashyap (4):
  qla2xxx: Implementation to get and manage host, target stats and
    initiator port
  qla2xxx: Add error counters to debugfs node
  qla2xxx: Move some messages from debug to normal log level
  qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER

 drivers/scsi/qla2xxx/qla_attr.c    |   9 +
 drivers/scsi/qla2xxx/qla_bsg.c     | 342 +++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_bsg.h     |   5 +
 drivers/scsi/qla2xxx/qla_dbg.c     |   1 +
 drivers/scsi/qla2xxx/qla_def.h     |  83 +++++++
 drivers/scsi/qla2xxx/qla_dfs.c     |  28 +++
 drivers/scsi/qla2xxx/qla_fw.h      |  27 ++-
 drivers/scsi/qla2xxx/qla_gbl.h     |  29 +++
 drivers/scsi/qla2xxx/qla_gs.c      |   1 +
 drivers/scsi/qla2xxx/qla_init.c    | 230 ++++++++++++++++++-
 drivers/scsi/qla2xxx/qla_iocb.c    |   8 +
 drivers/scsi/qla2xxx/qla_isr.c     |  82 ++++---
 drivers/scsi/qla2xxx/qla_mbx.c     |  18 +-
 drivers/scsi/qla2xxx/qla_nvme.c    |  90 +++++++-
 drivers/scsi/qla2xxx/qla_os.c      |  25 +++
 drivers/scsi/qla2xxx/qla_version.h |   4 +-
 16 files changed, 942 insertions(+), 40 deletions(-)


base-commit: be1b500212541a70006887bae558ff834d7365d0
-- 
2.19.0.rc0


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

* [PATCH v2 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port
  2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
@ 2021-01-05  6:03 ` Nilesh Javali
  2021-01-05  6:11   ` Saurav Kashyap
  2021-01-05  6:03 ` [PATCH v2 2/7] qla2xxx: Add error counters to debugfs node Nilesh Javali
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

From: Saurav Kashyap <skashyap@marvell.com>

This statistics will help in debugging process and checking specific
error counts.

Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Reported-by: kernel test robot <lkp@intel.com>
---
 drivers/scsi/qla2xxx/qla_attr.c |   9 +
 drivers/scsi/qla2xxx/qla_bsg.c  | 342 ++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_bsg.h  |   5 +
 drivers/scsi/qla2xxx/qla_def.h  |  71 +++++++
 drivers/scsi/qla2xxx/qla_gbl.h  |  23 +++
 drivers/scsi/qla2xxx/qla_gs.c   |   1 +
 drivers/scsi/qla2xxx/qla_init.c | 216 ++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_isr.c  |  22 ++
 drivers/scsi/qla2xxx/qla_mbx.c  |   9 +
 drivers/scsi/qla2xxx/qla_os.c   |  20 ++
 10 files changed, 718 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index ab45ac1e5a72..63391c9be05d 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -710,6 +710,12 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
 		ql_log(ql_log_info, vha, 0x706e,
 		    "Issuing ISP reset.\n");
 
+		if (vha->hw->flags.port_isolated) {
+			ql_log(ql_log_info, vha, 0x706e,
+			       "Port is isolated, returning.\n");
+			return -EINVAL;
+		}
+
 		scsi_block_requests(vha->host);
 		if (IS_QLA82XX(ha)) {
 			ha->flags.isp82xx_no_md_cap = 1;
@@ -2717,6 +2723,9 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
 	if (IS_QLAFX00(vha->hw))
 		return 0;
 
+	if (vha->hw->flags.port_isolated)
+		return 0;
+
 	qla2x00_loop_reset(vha);
 	return 0;
 }
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 23b604832a54..fb65e6f79e49 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -4,6 +4,7 @@
  * Copyright (c)  2003-2014 QLogic Corporation
  */
 #include "qla_def.h"
+#include "qla_gbl.h"
 
 #include <linux/kthread.h>
 #include <linux/vmalloc.h>
@@ -2444,6 +2445,323 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
 	return 0;
 }
 
+static int
+qla2x00_manage_host_stats(struct bsg_job *bsg_job)
+{
+	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct ql_vnd_mng_host_stats_param *req_data;
+	struct ql_vnd_mng_host_stats_resp rsp_data;
+	u32 req_data_len;
+	int ret = 0;
+
+	if (!vha->flags.online) {
+		ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n");
+		return -EIO;
+	}
+
+	req_data_len = bsg_job->request_payload.payload_len;
+
+	if (req_data_len != sizeof(struct ql_vnd_mng_host_stats_param)) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
+		return -EIO;
+	}
+
+	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
+	if (!req_data) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");
+		return -ENOMEM;
+	}
+
+	/* Copy the request buffer in req_data */
+	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+			  bsg_job->request_payload.sg_cnt, req_data,
+			  req_data_len);
+
+	switch (req_data->action) {
+	case 0:
+		ret = qla2xxx_stop_stats(vha->host, req_data->stat_type);
+		break;
+	case 1:
+		ret = qla2xxx_start_stats(vha->host, req_data->stat_type);
+		break;
+	case 2:
+		ret = qla2xxx_reset_stats(vha->host, req_data->stat_type);
+		break;
+	default:
+		ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n");
+		ret = -EIO;
+		break;
+	}
+
+	kfree(req_data);
+
+	/* Prepare response */
+	rsp_data.status = ret;
+	bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp);
+
+	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+	bsg_reply->reply_payload_rcv_len =
+		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+				    bsg_job->reply_payload.sg_cnt,
+				    &rsp_data,
+				    sizeof(struct ql_vnd_mng_host_stats_resp));
+
+	bsg_reply->result = DID_OK;
+	bsg_job_done(bsg_job, bsg_reply->result,
+		     bsg_reply->reply_payload_rcv_len);
+
+	return ret;
+}
+
+static int
+qla2x00_get_host_stats(struct bsg_job *bsg_job)
+{
+	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct ql_vnd_stats_param *req_data;
+	struct ql_vnd_host_stats_resp rsp_data;
+	u32 req_data_len;
+	int ret = 0;
+	u64 ini_entry_count = 0;
+	u64 entry_count = 0;
+	u64 tgt_num = 0;
+	u64 tmp_stat_type = 0;
+	u64 response_len = 0;
+	void *data;
+
+	req_data_len = bsg_job->request_payload.payload_len;
+
+	if (req_data_len != sizeof(struct ql_vnd_stats_param)) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
+		return -EIO;
+	}
+
+	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
+	if (!req_data) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");
+		return -ENOMEM;
+	}
+
+	/* Copy the request buffer in req_data */
+	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+			  bsg_job->request_payload.sg_cnt, req_data, req_data_len);
+
+	/* Copy stat type to work on it */
+	tmp_stat_type = req_data->stat_type;
+
+	if (tmp_stat_type & QLA2XX_TGT_SHT_LNK_DOWN) {
+		/* Num of tgts connected to this host */
+		tgt_num = qla2x00_get_num_tgts(vha);
+		/* unset BIT_17 */
+		tmp_stat_type &= ~(1 << 17);
+	}
+
+	/* Total ini stats */
+	ini_entry_count = qla2x00_count_set_bits(tmp_stat_type);
+
+	/* Total number of entries */
+	entry_count = ini_entry_count + tgt_num;
+
+	response_len = sizeof(struct ql_vnd_host_stats_resp) +
+		(sizeof(struct ql_vnd_stat_entry) * entry_count);
+
+	if (response_len > bsg_job->reply_payload.payload_len) {
+		rsp_data.status = EXT_STATUS_BUFFER_TOO_SMALL;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_BUFFER_TOO_SMALL;
+		bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp);
+
+		bsg_reply->reply_payload_rcv_len =
+			sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+					    bsg_job->reply_payload.sg_cnt, &rsp_data,
+					    sizeof(struct ql_vnd_mng_host_stats_resp));
+
+		bsg_reply->result = DID_OK;
+		bsg_job_done(bsg_job, bsg_reply->result,
+			     bsg_reply->reply_payload_rcv_len);
+		goto host_stat_out;
+	}
+
+	data = kzalloc(response_len, GFP_KERNEL);
+
+	ret = qla2xxx_get_ini_stats(fc_bsg_to_shost(bsg_job), req_data->stat_type,
+				    data, response_len);
+
+	rsp_data.status = EXT_STATUS_OK;
+	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+
+	bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+							       bsg_job->reply_payload.sg_cnt,
+							       data, response_len);
+	bsg_reply->result = DID_OK;
+	bsg_job_done(bsg_job, bsg_reply->result,
+		     bsg_reply->reply_payload_rcv_len);
+
+	kfree(data);
+host_stat_out:
+	kfree(req_data);
+	return ret;
+}
+
+static struct fc_rport *
+qla2xxx_find_rport(scsi_qla_host_t *vha, uint32_t tgt_num)
+{
+	fc_port_t *fcport = NULL;
+
+	list_for_each_entry(fcport, &vha->vp_fcports, list) {
+		if (fcport->rport->number == tgt_num)
+			return fcport->rport;
+	}
+	return NULL;
+}
+
+static int
+qla2x00_get_tgt_stats(struct bsg_job *bsg_job)
+{
+	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct ql_vnd_tgt_stats_param *req_data;
+	u32 req_data_len;
+	int ret = 0;
+	u64 response_len = 0;
+	struct ql_vnd_tgt_stats_resp *data = NULL;
+	struct fc_rport *rport = NULL;
+
+	if (!vha->flags.online) {
+		ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n");
+		return -EIO;
+	}
+
+	req_data_len = bsg_job->request_payload.payload_len;
+
+	if (req_data_len != sizeof(struct ql_vnd_stat_entry)) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
+		return -EIO;
+	}
+
+	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
+	if (!req_data) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");
+		return -ENOMEM;
+	}
+
+	/* Copy the request buffer in req_data */
+	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+			  bsg_job->request_payload.sg_cnt,
+			  req_data, req_data_len);
+
+	response_len = sizeof(struct ql_vnd_tgt_stats_resp) +
+		sizeof(struct ql_vnd_stat_entry);
+
+	if (response_len > bsg_job->reply_payload.payload_len) {
+		data->status = EXT_STATUS_BUFFER_TOO_SMALL;
+		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_BUFFER_TOO_SMALL;
+		bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_stats_resp);
+
+		bsg_reply->reply_payload_rcv_len =
+			sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+					    bsg_job->reply_payload.sg_cnt, &data,
+					    sizeof(struct ql_vnd_tgt_stats_resp));
+
+		bsg_reply->result = DID_OK;
+		bsg_job_done(bsg_job, bsg_reply->result,
+			     bsg_reply->reply_payload_rcv_len);
+		goto tgt_stat_out;
+	}
+
+	/* structure + size for one entry */
+	data = kzalloc(response_len, GFP_KERNEL);
+	if (!data) {
+		kfree(req_data);
+		return -ENOMEM;
+	}
+
+	rport = qla2xxx_find_rport(vha, req_data->tgt_id);
+	if (!rport) {
+		ql_log(ql_log_warn, vha, 0x0000, "target %d not found.\n", req_data->tgt_id);
+		ret = EXT_STATUS_INVALID_PARAM;
+		data->status = EXT_STATUS_INVALID_PARAM;
+		goto reply;
+	}
+
+	ret = qla2xxx_get_tgt_stats(fc_bsg_to_shost(bsg_job), req_data->stat_type,
+				    rport, (void *)data, response_len);
+
+	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+reply:
+	bsg_reply->reply_payload_rcv_len =
+		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+				    bsg_job->reply_payload.sg_cnt, data,
+				    response_len);
+	bsg_reply->result = DID_OK;
+	bsg_job_done(bsg_job, bsg_reply->result,
+		     bsg_reply->reply_payload_rcv_len);
+
+	kfree(data);
+tgt_stat_out:
+	kfree(req_data);
+
+	return ret;
+}
+
+static int
+qla2x00_manage_host_port(struct bsg_job *bsg_job)
+{
+	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
+	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+	struct ql_vnd_mng_host_port_param *req_data;
+	struct ql_vnd_mng_host_port_resp rsp_data;
+	u32 req_data_len;
+	int ret = 0;
+
+	req_data_len = bsg_job->request_payload.payload_len;
+
+	if (req_data_len != sizeof(struct ql_vnd_mng_host_port_param)) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
+		return -EIO;
+	}
+
+	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
+	if (!req_data) {
+		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation failure.\n");
+		return -ENOMEM;
+	}
+
+	/* Copy the request buffer in req_data */
+	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+			  bsg_job->request_payload.sg_cnt, req_data, req_data_len);
+
+	switch (req_data->action) {
+	case 0:
+		ret = qla2xxx_enable_port(vha->host);
+		break;
+	case 1:
+		ret = qla2xxx_disable_port(vha->host);
+		break;
+	default:
+		ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n");
+		ret = -EIO;
+		break;
+	}
+
+	kfree(req_data);
+
+	/* Prepare response */
+	rsp_data.status = ret;
+	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+	bsg_job->reply_payload.payload_len = sizeof(struct ql_vnd_mng_host_port_resp);
+
+	bsg_reply->reply_payload_rcv_len =
+		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+				    bsg_job->reply_payload.sg_cnt, &rsp_data,
+				    sizeof(struct ql_vnd_mng_host_port_resp));
+	bsg_reply->result = DID_OK;
+	bsg_job_done(bsg_job, bsg_reply->result,
+		     bsg_reply->reply_payload_rcv_len);
+
+	return ret;
+}
+
 static int
 qla2x00_process_vendor_specific(struct bsg_job *bsg_job)
 {
@@ -2520,6 +2838,18 @@ qla2x00_process_vendor_specific(struct bsg_job *bsg_job)
 	case QL_VND_SS_GET_FLASH_IMAGE_STATUS:
 		return qla2x00_get_flash_image_status(bsg_job);
 
+	case QL_VND_MANAGE_HOST_STATS:
+		return qla2x00_manage_host_stats(bsg_job);
+
+	case QL_VND_GET_HOST_STATS:
+		return qla2x00_get_host_stats(bsg_job);
+
+	case QL_VND_GET_TGT_STATS:
+		return qla2x00_get_tgt_stats(bsg_job);
+
+	case QL_VND_MANAGE_HOST_PORT:
+		return qla2x00_manage_host_port(bsg_job);
+
 	default:
 		return -ENOSYS;
 	}
@@ -2547,6 +2877,17 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
 		vha = shost_priv(host);
 	}
 
+	/* Disable port will bring down the chip, allow enable command */
+	if (bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_MANAGE_HOST_PORT ||
+	    bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_GET_HOST_STATS)
+		goto skip_chip_chk;
+
+	if (vha->hw->flags.port_isolated) {
+		bsg_reply->result = DID_ERROR;
+		/* operation not permitted */
+		return -EPERM;
+	}
+
 	if (qla2x00_chip_is_down(vha)) {
 		ql_dbg(ql_dbg_user, vha, 0x709f,
 		    "BSG: ISP abort active/needed -- cmd=%d.\n",
@@ -2554,6 +2895,7 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
 		return -EBUSY;
 	}
 
+skip_chip_chk:
 	ql_dbg(ql_dbg_user, vha, 0x7000,
 	    "Entered %s msgcode=0x%x.\n", __func__, bsg_request->msgcode);
 
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index 1a09b5512267..0274e99e4a12 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -31,6 +31,10 @@
 #define QL_VND_DPORT_DIAGNOSTICS	0x19
 #define QL_VND_GET_PRIV_STATS_EX	0x1A
 #define QL_VND_SS_GET_FLASH_IMAGE_STATUS	0x1E
+#define QL_VND_MANAGE_HOST_STATS	0x23
+#define QL_VND_GET_HOST_STATS		0x24
+#define QL_VND_GET_TGT_STATS		0x25
+#define QL_VND_MANAGE_HOST_PORT		0x26
 
 /* BSG Vendor specific subcode returns */
 #define EXT_STATUS_OK			0
@@ -40,6 +44,7 @@
 #define EXT_STATUS_DATA_OVERRUN		7
 #define EXT_STATUS_DATA_UNDERRUN	8
 #define EXT_STATUS_MAILBOX		11
+#define EXT_STATUS_BUFFER_TOO_SMALL	16
 #define EXT_STATUS_NO_MEMORY		17
 #define EXT_STATUS_DEVICE_OFFLINE	22
 
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 30c7e5e63851..f2f1b0231033 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2557,6 +2557,10 @@ typedef struct fc_port {
 	u16 n2n_chip_reset;
 
 	struct dentry *dfs_rport_dir;
+
+	u64 tgt_short_link_down_cnt;
+	u64 tgt_link_down_time;
+	u64 dev_loss_tmo;
 } fc_port_t;
 
 enum {
@@ -3922,6 +3926,7 @@ struct qla_hw_data {
 		uint32_t	scm_enabled:1;
 		uint32_t	max_req_queue_warned:1;
 		uint32_t	plogi_template_valid:1;
+		uint32_t	port_isolated:1;
 	} flags;
 
 	uint16_t max_exchg;
@@ -4851,6 +4856,13 @@ typedef struct scsi_qla_host {
 	uint8_t	scm_fabric_connection_flags;
 
 	unsigned int irq_offset;
+
+	u64 hw_err_cnt;
+	u64 interface_err_cnt;
+	u64 cmd_timeout_cnt;
+	u64 reset_cmd_err_cnt;
+	u64 link_down_time;
+	u64 short_link_down_cnt;
 } scsi_qla_host_t;
 
 struct qla27xx_image_status {
@@ -5174,6 +5186,65 @@ struct sff_8247_a0 {
 #define PRLI_PHASE(_cls) \
 	((_cls == DSC_LS_PRLI_PEND) || (_cls == DSC_LS_PRLI_COMP))
 
+enum ql_vnd_host_stat_action {
+	stop = 0,
+	start,
+	clear,
+};
+
+struct ql_vnd_mng_host_stats_param {
+	u32 stat_type;
+	enum ql_vnd_host_stat_action action;
+} __packed;
+
+struct ql_vnd_mng_host_stats_resp {
+	u32 status;
+} __packed;
+
+struct ql_vnd_stats_param {
+	u32 stat_type;
+} __packed;
+
+struct ql_vnd_tgt_stats_param {
+	s32 tgt_id;
+	u32 stat_type;
+} __packed;
+
+enum ql_vnd_host_port_action {
+	enable = 0,
+	disable,
+};
+
+struct ql_vnd_mng_host_port_param {
+	enum ql_vnd_host_port_action action;
+} __packed;
+
+struct ql_vnd_mng_host_port_resp {
+	u32 status;
+} __packed;
+
+struct ql_vnd_stat_entry {
+	u32 stat_type;	/* Failure type */
+	u32 tgt_num;	/* Target Num */
+	u64 cnt;	/* Counter value */
+} __packed;
+
+struct ql_vnd_stats {
+	u64 entry_count; /* Num of entries */
+	u64 rservd;
+	struct ql_vnd_stat_entry entry[0]; /* Place holder of entries */
+} __packed;
+
+struct ql_vnd_host_stats_resp {
+	u32 status;
+	struct ql_vnd_stats stats;
+} __packed;
+
+struct ql_vnd_tgt_stats_resp {
+	u32 status;
+	struct ql_vnd_stats stats;
+} __packed;
+
 #include "qla_target.h"
 #include "qla_gbl.h"
 #include "qla_dbg.h"
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index e39b4f2da73a..708f82311b83 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -945,4 +945,27 @@ extern void qla2x00_dfs_remove_rport(scsi_qla_host_t *vha, struct fc_port *fp);
 /* nvme.c */
 void qla_nvme_unregister_remote_port(struct fc_port *fcport);
 void qla_handle_els_plogi_done(scsi_qla_host_t *vha, struct event_arg *ea);
+
+#define QLA2XX_HW_ERROR			BIT_0
+#define QLA2XX_SHT_LNK_DWN		BIT_1
+#define QLA2XX_INT_ERR			BIT_2
+#define QLA2XX_CMD_TIMEOUT		BIT_3
+#define QLA2XX_RESET_CMD_ERR		BIT_4
+#define QLA2XX_TGT_SHT_LNK_DOWN		BIT_17
+
+#define QLA2XX_MAX_LINK_DOWN_TIME	100
+
+int qla2xxx_start_stats(struct Scsi_Host *shost, u32 flags);
+int qla2xxx_stop_stats(struct Scsi_Host *shost, u32 flags);
+int qla2xxx_reset_stats(struct Scsi_Host *shost, u32 flags);
+
+int qla2xxx_get_ini_stats(struct Scsi_Host *shost, u32 flags, void *data, u64 size);
+int qla2xxx_get_tgt_stats(struct Scsi_Host *shost, u32 flags,
+			  struct fc_rport *rport, void *data, u64 size);
+int qla2xxx_disable_port(struct Scsi_Host *shost);
+int qla2xxx_enable_port(struct Scsi_Host *shost);
+
+uint64_t qla2x00_get_num_tgts(scsi_qla_host_t *vha);
+uint64_t qla2x00_count_set_bits(u32 num);
+
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 391ac75e3de3..517d358b0031 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -3563,6 +3563,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
 					       __func__, __LINE__,
 					       fcport->port_name);
 
+					fcport->tgt_link_down_time = 0;
 					qlt_schedule_sess_for_deletion(fcport);
 					continue;
 				}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index dcc0f0d823db..410ff5534a59 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4993,6 +4993,9 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
 	fcport->login_retry = vha->hw->login_retry_count;
 	fcport->chip_reset = vha->hw->base_qpair->chip_reset;
 	fcport->logout_on_delete = 1;
+	fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+	fcport->tgt_short_link_down_cnt = 0;
+	fcport->dev_loss_tmo = 0;
 
 	if (!fcport->ct_desc.ct_sns) {
 		ql_log(ql_log_warn, vha, 0xd049,
@@ -5490,6 +5493,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
 	spin_lock_irqsave(fcport->vha->host->host_lock, flags);
 	*((fc_port_t **)rport->dd_data) = fcport;
 	spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
+	fcport->dev_loss_tmo = rport->dev_loss_tmo;
 
 	rport->supported_classes = fcport->supported_classes;
 
@@ -5548,6 +5552,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
 		fcport->logout_on_delete = 1;
 	fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
 
+	if (fcport->tgt_link_down_time < fcport->dev_loss_tmo) {
+		fcport->tgt_short_link_down_cnt++;
+		fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+	}
+
 	switch (vha->hw->current_topology) {
 	case ISP_CFG_N:
 	case ISP_CFG_NL:
@@ -6908,6 +6917,9 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
 	if (vha->flags.online) {
 		qla2x00_abort_isp_cleanup(vha);
 
+		if (vha->hw->flags.port_isolated)
+			return status;
+
 		if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
 			ha->flags.chip_reset_done = 1;
 			vha->flags.online = 1;
@@ -7029,6 +7041,11 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
 
 	}
 
+	if (vha->hw->flags.port_isolated) {
+		qla2x00_abort_isp_cleanup(vha);
+		return status;
+	}
+
 	if (!status) {
 		ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n", __func__);
 		qla2x00_configure_hba(vha);
@@ -9171,3 +9188,202 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair)
 fail:
 	return ret;
 }
+
+uint64_t
+qla2x00_count_set_bits(uint32_t num)
+{
+	/* Brian Kernighan's Alogorithm */
+	u64 count = 0;
+
+	while (num) {
+		num &= (num - 1);
+		count++;
+	}
+	return count;
+}
+
+uint64_t
+qla2x00_get_num_tgts(scsi_qla_host_t *vha)
+{
+	fc_port_t *f, *tf;
+	u64 count = 0;
+
+	f = NULL;
+	tf = NULL;
+
+	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
+		if (f->port_type != FCT_TARGET)
+			continue;
+		count++;
+	}
+	return count;
+}
+
+int qla2xxx_reset_stats(struct Scsi_Host *host, u32 flags)
+{
+	scsi_qla_host_t *vha = shost_priv(host);
+	fc_port_t *fcport = NULL;
+	unsigned long int_flags;
+
+	if (flags & QLA2XX_HW_ERROR)
+		vha->hw_err_cnt = 0;
+	if (flags & QLA2XX_SHT_LNK_DWN)
+		vha->short_link_down_cnt = 0;
+	if (flags & QLA2XX_INT_ERR)
+		vha->interface_err_cnt = 0;
+	if (flags & QLA2XX_CMD_TIMEOUT)
+		vha->cmd_timeout_cnt = 0;
+	if (flags & QLA2XX_RESET_CMD_ERR)
+		vha->reset_cmd_err_cnt = 0;
+	if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
+		spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
+		list_for_each_entry(fcport, &vha->vp_fcports, list) {
+			fcport->tgt_short_link_down_cnt = 0;
+			fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+		}
+		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
+	}
+	vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+	return 0;
+}
+
+int qla2xxx_start_stats(struct Scsi_Host *host, u32 flags)
+{
+	return qla2xxx_reset_stats(host, flags);
+}
+
+int qla2xxx_stop_stats(struct Scsi_Host *host, u32 flags)
+{
+	return qla2xxx_reset_stats(host, flags);
+}
+
+int qla2xxx_get_ini_stats(struct Scsi_Host *host, u32 flags,
+			  void *data, u64 size)
+{
+	scsi_qla_host_t *vha = shost_priv(host);
+	struct ql_vnd_host_stats_resp *resp = (struct ql_vnd_host_stats_resp *)data;
+	struct ql_vnd_stats *rsp_data = &resp->stats;
+	u64 ini_entry_count = 0;
+	u64 i = 0;
+	u64 entry_count = 0;
+	u64 num_tgt = 0;
+	u32 tmp_stat_type = 0;
+	fc_port_t *fcport = NULL;
+	unsigned long int_flags;
+
+	/* Copy stat type to work on it */
+	tmp_stat_type = flags;
+
+	if (tmp_stat_type & BIT_17) {
+		num_tgt = qla2x00_get_num_tgts(vha);
+		/* unset BIT_17 */
+		tmp_stat_type &= ~(1 << 17);
+	}
+	ini_entry_count = qla2x00_count_set_bits(tmp_stat_type);
+
+	entry_count = ini_entry_count + num_tgt;
+
+	rsp_data->entry_count = entry_count;
+
+	i = 0;
+	if (flags & QLA2XX_HW_ERROR) {
+		rsp_data->entry[i].stat_type = QLA2XX_HW_ERROR;
+		rsp_data->entry[i].tgt_num = 0x0;
+		rsp_data->entry[i].cnt = vha->hw_err_cnt;
+		i++;
+	}
+
+	if (flags & QLA2XX_SHT_LNK_DWN) {
+		rsp_data->entry[i].stat_type = QLA2XX_SHT_LNK_DWN;
+		rsp_data->entry[i].tgt_num = 0x0;
+		rsp_data->entry[i].cnt = vha->short_link_down_cnt;
+		i++;
+	}
+
+	if (flags & QLA2XX_INT_ERR) {
+		rsp_data->entry[i].stat_type = QLA2XX_INT_ERR;
+		rsp_data->entry[i].tgt_num = 0x0;
+		rsp_data->entry[i].cnt = vha->interface_err_cnt;
+		i++;
+	}
+
+	if (flags & QLA2XX_CMD_TIMEOUT) {
+		rsp_data->entry[i].stat_type = QLA2XX_CMD_TIMEOUT;
+		rsp_data->entry[i].tgt_num = 0x0;
+		rsp_data->entry[i].cnt = vha->cmd_timeout_cnt;
+		i++;
+	}
+
+	if (flags & QLA2XX_RESET_CMD_ERR) {
+		rsp_data->entry[i].stat_type = QLA2XX_RESET_CMD_ERR;
+		rsp_data->entry[i].tgt_num = 0x0;
+		rsp_data->entry[i].cnt = vha->reset_cmd_err_cnt;
+		i++;
+	}
+
+	/* i will continue from previous loop, as target
+	 * entries are after initiator
+	 */
+	if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
+		spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
+		list_for_each_entry(fcport, &vha->vp_fcports, list) {
+			if (fcport->port_type != FCT_TARGET)
+				continue;
+			if (!fcport->rport)
+				continue;
+			rsp_data->entry[i].stat_type = QLA2XX_TGT_SHT_LNK_DOWN;
+			rsp_data->entry[i].tgt_num = fcport->rport->number;
+			rsp_data->entry[i].cnt = fcport->tgt_short_link_down_cnt;
+			i++;
+		}
+		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
+	}
+	resp->status = EXT_STATUS_OK;
+
+	return 0;
+}
+
+int qla2xxx_get_tgt_stats(struct Scsi_Host *host, u32 flags,
+			  struct fc_rport *rport, void *data, u64 size)
+{
+	struct ql_vnd_tgt_stats_resp *tgt_data = data;
+	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
+
+	tgt_data->status = 0;
+	tgt_data->stats.entry_count = 1;
+	tgt_data->stats.entry[0].stat_type = flags;
+	tgt_data->stats.entry[0].tgt_num = rport->number;
+	tgt_data->stats.entry[0].cnt = fcport->tgt_short_link_down_cnt;
+
+	return 0;
+}
+
+int qla2xxx_disable_port(struct Scsi_Host *host)
+{
+	scsi_qla_host_t *vha = shost_priv(host);
+
+	vha->hw->flags.port_isolated = 1;
+
+	if (qla2x00_chip_is_down(vha))
+		return 0;
+
+	if (vha->flags.online) {
+		qla2x00_abort_isp_cleanup(vha);
+		qla2x00_wait_for_sess_deletion(vha);
+	}
+
+	return 0;
+}
+
+int qla2xxx_enable_port(struct Scsi_Host *host)
+{
+	scsi_qla_host_t *vha = shost_priv(host);
+
+	vha->hw->flags.port_isolated = 0;
+	/* Set the flag to 1, so that isp_abort can proceed */
+	vha->flags.online = 1;
+	set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+	qla2xxx_wake_dpc(vha);
+
+	return 0;
+}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index f9142dbec112..9cf8326ab9fc 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1059,6 +1059,9 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 
 	case MBA_SYSTEM_ERR:		/* System Error */
 		mbx = 0;
+
+		vha->hw_err_cnt++;
+
 		if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
 		    IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
 			u16 m[4];
@@ -1112,6 +1115,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 		ql_log(ql_log_warn, vha, 0x5006,
 		    "ISP Request Transfer Error (%x).\n",  mb[1]);
 
+		vha->hw_err_cnt++;
+
 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 		break;
 
@@ -1119,6 +1124,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 		ql_log(ql_log_warn, vha, 0x5007,
 		    "ISP Response Transfer Error (%x).\n", mb[1]);
 
+		vha->hw_err_cnt++;
+
 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 		break;
 
@@ -1176,12 +1183,18 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 		vha->flags.management_server_logged_in = 0;
 		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
 
+		if (vha->link_down_time < vha->hw->port_down_retry_count) {
+			vha->short_link_down_cnt++;
+			vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+		}
+
 		break;
 
 	case MBA_LOOP_DOWN:		/* Loop Down Event */
 		SAVE_TOPO(ha);
 		ha->flags.lip_ae = 0;
 		ha->current_topology = 0;
+		vha->link_down_time = 0;
 
 		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
 			? rd_reg_word(&reg24->mailbox4) : 0;
@@ -1503,6 +1516,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 		ql_dbg(ql_dbg_async, vha, 0x5016,
 		    "Discard RND Frame -- %04x %04x %04x.\n",
 		    mb[1], mb[2], mb[3]);
+		vha->interface_err_cnt++;
 		break;
 
 	case MBA_TRACE_NOTIFICATION:
@@ -1592,6 +1606,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 
 	case MBA_IDC_AEN:
 		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+			vha->hw_err_cnt++;
 			qla27xx_handle_8200_aen(vha, mb);
 		} else if (IS_QLA83XX(ha)) {
 			mb[4] = rd_reg_word(&reg24->mailbox4);
@@ -3101,6 +3116,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 				    "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
 				    resid, scsi_bufflen(cp));
 
+				vha->interface_err_cnt++;
+
 				res = DID_ERROR << 16 | lscsi_status;
 				goto check_scsi_status;
 			}
@@ -3126,6 +3143,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 			    "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
 			    resid, scsi_bufflen(cp));
 
+			vha->interface_err_cnt++;
+
 			res = DID_ERROR << 16 | lscsi_status;
 			goto check_scsi_status;
 		} else {
@@ -3208,6 +3227,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 
 	case CS_TRANSPORT:
 		res = DID_ERROR << 16;
+		vha->hw_err_cnt++;
 
 		if (!IS_PI_SPLIT_DET_CAPABLE(ha))
 			break;
@@ -3228,6 +3248,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 		ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee,
 		    pkt, sizeof(*sts24));
 		res = DID_ERROR << 16;
+		vha->hw_err_cnt++;
 		break;
 	default:
 		res = DID_ERROR << 16;
@@ -3839,6 +3860,7 @@ qla24xx_msix_default(int irq, void *dev_id)
 			    hccr);
 
 			qla2xxx_check_risc_status(vha);
+			vha->hw_err_cnt++;
 
 			ha->isp_ops->fw_dump(vha);
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d7d4ab65009c..f438cdedca23 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -180,6 +180,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 		ql_log(ql_log_warn, vha, 0xd035,
 		    "Cmd access timeout, cmd=0x%x, Exiting.\n",
 		    mcp->mb[0]);
+		vha->hw_err_cnt++;
 		atomic_dec(&ha->num_pend_mbx_stage1);
 		return QLA_FUNCTION_TIMEOUT;
 	}
@@ -307,6 +308,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 				atomic_dec(&ha->num_pend_mbx_stage2);
 				ql_dbg(ql_dbg_mbx, vha, 0x1012,
 				    "Pending mailbox timeout, exiting.\n");
+				vha->hw_err_cnt++;
 				rval = QLA_FUNCTION_TIMEOUT;
 				goto premature_exit;
 			}
@@ -418,6 +420,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 			    "mb[0-3]=[0x%x 0x%x 0x%x 0x%x] mb7 0x%x host_status 0x%x hccr 0x%x\n",
 			    command, ictrl, jiffies, mb[0], mb[1], mb[2], mb[3],
 			    mb[7], host_status, hccr);
+			vha->hw_err_cnt++;
 
 		} else {
 			mb[0] = RD_MAILBOX_REG(ha, &reg->isp, 0);
@@ -425,6 +428,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 			ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119,
 			    "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx "
 			    "mb[0]=0x%x\n", command, ictrl, jiffies, mb[0]);
+			vha->hw_err_cnt++;
 		}
 		ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019);
 
@@ -497,6 +501,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 				    "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP "
 				    "abort.\n", command, mcp->mb[0],
 				    ha->flags.eeh_busy);
+				vha->hw_err_cnt++;
 				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 				qla2xxx_wake_dpc(vha);
 			}
@@ -521,6 +526,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
 				    "Mailbox cmd timeout occurred, cmd=0x%x, "
 				    "mb[0]=0x%x. Scheduling ISP abort ",
 				    command, mcp->mb[0]);
+				vha->hw_err_cnt++;
 				set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
 				clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 				/* Allow next mbx cmd to come in. */
@@ -625,6 +631,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
 		ql_dbg(ql_dbg_mbx, vha, 0x1023,
 		    "Failed=%x mb[0]=%x mb[1]=%x.\n",
 		    rval, mcp->mb[0], mcp->mb[1]);
+		vha->hw_err_cnt++;
 	} else {
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1024,
 		    "Done %s.\n", __func__);
@@ -736,6 +743,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
 
 		ql_dbg(ql_dbg_mbx, vha, 0x1026,
 		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+		vha->hw_err_cnt++;
 		return rval;
 	}
 
@@ -1313,6 +1321,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
 		ql_dbg(ql_dbg_mbx, vha, 0x1033, "Failed=%x.\n", rval);
+		vha->hw_err_cnt++;
 	} else {
 		/*EMPTY*/
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1034,
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index f80abe28f35a..a760cb38e487 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1274,6 +1274,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 	sp = scsi_cmd_priv(cmd);
 	qpair = sp->qpair;
 
+	vha->cmd_timeout_cnt++;
+
 	if ((sp->fcport && sp->fcport->deleted) || !qpair)
 		return SUCCESS;
 
@@ -1442,6 +1444,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
 	    "%s RESET FAILED: %s nexus=%ld:%d:%llu cmd=%p.\n", name,
 	    reset_errors[err], vha->host_no, cmd->device->id, cmd->device->lun,
 	    cmd);
+	vha->reset_cmd_err_cnt++;
 	return FAILED;
 }
 
@@ -3141,6 +3144,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	ha->mr.fcport.supported_classes = FC_COS_UNSPECIFIED;
 	ha->mr.fcport.scan_state = 1;
 
+	qla2xxx_reset_stats(host, QLA2XX_HW_ERROR | QLA2XX_SHT_LNK_DWN |
+			    QLA2XX_INT_ERR | QLA2XX_CMD_TIMEOUT |
+			    QLA2XX_RESET_CMD_ERR | QLA2XX_TGT_SHT_LNK_DOWN);
+
 	/* Set the SG table size based on ISP type */
 	if (!IS_FWI2_CAPABLE(ha)) {
 		if (IS_QLA2100(ha))
@@ -5090,6 +5097,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
 			fcport->d_id = e->u.new_sess.id;
 			fcport->flags |= FCF_FABRIC_DEVICE;
 			fcport->fw_login_state = DSC_LS_PLOGI_PEND;
+			fcport->tgt_short_link_down_cnt = 0;
 
 			memcpy(fcport->port_name, e->u.new_sess.port_name,
 			    WWN_SIZE);
@@ -7061,6 +7069,8 @@ qla2x00_timer(struct timer_list *t)
 	uint16_t        w;
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req;
+	unsigned long flags;
+	fc_port_t *fcport = NULL;
 
 	if (ha->flags.eeh_busy) {
 		ql_dbg(ql_dbg_timer, vha, 0x6000,
@@ -7092,6 +7102,16 @@ qla2x00_timer(struct timer_list *t)
 	if (!vha->vp_idx && IS_QLAFX00(ha))
 		qlafx00_timer_routine(vha);
 
+	if (vha->link_down_time < QLA2XX_MAX_LINK_DOWN_TIME)
+		vha->link_down_time++;
+
+	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+	list_for_each_entry(fcport, &vha->vp_fcports, list) {
+		if (fcport->tgt_link_down_time < QLA2XX_MAX_LINK_DOWN_TIME)
+			fcport->tgt_link_down_time++;
+	}
+	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+
 	/* Loop down handler. */
 	if (atomic_read(&vha->loop_down_timer) > 0 &&
 	    !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
-- 
2.19.0.rc0


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

* [PATCH v2 2/7] qla2xxx: Add error counters to debugfs node
  2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
@ 2021-01-05  6:03 ` Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 3/7] qla2xxx: Move some messages from debug to normal log level Nilesh Javali
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

From: Saurav Kashyap <skashyap@marvell.com>

Display error counters via debugfs node.

Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_dfs.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index d5ebcf7d70ff..ccce0eab844e 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -286,6 +286,10 @@ qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
 		core_qla_snd_status, qla_core_ret_sta_ctio, core_qla_free_cmd,
 		num_q_full_sent, num_alloc_iocb_failed, num_term_xchg_sent;
 	u16 i;
+	fc_port_t *fcport = NULL;
+
+	if (qla2x00_chip_is_down(vha))
+		return 0;
 
 	qla_core_sbt_cmd = qpair->tgt_counters.qla_core_sbt_cmd;
 	core_qla_que_buf = qpair->tgt_counters.core_qla_que_buf;
@@ -349,6 +353,30 @@ qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
 		vha->qla_stats.qla_dif_stats.dif_ref_tag_err);
 	seq_printf(s, "DIF App tag err = %d\n",
 		vha->qla_stats.qla_dif_stats.dif_app_tag_err);
+
+	seq_puts(s, "\n");
+	seq_puts(s, "Initiator Error Counters\n");
+	seq_printf(s, "HW Error Count =		%14lld\n",
+		   vha->hw_err_cnt);
+	seq_printf(s, "Link Down Count =	%14lld\n",
+		   vha->short_link_down_cnt);
+	seq_printf(s, "Interface Err Count =	%14lld\n",
+		   vha->interface_err_cnt);
+	seq_printf(s, "Cmd Timeout Count =	%14lld\n",
+		   vha->cmd_timeout_cnt);
+	seq_printf(s, "Reset Count =		%14lld\n",
+		   vha->reset_cmd_err_cnt);
+	seq_puts(s, "\n");
+
+	list_for_each_entry(fcport, &vha->vp_fcports, list) {
+		if (!fcport || !fcport->rport)
+			continue;
+
+		seq_printf(s, "Target Num = %7d Link Down Count = %14lld\n",
+			   fcport->rport->number, fcport->tgt_short_link_down_cnt);
+	}
+	seq_puts(s, "\n");
+
 	return 0;
 }
 
-- 
2.19.0.rc0


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

* [PATCH v2 3/7] qla2xxx: Move some messages from debug to normal log level
  2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 2/7] qla2xxx: Add error counters to debugfs node Nilesh Javali
@ 2021-01-05  6:03 ` Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe Nilesh Javali
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

From: Saurav Kashyap <skashyap@marvell.com>

This change will aid in debugging issues where debug level is not set.

Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_init.c | 10 +++----
 drivers/scsi/qla2xxx/qla_isr.c  | 52 ++++++++++++++++-----------------
 2 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 410ff5534a59..221369cdf71f 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -347,11 +347,11 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
 	if (NVME_TARGET(vha->hw, fcport))
 		lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
 
-	ql_dbg(ql_dbg_disc, vha, 0x2072,
-	    "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x "
-		"retries=%d.\n", fcport->port_name, sp->handle, fcport->loop_id,
-	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
-	    fcport->login_retry);
+	ql_log(ql_log_warn, vha, 0x2072,
+	       "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x retries=%d.\n",
+	       fcport->port_name, sp->handle, fcport->loop_id,
+	       fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
+	       fcport->login_retry);
 
 	rval = qla2x00_start_sp(sp);
 	if (rval != QLA_SUCCESS) {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 9cf8326ab9fc..bfc8bbaeea46 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1455,9 +1455,9 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
 		if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
 			break;
 
-		ql_dbg(ql_dbg_async, vha, 0x5013,
-		    "RSCN database changed -- %04x %04x %04x.\n",
-		    mb[1], mb[2], mb[3]);
+		ql_log(ql_log_warn, vha, 0x5013,
+		       "RSCN database changed -- %04x %04x %04x.\n",
+		       mb[1], mb[2], mb[3]);
 
 		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
 		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
@@ -2221,12 +2221,12 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
 		break;
 	}
 
-	ql_dbg(ql_dbg_async, sp->vha, 0x5037,
-	    "Async-%s failed: handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
-	    type, sp->handle, fcport->d_id.b24, fcport->port_name,
-	    le16_to_cpu(logio->comp_status),
-	    le32_to_cpu(logio->io_parameter[0]),
-	    le32_to_cpu(logio->io_parameter[1]));
+	ql_log(ql_log_warn, sp->vha, 0x5037,
+	       "Async-%s failed: handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
+	       type, sp->handle, fcport->d_id.b24, fcport->port_name,
+	       le16_to_cpu(logio->comp_status),
+	       le32_to_cpu(logio->io_parameter[0]),
+	       le32_to_cpu(logio->io_parameter[1]));
 
 logio_done:
 	sp->done(sp, 0);
@@ -2389,9 +2389,9 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 
 		tgt_xfer_len = be32_to_cpu(rsp_iu->xfrd_len);
 		if (fd->transferred_length != tgt_xfer_len) {
-			ql_dbg(ql_dbg_io, fcport->vha, 0x3079,
-				"Dropped frame(s) detected (sent/rcvd=%u/%u).\n",
-				tgt_xfer_len, fd->transferred_length);
+			ql_log(ql_log_warn, fcport->vha, 0x3079,
+			       "Dropped frame(s) detected (sent/rcvd=%u/%u).\n",
+			       tgt_xfer_len, fd->transferred_length);
 			logit = 1;
 		} else if (le16_to_cpu(comp_status) == CS_DATA_UNDERRUN) {
 			/*
@@ -3112,9 +3112,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 		scsi_set_resid(cp, resid);
 		if (scsi_status & SS_RESIDUAL_UNDER) {
 			if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
-				ql_dbg(ql_dbg_io, fcport->vha, 0x301d,
-				    "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
-				    resid, scsi_bufflen(cp));
+				ql_log(ql_log_warn, fcport->vha, 0x301d,
+				       "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
+				       resid, scsi_bufflen(cp));
 
 				vha->interface_err_cnt++;
 
@@ -3139,9 +3139,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 			 * task not completed.
 			 */
 
-			ql_dbg(ql_dbg_io, fcport->vha, 0x301f,
-			    "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
-			    resid, scsi_bufflen(cp));
+			ql_log(ql_log_warn, fcport->vha, 0x301f,
+			       "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
+			       resid, scsi_bufflen(cp));
 
 			vha->interface_err_cnt++;
 
@@ -3257,15 +3257,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 
 out:
 	if (logit)
-		ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
-		    "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu "
-		    "portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x "
-		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
-		    comp_status, scsi_status, res, vha->host_no,
-		    cp->device->id, cp->device->lun, fcport->d_id.b.domain,
-		    fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
-		    cp->cmnd, scsi_bufflen(cp), rsp_info_len,
-		    resid_len, fw_resid_len, sp, cp);
+		ql_log(ql_log_warn, fcport->vha, 0x3022,
+		       "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
+		       comp_status, scsi_status, res, vha->host_no,
+		       cp->device->id, cp->device->lun, fcport->d_id.b.domain,
+		       fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
+		       cp->cmnd, scsi_bufflen(cp), rsp_info_len,
+		       resid_len, fw_resid_len, sp, cp);
 
 	if (rsp->status_srb == NULL)
 		sp->done(sp, res);
-- 
2.19.0.rc0


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

* [PATCH v2 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe
  2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
                   ` (2 preceding siblings ...)
  2021-01-05  6:03 ` [PATCH v2 3/7] qla2xxx: Move some messages from debug to normal log level Nilesh Javali
@ 2021-01-05  6:03 ` Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 5/7] qla2xxx: Fix mailbox Ch erroneous error Nilesh Javali
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

From: Bikash Hazarika <bhazarika@marvell.com>

FW needs to wait for an ABTS response before completing the I/O

Signed-off-by: Bikash Hazarika <bhazarika@marvell.com>
Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
Signed-off-by: Arun Easi <aeasi@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_def.h  | 12 +++++
 drivers/scsi/qla2xxx/qla_fw.h   | 27 ++++++++--
 drivers/scsi/qla2xxx/qla_gbl.h  |  6 +++
 drivers/scsi/qla2xxx/qla_init.c |  4 ++
 drivers/scsi/qla2xxx/qla_iocb.c |  6 +++
 drivers/scsi/qla2xxx/qla_isr.c  |  8 +++
 drivers/scsi/qla2xxx/qla_mbx.c  |  6 +++
 drivers/scsi/qla2xxx/qla_nvme.c | 90 ++++++++++++++++++++++++++++++++-
 drivers/scsi/qla2xxx/qla_os.c   |  5 ++
 9 files changed, 159 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index f2f1b0231033..17da6b436e74 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2101,6 +2101,7 @@ typedef struct {
 #define CS_COMPLETE_CHKCOND	0x30	/* Error? */
 #define CS_IOCB_ERROR		0x31	/* Generic error for IOCB request
 					   failure */
+#define CS_REJECT_RECEIVED	0x4E	/* Reject received */
 #define CS_BAD_PAYLOAD		0x80	/* Driver defined */
 #define CS_UNKNOWN		0x81	/* Driver defined */
 #define CS_RETRY		0x82	/* Driver defined */
@@ -4150,6 +4151,17 @@ struct qla_hw_data {
 /* Bit 21 of fw_attributes decides the MCTP capabilities */
 #define IS_MCTP_CAPABLE(ha)	(IS_QLA2031(ha) && \
 				((ha)->fw_attributes_ext[0] & BIT_0))
+#define QLA_ABTS_FW_ENABLED(_ha)       ((_ha)->fw_attributes_ext[0] & BIT_14)
+#define QLA_SRB_NVME_LS(_sp) ((_sp)->type == SRB_NVME_LS)
+#define QLA_SRB_NVME_CMD(_sp) ((_sp)->type == SRB_NVME_CMD)
+#define QLA_NVME_IOS(_sp) (QLA_SRB_NVME_CMD(_sp) || QLA_SRB_NVME_LS(_sp))
+#define QLA_LS_ABTS_WAIT_ENABLED(_sp) \
+	(QLA_SRB_NVME_LS(_sp) && QLA_ABTS_FW_ENABLED(_sp->fcport->vha->hw))
+#define QLA_CMD_ABTS_WAIT_ENABLED(_sp) \
+	(QLA_SRB_NVME_CMD(_sp) && QLA_ABTS_FW_ENABLED(_sp->fcport->vha->hw))
+#define QLA_ABTS_WAIT_ENABLED(_sp) \
+	(QLA_NVME_IOS(_sp) && QLA_ABTS_FW_ENABLED(_sp->fcport->vha->hw))
+
 #define IS_PI_UNINIT_CAPABLE(ha)	(IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_PI_IPGUARD_CAPABLE(ha)	(IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_PI_DIFB_DIX0_CAPABLE(ha)	(0)
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 12b689e32883..49df418030e4 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -982,11 +982,18 @@ struct abort_entry_24xx {
 
 	uint32_t handle;		/* System handle. */
 
-	__le16	nport_handle;		/* N_PORT handle. */
-					/* or Completion status. */
+	union {
+		__le16 nport_handle;            /* N_PORT handle. */
+		__le16 comp_status;             /* Completion status. */
+	};
 
 	__le16	options;		/* Options. */
 #define AOF_NO_ABTS		BIT_0	/* Do not send any ABTS. */
+#define AOF_NO_RRQ		BIT_1   /* Do not send RRQ. */
+#define AOF_ABTS_TIMEOUT	BIT_2   /* Disable logout on ABTS timeout. */
+#define AOF_ABTS_RTY_CNT	BIT_3   /* Use driver specified retry count. */
+#define AOF_RSP_TIMEOUT		BIT_4   /* Use specified response timeout. */
+
 
 	uint32_t handle_to_abort;	/* System handle to abort. */
 
@@ -995,8 +1002,20 @@ struct abort_entry_24xx {
 
 	uint8_t port_id[3];		/* PortID of destination port. */
 	uint8_t vp_index;
-
-	uint8_t reserved_2[12];
+	u8	reserved_2[4];
+	union {
+		struct {
+			__le16 abts_rty_cnt;
+			__le16 rsp_timeout;
+		} drv;
+		struct {
+			u8	ba_rjt_vendorUnique;
+			u8	ba_rjt_reasonCodeExpl;
+			u8	ba_rjt_reasonCode;
+			u8	reserved_3;
+		} fw;
+	};
+	u8	reserved_4[4];
 };
 
 #define ABTS_RCV_TYPE		0x54
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 708f82311b83..6486f97d649e 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -177,6 +177,7 @@ extern int ql2xexlogins;
 extern int ql2xdifbundlinginternalbuffers;
 extern int ql2xfulldump_on_mpifail;
 extern int ql2xenforce_iocb_limit;
+extern int ql2xabts_wait_nvme;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -941,6 +942,11 @@ int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode);
 extern void qla24xx_process_purex_list(struct purex_list *);
 extern void qla2x00_dfs_create_rport(scsi_qla_host_t *vha, struct fc_port *fp);
 extern void qla2x00_dfs_remove_rport(scsi_qla_host_t *vha, struct fc_port *fp);
+extern void qla_wait_nvme_release_cmd_kref(srb_t *sp);
+extern void qla_nvme_abort_set_option
+		(struct abort_entry_24xx *abt, srb_t *sp);
+extern void qla_nvme_abort_process_comp_status
+		(struct abort_entry_24xx *abt, srb_t *sp);
 
 /* nvme.c */
 void qla_nvme_unregister_remote_port(struct fc_port *fcport);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 221369cdf71f..a6ab2629b7cf 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -136,6 +136,10 @@ static void qla24xx_abort_iocb_timeout(void *data)
 static void qla24xx_abort_sp_done(srb_t *sp, int res)
 {
 	struct srb_iocb *abt = &sp->u.iocb_cmd;
+	srb_t *orig_sp = sp->cmd_sp;
+
+	if (orig_sp)
+		qla_wait_nvme_release_cmd_kref(orig_sp);
 
 	del_timer(&sp->u.iocb_cmd.timer);
 	if (sp->flags & SRB_WAKEUP_ON_COMP)
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c532c74ca1ab..e27359b294d3 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -3571,6 +3571,7 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
 	struct srb_iocb *aio = &sp->u.iocb_cmd;
 	scsi_qla_host_t *vha = sp->vha;
 	struct req_que *req = sp->qpair->req;
+	srb_t *orig_sp = sp->cmd_sp;
 
 	memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
 	abt_iocb->entry_type = ABORT_IOCB_TYPE;
@@ -3587,6 +3588,11 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
 			    aio->u.abt.cmd_hndl);
 	abt_iocb->vp_index = vha->vp_idx;
 	abt_iocb->req_que_no = aio->u.abt.req_que_no;
+
+	/* need to pass original sp */
+	if (orig_sp)
+		qla_nvme_abort_set_option(abt_iocb, orig_sp);
+
 	/* Send the command to the firmware */
 	wmb();
 }
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index bfc8bbaeea46..a4a52a2d724e 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -5,6 +5,7 @@
  */
 #include "qla_def.h"
 #include "qla_target.h"
+#include "qla_gbl.h"
 
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -3431,6 +3432,7 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 {
 	const char func[] = "ABT_IOCB";
 	srb_t *sp;
+	srb_t *orig_sp = NULL;
 	struct srb_iocb *abt;
 
 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
@@ -3439,6 +3441,12 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
 
 	abt = &sp->u.iocb_cmd;
 	abt->u.abt.comp_status = pkt->nport_handle;
+	abt->u.abt.comp_status = le16_to_cpu(pkt->comp_status);
+	orig_sp = sp->cmd_sp;
+	/* Need to pass original sp */
+	if (orig_sp)
+		qla_nvme_abort_process_comp_status(pkt, orig_sp);
+
 	sp->done(sp, 0);
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index f438cdedca23..629af6fe8c55 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3243,6 +3243,8 @@ qla24xx_abort_command(srb_t *sp)
 	abt->vp_index = fcport->vha->vp_idx;
 
 	abt->req_que_no = cpu_to_le16(req->id);
+	/* Need to pass original sp */
+	qla_nvme_abort_set_option(abt, sp);
 
 	rval = qla2x00_issue_iocb(vha, abt, abt_dma, 0);
 	if (rval != QLA_SUCCESS) {
@@ -3265,6 +3267,10 @@ qla24xx_abort_command(srb_t *sp)
 		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1091,
 		    "Done %s.\n", __func__);
 	}
+	if (rval == QLA_SUCCESS)
+		qla_nvme_abort_process_comp_status(abt, sp);
+
+	qla_wait_nvme_release_cmd_kref(sp);
 
 	dma_pool_free(ha->s_dma_pool, abt, abt_dma);
 
diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c
index eab559b3b257..1cdb7352d6db 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -245,6 +245,12 @@ static void qla_nvme_abort_work(struct work_struct *work)
 	    __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted",
 	    sp, sp->handle, fcport, rval);
 
+	/* Returned before decreasing kref so that I/O requests
+	 * are waited until ABTS complete. This kref is decreased
+	 * at qla24xx_abort_sp_done function.
+	 */
+	if (ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(sp))
+		return;
 out:
 	/* kref_get was done before work was schedule. */
 	kref_put(&sp->cmd_kref, sp->put_fn);
@@ -284,7 +290,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
 	struct qla_hw_data *ha;
 	srb_t           *sp;
 
-
 	if (!fcport || (fcport && fcport->deleted))
 		return rval;
 
@@ -591,6 +596,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
 	sp->put_fn = qla_nvme_release_fcp_cmd_kref;
 	sp->qpair = qpair;
 	sp->vha = vha;
+	sp->cmd_sp = sp;
 	nvme = &sp->u.iocb_cmd;
 	nvme->u.nvme.desc = fd;
 
@@ -744,3 +750,85 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
 
 	return ret;
 }
+
+void qla_nvme_abort_set_option(struct abort_entry_24xx *abt, srb_t *orig_sp)
+{
+	struct qla_hw_data *ha;
+
+	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
+		return;
+
+	ha = orig_sp->fcport->vha->hw;
+
+	WARN_ON_ONCE(abt->options & cpu_to_le16(BIT_0));
+	/* Use Driver Specified Retry Count */
+	abt->options |= cpu_to_le16(AOF_ABTS_RTY_CNT);
+	abt->drv.abts_rty_cnt = cpu_to_le16(2);
+	/* Use specified response timeout */
+	abt->options |= cpu_to_le16(AOF_RSP_TIMEOUT);
+	/* set it to 2 * r_a_tov in secs */
+	abt->drv.rsp_timeout = cpu_to_le16(2 * (ha->r_a_tov / 10));
+}
+
+void qla_nvme_abort_process_comp_status(struct abort_entry_24xx *abt, srb_t *orig_sp)
+{
+	u16	comp_status;
+	struct scsi_qla_host *vha;
+
+	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
+		return;
+
+	vha = orig_sp->fcport->vha;
+
+	comp_status = le16_to_cpu(abt->comp_status);
+	switch (comp_status) {
+	case CS_RESET:		/* reset event aborted */
+	case CS_ABORTED:	/* IOCB was cleaned */
+	/* N_Port handle is not currently logged in */
+	case CS_TIMEOUT:
+	/* N_Port handle was logged out while waiting for ABTS to complete */
+	case CS_PORT_UNAVAILABLE:
+	/* Firmware found that the port name changed */
+	case CS_PORT_LOGGED_OUT:
+	/* BA_RJT was received for the ABTS */
+	case CS_PORT_CONFIG_CHG:
+		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf09d,
+		       "Abort I/O IOCB completed with error, comp_status=%x\n",
+		comp_status);
+		break;
+
+	/* BA_RJT was received for the ABTS */
+	case CS_REJECT_RECEIVED:
+		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf09e,
+		       "BA_RJT was received for the ABTS rjt_vendorUnique = %u",
+			abt->fw.ba_rjt_vendorUnique);
+		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf09e,
+		       "ba_rjt_reasonCodeExpl = %u, ba_rjt_reasonCode = %u\n",
+		       abt->fw.ba_rjt_reasonCodeExpl, abt->fw.ba_rjt_reasonCode);
+		break;
+
+	case CS_COMPLETE:
+		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf09f,
+		       "IOCB request is completed successfully comp_status=%x\n",
+		comp_status);
+		break;
+
+	case CS_IOCB_ERROR:
+		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf0a0,
+		       "IOCB request is failed, comp_status=%x\n", comp_status);
+		break;
+
+	default:
+		ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf0a1,
+		       "Invalid Abort IO IOCB Completion Status %x\n",
+		comp_status);
+		break;
+	}
+}
+
+inline void qla_wait_nvme_release_cmd_kref(srb_t *orig_sp)
+{
+	if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
+		return;
+	kref_put(&orig_sp->cmd_kref, orig_sp->put_fn);
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index a760cb38e487..3cfd83fce9c5 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -327,6 +327,11 @@ MODULE_PARM_DESC(ql2xrdpenable,
 		"Enables RDP responses. "
 		"0 - no RDP responses (default). "
 		"1 - provide RDP responses.");
+int ql2xabts_wait_nvme = 1;
+module_param(ql2xabts_wait_nvme, int, 0444);
+MODULE_PARM_DESC(ql2xabts_wait_nvme,
+		 "To wait for ABTS response on I/O timeouts for NVMe. (default: 1)");
+
 
 static void qla2x00_clear_drv_active(struct qla_hw_data *);
 static void qla2x00_free_device(scsi_qla_host_t *);
-- 
2.19.0.rc0


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

* [PATCH v2 5/7] qla2xxx: Fix mailbox Ch erroneous error
  2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
                   ` (3 preceding siblings ...)
  2021-01-05  6:03 ` [PATCH v2 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe Nilesh Javali
@ 2021-01-05  6:03 ` Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 7/7] qla2xxx: Update version to 10.02.00.105-k Nilesh Javali
  6 siblings, 0 replies; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

From: Quinn Tran <qutran@marvell.com>

Mailbox Ch/dump ram extend expects mb register 10 to be
set. If not set/clear, firmware can pick up garbage from previous
invocation of this mailbox. Example: mctp dump can set mb10.
On subsequent flash read which use mailbox cmd Ch, mb10 can
retain previous value.

Cc: stable@vger.kernel.org
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_dbg.c | 1 +
 drivers/scsi/qla2xxx/qla_mbx.c | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index bb7431912d41..144a893e7335 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -202,6 +202,7 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, __be32 *ram,
 		wrt_reg_word(&reg->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
 		wrt_reg_word(&reg->mailbox1, LSW(addr));
 		wrt_reg_word(&reg->mailbox8, MSW(addr));
+		wrt_reg_word(&reg->mailbox10, 0);
 
 		wrt_reg_word(&reg->mailbox2, MSW(LSD(dump_dma)));
 		wrt_reg_word(&reg->mailbox3, LSW(LSD(dump_dma)));
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 629af6fe8c55..06c99963b2c9 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -4291,7 +4291,8 @@ qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr,
 	if (MSW(addr) || IS_FWI2_CAPABLE(vha->hw)) {
 		mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED;
 		mcp->mb[8] = MSW(addr);
-		mcp->out_mb = MBX_8|MBX_0;
+		mcp->mb[10] = 0;
+		mcp->out_mb = MBX_10|MBX_8|MBX_0;
 	} else {
 		mcp->mb[0] = MBC_DUMP_RISC_RAM;
 		mcp->out_mb = MBX_0;
-- 
2.19.0.rc0


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

* [PATCH v2 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER
  2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
                   ` (4 preceding siblings ...)
  2021-01-05  6:03 ` [PATCH v2 5/7] qla2xxx: Fix mailbox Ch erroneous error Nilesh Javali
@ 2021-01-05  6:03 ` Nilesh Javali
  2021-01-05  6:03 ` [PATCH v2 7/7] qla2xxx: Update version to 10.02.00.105-k Nilesh Javali
  6 siblings, 0 replies; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

From: Saurav Kashyap <skashyap@marvell.com>

Enable NVME confirmation bit in PRLI.

Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_iocb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index e27359b294d3..8b41cbaf8535 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2378,6 +2378,8 @@ qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio)
 			logio->io_parameter[0] =
 				cpu_to_le32(NVME_PRLI_SP_FIRST_BURST);
 		if (sp->vha->flags.nvme2_enabled) {
+			/* Set service parameter BIT_7 for NVME CONF support */
+			logio->io_parameter[0] |= NVME_PRLI_SP_CONF;
 			/* Set service parameter BIT_8 for SLER support */
 			logio->io_parameter[0] |=
 				cpu_to_le32(NVME_PRLI_SP_SLER);
-- 
2.19.0.rc0


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

* [PATCH v2 7/7] qla2xxx: Update version to 10.02.00.105-k
  2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
                   ` (5 preceding siblings ...)
  2021-01-05  6:03 ` [PATCH v2 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER Nilesh Javali
@ 2021-01-05  6:03 ` Nilesh Javali
  6 siblings, 0 replies; 9+ messages in thread
From: Nilesh Javali @ 2021-01-05  6:03 UTC (permalink / raw)
  To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_version.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index ccec858875dd..72c648442e8d 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -6,9 +6,9 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "10.02.00.104-k"
+#define QLA2XXX_VERSION      "10.02.00.105-k"
 
 #define QLA_DRIVER_MAJOR_VER	10
 #define QLA_DRIVER_MINOR_VER	2
 #define QLA_DRIVER_PATCH_VER	0
-#define QLA_DRIVER_BETA_VER	104
+#define QLA_DRIVER_BETA_VER	105
-- 
2.19.0.rc0


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

* RE: [PATCH v2 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port
  2021-01-05  6:03 ` [PATCH v2 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
@ 2021-01-05  6:11   ` Saurav Kashyap
  0 siblings, 0 replies; 9+ messages in thread
From: Saurav Kashyap @ 2021-01-05  6:11 UTC (permalink / raw)
  To: Nilesh Javali, martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream

Hi Nilesh,
Sorry, the fix for error reported by "kernl test robot" is not complete.  I will share complete fix with you.

NACKed-by: Saurav Kashyap <skashyap@marvell.com>

Thanks,
~Saurav

> -----Original Message-----
> From: Nilesh Javali <njavali@marvell.com>
> Sent: Tuesday, January 5, 2021 11:33 AM
> To: martin.petersen@oracle.com
> Cc: linux-scsi@vger.kernel.org; GR-QLogic-Storage-Upstream <GR-QLogic-
> Storage-Upstream@marvell.com>
> Subject: [PATCH v2 1/7] qla2xxx: Implementation to get and manage host,
> target stats and initiator port
> 
> From: Saurav Kashyap <skashyap@marvell.com>
> 
> This statistics will help in debugging process and checking specific
> error counts.
> 
> Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> Reported-by: kernel test robot <lkp@intel.com>
> ---
>  drivers/scsi/qla2xxx/qla_attr.c |   9 +
>  drivers/scsi/qla2xxx/qla_bsg.c  | 342 ++++++++++++++++++++++++++++++++
>  drivers/scsi/qla2xxx/qla_bsg.h  |   5 +
>  drivers/scsi/qla2xxx/qla_def.h  |  71 +++++++
>  drivers/scsi/qla2xxx/qla_gbl.h  |  23 +++
>  drivers/scsi/qla2xxx/qla_gs.c   |   1 +
>  drivers/scsi/qla2xxx/qla_init.c | 216 ++++++++++++++++++++
>  drivers/scsi/qla2xxx/qla_isr.c  |  22 ++
>  drivers/scsi/qla2xxx/qla_mbx.c  |   9 +
>  drivers/scsi/qla2xxx/qla_os.c   |  20 ++
>  10 files changed, 718 insertions(+)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
> index ab45ac1e5a72..63391c9be05d 100644
> --- a/drivers/scsi/qla2xxx/qla_attr.c
> +++ b/drivers/scsi/qla2xxx/qla_attr.c
> @@ -710,6 +710,12 @@ qla2x00_sysfs_write_reset(struct file *filp, struct
> kobject *kobj,
>  		ql_log(ql_log_info, vha, 0x706e,
>  		    "Issuing ISP reset.\n");
> 
> +		if (vha->hw->flags.port_isolated) {
> +			ql_log(ql_log_info, vha, 0x706e,
> +			       "Port is isolated, returning.\n");
> +			return -EINVAL;
> +		}
> +
>  		scsi_block_requests(vha->host);
>  		if (IS_QLA82XX(ha)) {
>  			ha->flags.isp82xx_no_md_cap = 1;
> @@ -2717,6 +2723,9 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
>  	if (IS_QLAFX00(vha->hw))
>  		return 0;
> 
> +	if (vha->hw->flags.port_isolated)
> +		return 0;
> +
>  	qla2x00_loop_reset(vha);
>  	return 0;
>  }
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 23b604832a54..fb65e6f79e49 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -4,6 +4,7 @@
>   * Copyright (c)  2003-2014 QLogic Corporation
>   */
>  #include "qla_def.h"
> +#include "qla_gbl.h"
> 
>  #include <linux/kthread.h>
>  #include <linux/vmalloc.h>
> @@ -2444,6 +2445,323 @@ qla2x00_get_flash_image_status(struct bsg_job
> *bsg_job)
>  	return 0;
>  }
> 
> +static int
> +qla2x00_manage_host_stats(struct bsg_job *bsg_job)
> +{
> +	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
> +	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
> +	struct ql_vnd_mng_host_stats_param *req_data;
> +	struct ql_vnd_mng_host_stats_resp rsp_data;
> +	u32 req_data_len;
> +	int ret = 0;
> +
> +	if (!vha->flags.online) {
> +		ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n");
> +		return -EIO;
> +	}
> +
> +	req_data_len = bsg_job->request_payload.payload_len;
> +
> +	if (req_data_len != sizeof(struct ql_vnd_mng_host_stats_param)) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
> +		return -EIO;
> +	}
> +
> +	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
> +	if (!req_data) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation
> failure.\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* Copy the request buffer in req_data */
> +	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
> +			  bsg_job->request_payload.sg_cnt, req_data,
> +			  req_data_len);
> +
> +	switch (req_data->action) {
> +	case 0:
> +		ret = qla2xxx_stop_stats(vha->host, req_data->stat_type);
> +		break;
> +	case 1:
> +		ret = qla2xxx_start_stats(vha->host, req_data->stat_type);
> +		break;
> +	case 2:
> +		ret = qla2xxx_reset_stats(vha->host, req_data->stat_type);
> +		break;
> +	default:
> +		ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n");
> +		ret = -EIO;
> +		break;
> +	}
> +
> +	kfree(req_data);
> +
> +	/* Prepare response */
> +	rsp_data.status = ret;
> +	bsg_job->reply_payload.payload_len = sizeof(struct
> ql_vnd_mng_host_stats_resp);
> +
> +	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
> +	bsg_reply->reply_payload_rcv_len =
> +		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
> +				    bsg_job->reply_payload.sg_cnt,
> +				    &rsp_data,
> +				    sizeof(struct ql_vnd_mng_host_stats_resp));
> +
> +	bsg_reply->result = DID_OK;
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +		     bsg_reply->reply_payload_rcv_len);
> +
> +	return ret;
> +}
> +
> +static int
> +qla2x00_get_host_stats(struct bsg_job *bsg_job)
> +{
> +	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
> +	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
> +	struct ql_vnd_stats_param *req_data;
> +	struct ql_vnd_host_stats_resp rsp_data;
> +	u32 req_data_len;
> +	int ret = 0;
> +	u64 ini_entry_count = 0;
> +	u64 entry_count = 0;
> +	u64 tgt_num = 0;
> +	u64 tmp_stat_type = 0;
> +	u64 response_len = 0;
> +	void *data;
> +
> +	req_data_len = bsg_job->request_payload.payload_len;
> +
> +	if (req_data_len != sizeof(struct ql_vnd_stats_param)) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
> +		return -EIO;
> +	}
> +
> +	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
> +	if (!req_data) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation
> failure.\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* Copy the request buffer in req_data */
> +	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
> +			  bsg_job->request_payload.sg_cnt, req_data,
> req_data_len);
> +
> +	/* Copy stat type to work on it */
> +	tmp_stat_type = req_data->stat_type;
> +
> +	if (tmp_stat_type & QLA2XX_TGT_SHT_LNK_DOWN) {
> +		/* Num of tgts connected to this host */
> +		tgt_num = qla2x00_get_num_tgts(vha);
> +		/* unset BIT_17 */
> +		tmp_stat_type &= ~(1 << 17);
> +	}
> +
> +	/* Total ini stats */
> +	ini_entry_count = qla2x00_count_set_bits(tmp_stat_type);
> +
> +	/* Total number of entries */
> +	entry_count = ini_entry_count + tgt_num;
> +
> +	response_len = sizeof(struct ql_vnd_host_stats_resp) +
> +		(sizeof(struct ql_vnd_stat_entry) * entry_count);
> +
> +	if (response_len > bsg_job->reply_payload.payload_len) {
> +		rsp_data.status = EXT_STATUS_BUFFER_TOO_SMALL;
> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> EXT_STATUS_BUFFER_TOO_SMALL;
> +		bsg_job->reply_payload.payload_len = sizeof(struct
> ql_vnd_mng_host_stats_resp);
> +
> +		bsg_reply->reply_payload_rcv_len =
> +			sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
> +					    bsg_job->reply_payload.sg_cnt,
> &rsp_data,
> +					    sizeof(struct
> ql_vnd_mng_host_stats_resp));
> +
> +		bsg_reply->result = DID_OK;
> +		bsg_job_done(bsg_job, bsg_reply->result,
> +			     bsg_reply->reply_payload_rcv_len);
> +		goto host_stat_out;
> +	}
> +
> +	data = kzalloc(response_len, GFP_KERNEL);
> +
> +	ret = qla2xxx_get_ini_stats(fc_bsg_to_shost(bsg_job), req_data-
> >stat_type,
> +				    data, response_len);
> +
> +	rsp_data.status = EXT_STATUS_OK;
> +	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
> +
> +	bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job-
> >reply_payload.sg_list,
> +							       bsg_job-
> >reply_payload.sg_cnt,
> +							       data,
> response_len);
> +	bsg_reply->result = DID_OK;
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +		     bsg_reply->reply_payload_rcv_len);
> +
> +	kfree(data);
> +host_stat_out:
> +	kfree(req_data);
> +	return ret;
> +}
> +
> +static struct fc_rport *
> +qla2xxx_find_rport(scsi_qla_host_t *vha, uint32_t tgt_num)
> +{
> +	fc_port_t *fcport = NULL;
> +
> +	list_for_each_entry(fcport, &vha->vp_fcports, list) {
> +		if (fcport->rport->number == tgt_num)
> +			return fcport->rport;
> +	}
> +	return NULL;
> +}
> +
> +static int
> +qla2x00_get_tgt_stats(struct bsg_job *bsg_job)
> +{
> +	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
> +	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
> +	struct ql_vnd_tgt_stats_param *req_data;
> +	u32 req_data_len;
> +	int ret = 0;
> +	u64 response_len = 0;
> +	struct ql_vnd_tgt_stats_resp *data = NULL;
> +	struct fc_rport *rport = NULL;
> +
> +	if (!vha->flags.online) {
> +		ql_log(ql_log_warn, vha, 0x0000, "Host is not online.\n");
> +		return -EIO;
> +	}
> +
> +	req_data_len = bsg_job->request_payload.payload_len;
> +
> +	if (req_data_len != sizeof(struct ql_vnd_stat_entry)) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
> +		return -EIO;
> +	}
> +
> +	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
> +	if (!req_data) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation
> failure.\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* Copy the request buffer in req_data */
> +	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
> +			  bsg_job->request_payload.sg_cnt,
> +			  req_data, req_data_len);
> +
> +	response_len = sizeof(struct ql_vnd_tgt_stats_resp) +
> +		sizeof(struct ql_vnd_stat_entry);
> +
> +	if (response_len > bsg_job->reply_payload.payload_len) {
> +		data->status = EXT_STATUS_BUFFER_TOO_SMALL;
> +		bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
> EXT_STATUS_BUFFER_TOO_SMALL;
> +		bsg_job->reply_payload.payload_len = sizeof(struct
> ql_vnd_mng_host_stats_resp);
> +
> +		bsg_reply->reply_payload_rcv_len =
> +			sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
> +					    bsg_job->reply_payload.sg_cnt,
> &data,
> +					    sizeof(struct
> ql_vnd_tgt_stats_resp));
> +
> +		bsg_reply->result = DID_OK;
> +		bsg_job_done(bsg_job, bsg_reply->result,
> +			     bsg_reply->reply_payload_rcv_len);
> +		goto tgt_stat_out;
> +	}
> +
> +	/* structure + size for one entry */
> +	data = kzalloc(response_len, GFP_KERNEL);
> +	if (!data) {
> +		kfree(req_data);
> +		return -ENOMEM;
> +	}
> +
> +	rport = qla2xxx_find_rport(vha, req_data->tgt_id);
> +	if (!rport) {
> +		ql_log(ql_log_warn, vha, 0x0000, "target %d not found.\n",
> req_data->tgt_id);
> +		ret = EXT_STATUS_INVALID_PARAM;
> +		data->status = EXT_STATUS_INVALID_PARAM;
> +		goto reply;
> +	}
> +
> +	ret = qla2xxx_get_tgt_stats(fc_bsg_to_shost(bsg_job), req_data-
> >stat_type,
> +				    rport, (void *)data, response_len);
> +
> +	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
> +reply:
> +	bsg_reply->reply_payload_rcv_len =
> +		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
> +				    bsg_job->reply_payload.sg_cnt, data,
> +				    response_len);
> +	bsg_reply->result = DID_OK;
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +		     bsg_reply->reply_payload_rcv_len);
> +
> +	kfree(data);
> +tgt_stat_out:
> +	kfree(req_data);
> +
> +	return ret;
> +}
> +
> +static int
> +qla2x00_manage_host_port(struct bsg_job *bsg_job)
> +{
> +	scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
> +	struct fc_bsg_reply *bsg_reply = bsg_job->reply;
> +	struct ql_vnd_mng_host_port_param *req_data;
> +	struct ql_vnd_mng_host_port_resp rsp_data;
> +	u32 req_data_len;
> +	int ret = 0;
> +
> +	req_data_len = bsg_job->request_payload.payload_len;
> +
> +	if (req_data_len != sizeof(struct ql_vnd_mng_host_port_param)) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data_len invalid.\n");
> +		return -EIO;
> +	}
> +
> +	req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
> +	if (!req_data) {
> +		ql_log(ql_log_warn, vha, 0x0000, "req_data memory allocation
> failure.\n");
> +		return -ENOMEM;
> +	}
> +
> +	/* Copy the request buffer in req_data */
> +	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
> +			  bsg_job->request_payload.sg_cnt, req_data,
> req_data_len);
> +
> +	switch (req_data->action) {
> +	case 0:
> +		ret = qla2xxx_enable_port(vha->host);
> +		break;
> +	case 1:
> +		ret = qla2xxx_disable_port(vha->host);
> +		break;
> +	default:
> +		ql_log(ql_log_warn, vha, 0x0000, "Invalid action.\n");
> +		ret = -EIO;
> +		break;
> +	}
> +
> +	kfree(req_data);
> +
> +	/* Prepare response */
> +	rsp_data.status = ret;
> +	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
> +	bsg_job->reply_payload.payload_len = sizeof(struct
> ql_vnd_mng_host_port_resp);
> +
> +	bsg_reply->reply_payload_rcv_len =
> +		sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
> +				    bsg_job->reply_payload.sg_cnt, &rsp_data,
> +				    sizeof(struct ql_vnd_mng_host_port_resp));
> +	bsg_reply->result = DID_OK;
> +	bsg_job_done(bsg_job, bsg_reply->result,
> +		     bsg_reply->reply_payload_rcv_len);
> +
> +	return ret;
> +}
> +
>  static int
>  qla2x00_process_vendor_specific(struct bsg_job *bsg_job)
>  {
> @@ -2520,6 +2838,18 @@ qla2x00_process_vendor_specific(struct bsg_job
> *bsg_job)
>  	case QL_VND_SS_GET_FLASH_IMAGE_STATUS:
>  		return qla2x00_get_flash_image_status(bsg_job);
> 
> +	case QL_VND_MANAGE_HOST_STATS:
> +		return qla2x00_manage_host_stats(bsg_job);
> +
> +	case QL_VND_GET_HOST_STATS:
> +		return qla2x00_get_host_stats(bsg_job);
> +
> +	case QL_VND_GET_TGT_STATS:
> +		return qla2x00_get_tgt_stats(bsg_job);
> +
> +	case QL_VND_MANAGE_HOST_PORT:
> +		return qla2x00_manage_host_port(bsg_job);
> +
>  	default:
>  		return -ENOSYS;
>  	}
> @@ -2547,6 +2877,17 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
>  		vha = shost_priv(host);
>  	}
> 
> +	/* Disable port will bring down the chip, allow enable command */
> +	if (bsg_request->rqst_data.h_vendor.vendor_cmd[0] ==
> QL_VND_MANAGE_HOST_PORT ||
> +	    bsg_request->rqst_data.h_vendor.vendor_cmd[0] ==
> QL_VND_GET_HOST_STATS)
> +		goto skip_chip_chk;
> +
> +	if (vha->hw->flags.port_isolated) {
> +		bsg_reply->result = DID_ERROR;
> +		/* operation not permitted */
> +		return -EPERM;
> +	}
> +
>  	if (qla2x00_chip_is_down(vha)) {
>  		ql_dbg(ql_dbg_user, vha, 0x709f,
>  		    "BSG: ISP abort active/needed -- cmd=%d.\n",
> @@ -2554,6 +2895,7 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
>  		return -EBUSY;
>  	}
> 
> +skip_chip_chk:
>  	ql_dbg(ql_dbg_user, vha, 0x7000,
>  	    "Entered %s msgcode=0x%x.\n", __func__, bsg_request->msgcode);
> 
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
> index 1a09b5512267..0274e99e4a12 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.h
> +++ b/drivers/scsi/qla2xxx/qla_bsg.h
> @@ -31,6 +31,10 @@
>  #define QL_VND_DPORT_DIAGNOSTICS	0x19
>  #define QL_VND_GET_PRIV_STATS_EX	0x1A
>  #define QL_VND_SS_GET_FLASH_IMAGE_STATUS	0x1E
> +#define QL_VND_MANAGE_HOST_STATS	0x23
> +#define QL_VND_GET_HOST_STATS		0x24
> +#define QL_VND_GET_TGT_STATS		0x25
> +#define QL_VND_MANAGE_HOST_PORT		0x26
> 
>  /* BSG Vendor specific subcode returns */
>  #define EXT_STATUS_OK			0
> @@ -40,6 +44,7 @@
>  #define EXT_STATUS_DATA_OVERRUN		7
>  #define EXT_STATUS_DATA_UNDERRUN	8
>  #define EXT_STATUS_MAILBOX		11
> +#define EXT_STATUS_BUFFER_TOO_SMALL	16
>  #define EXT_STATUS_NO_MEMORY		17
>  #define EXT_STATUS_DEVICE_OFFLINE	22
> 
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 30c7e5e63851..f2f1b0231033 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -2557,6 +2557,10 @@ typedef struct fc_port {
>  	u16 n2n_chip_reset;
> 
>  	struct dentry *dfs_rport_dir;
> +
> +	u64 tgt_short_link_down_cnt;
> +	u64 tgt_link_down_time;
> +	u64 dev_loss_tmo;
>  } fc_port_t;
> 
>  enum {
> @@ -3922,6 +3926,7 @@ struct qla_hw_data {
>  		uint32_t	scm_enabled:1;
>  		uint32_t	max_req_queue_warned:1;
>  		uint32_t	plogi_template_valid:1;
> +		uint32_t	port_isolated:1;
>  	} flags;
> 
>  	uint16_t max_exchg;
> @@ -4851,6 +4856,13 @@ typedef struct scsi_qla_host {
>  	uint8_t	scm_fabric_connection_flags;
> 
>  	unsigned int irq_offset;
> +
> +	u64 hw_err_cnt;
> +	u64 interface_err_cnt;
> +	u64 cmd_timeout_cnt;
> +	u64 reset_cmd_err_cnt;
> +	u64 link_down_time;
> +	u64 short_link_down_cnt;
>  } scsi_qla_host_t;
> 
>  struct qla27xx_image_status {
> @@ -5174,6 +5186,65 @@ struct sff_8247_a0 {
>  #define PRLI_PHASE(_cls) \
>  	((_cls == DSC_LS_PRLI_PEND) || (_cls == DSC_LS_PRLI_COMP))
> 
> +enum ql_vnd_host_stat_action {
> +	stop = 0,
> +	start,
> +	clear,
> +};
> +
> +struct ql_vnd_mng_host_stats_param {
> +	u32 stat_type;
> +	enum ql_vnd_host_stat_action action;
> +} __packed;
> +
> +struct ql_vnd_mng_host_stats_resp {
> +	u32 status;
> +} __packed;
> +
> +struct ql_vnd_stats_param {
> +	u32 stat_type;
> +} __packed;
> +
> +struct ql_vnd_tgt_stats_param {
> +	s32 tgt_id;
> +	u32 stat_type;
> +} __packed;
> +
> +enum ql_vnd_host_port_action {
> +	enable = 0,
> +	disable,
> +};
> +
> +struct ql_vnd_mng_host_port_param {
> +	enum ql_vnd_host_port_action action;
> +} __packed;
> +
> +struct ql_vnd_mng_host_port_resp {
> +	u32 status;
> +} __packed;
> +
> +struct ql_vnd_stat_entry {
> +	u32 stat_type;	/* Failure type */
> +	u32 tgt_num;	/* Target Num */
> +	u64 cnt;	/* Counter value */
> +} __packed;
> +
> +struct ql_vnd_stats {
> +	u64 entry_count; /* Num of entries */
> +	u64 rservd;
> +	struct ql_vnd_stat_entry entry[0]; /* Place holder of entries */
> +} __packed;
> +
> +struct ql_vnd_host_stats_resp {
> +	u32 status;
> +	struct ql_vnd_stats stats;
> +} __packed;
> +
> +struct ql_vnd_tgt_stats_resp {
> +	u32 status;
> +	struct ql_vnd_stats stats;
> +} __packed;
> +
>  #include "qla_target.h"
>  #include "qla_gbl.h"
>  #include "qla_dbg.h"
> diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
> index e39b4f2da73a..708f82311b83 100644
> --- a/drivers/scsi/qla2xxx/qla_gbl.h
> +++ b/drivers/scsi/qla2xxx/qla_gbl.h
> @@ -945,4 +945,27 @@ extern void
> qla2x00_dfs_remove_rport(scsi_qla_host_t *vha, struct fc_port *fp);
>  /* nvme.c */
>  void qla_nvme_unregister_remote_port(struct fc_port *fcport);
>  void qla_handle_els_plogi_done(scsi_qla_host_t *vha, struct event_arg *ea);
> +
> +#define QLA2XX_HW_ERROR			BIT_0
> +#define QLA2XX_SHT_LNK_DWN		BIT_1
> +#define QLA2XX_INT_ERR			BIT_2
> +#define QLA2XX_CMD_TIMEOUT		BIT_3
> +#define QLA2XX_RESET_CMD_ERR		BIT_4
> +#define QLA2XX_TGT_SHT_LNK_DOWN		BIT_17
> +
> +#define QLA2XX_MAX_LINK_DOWN_TIME	100
> +
> +int qla2xxx_start_stats(struct Scsi_Host *shost, u32 flags);
> +int qla2xxx_stop_stats(struct Scsi_Host *shost, u32 flags);
> +int qla2xxx_reset_stats(struct Scsi_Host *shost, u32 flags);
> +
> +int qla2xxx_get_ini_stats(struct Scsi_Host *shost, u32 flags, void *data, u64
> size);
> +int qla2xxx_get_tgt_stats(struct Scsi_Host *shost, u32 flags,
> +			  struct fc_rport *rport, void *data, u64 size);
> +int qla2xxx_disable_port(struct Scsi_Host *shost);
> +int qla2xxx_enable_port(struct Scsi_Host *shost);
> +
> +uint64_t qla2x00_get_num_tgts(scsi_qla_host_t *vha);
> +uint64_t qla2x00_count_set_bits(u32 num);
> +
>  #endif /* _QLA_GBL_H */
> diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
> index 391ac75e3de3..517d358b0031 100644
> --- a/drivers/scsi/qla2xxx/qla_gs.c
> +++ b/drivers/scsi/qla2xxx/qla_gs.c
> @@ -3563,6 +3563,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t
> *vha, srb_t *sp)
>  					       __func__, __LINE__,
>  					       fcport->port_name);
> 
> +					fcport->tgt_link_down_time = 0;
> 
> 	qlt_schedule_sess_for_deletion(fcport);
>  					continue;
>  				}
> diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
> index dcc0f0d823db..410ff5534a59 100644
> --- a/drivers/scsi/qla2xxx/qla_init.c
> +++ b/drivers/scsi/qla2xxx/qla_init.c
> @@ -4993,6 +4993,9 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t
> flags)
>  	fcport->login_retry = vha->hw->login_retry_count;
>  	fcport->chip_reset = vha->hw->base_qpair->chip_reset;
>  	fcport->logout_on_delete = 1;
> +	fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
> +	fcport->tgt_short_link_down_cnt = 0;
> +	fcport->dev_loss_tmo = 0;
> 
>  	if (!fcport->ct_desc.ct_sns) {
>  		ql_log(ql_log_warn, vha, 0xd049,
> @@ -5490,6 +5493,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha,
> fc_port_t *fcport)
>  	spin_lock_irqsave(fcport->vha->host->host_lock, flags);
>  	*((fc_port_t **)rport->dd_data) = fcport;
>  	spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
> +	fcport->dev_loss_tmo = rport->dev_loss_tmo;
> 
>  	rport->supported_classes = fcport->supported_classes;
> 
> @@ -5548,6 +5552,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha,
> fc_port_t *fcport)
>  		fcport->logout_on_delete = 1;
>  	fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
> 
> +	if (fcport->tgt_link_down_time < fcport->dev_loss_tmo) {
> +		fcport->tgt_short_link_down_cnt++;
> +		fcport->tgt_link_down_time =
> QLA2XX_MAX_LINK_DOWN_TIME;
> +	}
> +
>  	switch (vha->hw->current_topology) {
>  	case ISP_CFG_N:
>  	case ISP_CFG_NL:
> @@ -6908,6 +6917,9 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
>  	if (vha->flags.online) {
>  		qla2x00_abort_isp_cleanup(vha);
> 
> +		if (vha->hw->flags.port_isolated)
> +			return status;
> +
>  		if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha-
> >dpc_flags)) {
>  			ha->flags.chip_reset_done = 1;
>  			vha->flags.online = 1;
> @@ -7029,6 +7041,11 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
> 
>  	}
> 
> +	if (vha->hw->flags.port_isolated) {
> +		qla2x00_abort_isp_cleanup(vha);
> +		return status;
> +	}
> +
>  	if (!status) {
>  		ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n",
> __func__);
>  		qla2x00_configure_hba(vha);
> @@ -9171,3 +9188,202 @@ int qla2xxx_delete_qpair(struct scsi_qla_host
> *vha, struct qla_qpair *qpair)
>  fail:
>  	return ret;
>  }
> +
> +uint64_t
> +qla2x00_count_set_bits(uint32_t num)
> +{
> +	/* Brian Kernighan's Alogorithm */
> +	u64 count = 0;
> +
> +	while (num) {
> +		num &= (num - 1);
> +		count++;
> +	}
> +	return count;
> +}
> +
> +uint64_t
> +qla2x00_get_num_tgts(scsi_qla_host_t *vha)
> +{
> +	fc_port_t *f, *tf;
> +	u64 count = 0;
> +
> +	f = NULL;
> +	tf = NULL;
> +
> +	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
> +		if (f->port_type != FCT_TARGET)
> +			continue;
> +		count++;
> +	}
> +	return count;
> +}
> +
> +int qla2xxx_reset_stats(struct Scsi_Host *host, u32 flags)
> +{
> +	scsi_qla_host_t *vha = shost_priv(host);
> +	fc_port_t *fcport = NULL;
> +	unsigned long int_flags;
> +
> +	if (flags & QLA2XX_HW_ERROR)
> +		vha->hw_err_cnt = 0;
> +	if (flags & QLA2XX_SHT_LNK_DWN)
> +		vha->short_link_down_cnt = 0;
> +	if (flags & QLA2XX_INT_ERR)
> +		vha->interface_err_cnt = 0;
> +	if (flags & QLA2XX_CMD_TIMEOUT)
> +		vha->cmd_timeout_cnt = 0;
> +	if (flags & QLA2XX_RESET_CMD_ERR)
> +		vha->reset_cmd_err_cnt = 0;
> +	if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
> +		spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
> +		list_for_each_entry(fcport, &vha->vp_fcports, list) {
> +			fcport->tgt_short_link_down_cnt = 0;
> +			fcport->tgt_link_down_time =
> QLA2XX_MAX_LINK_DOWN_TIME;
> +		}
> +		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
> +	}
> +	vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
> +	return 0;
> +}
> +
> +int qla2xxx_start_stats(struct Scsi_Host *host, u32 flags)
> +{
> +	return qla2xxx_reset_stats(host, flags);
> +}
> +
> +int qla2xxx_stop_stats(struct Scsi_Host *host, u32 flags)
> +{
> +	return qla2xxx_reset_stats(host, flags);
> +}
> +
> +int qla2xxx_get_ini_stats(struct Scsi_Host *host, u32 flags,
> +			  void *data, u64 size)
> +{
> +	scsi_qla_host_t *vha = shost_priv(host);
> +	struct ql_vnd_host_stats_resp *resp = (struct ql_vnd_host_stats_resp
> *)data;
> +	struct ql_vnd_stats *rsp_data = &resp->stats;
> +	u64 ini_entry_count = 0;
> +	u64 i = 0;
> +	u64 entry_count = 0;
> +	u64 num_tgt = 0;
> +	u32 tmp_stat_type = 0;
> +	fc_port_t *fcport = NULL;
> +	unsigned long int_flags;
> +
> +	/* Copy stat type to work on it */
> +	tmp_stat_type = flags;
> +
> +	if (tmp_stat_type & BIT_17) {
> +		num_tgt = qla2x00_get_num_tgts(vha);
> +		/* unset BIT_17 */
> +		tmp_stat_type &= ~(1 << 17);
> +	}
> +	ini_entry_count = qla2x00_count_set_bits(tmp_stat_type);
> +
> +	entry_count = ini_entry_count + num_tgt;
> +
> +	rsp_data->entry_count = entry_count;
> +
> +	i = 0;
> +	if (flags & QLA2XX_HW_ERROR) {
> +		rsp_data->entry[i].stat_type = QLA2XX_HW_ERROR;
> +		rsp_data->entry[i].tgt_num = 0x0;
> +		rsp_data->entry[i].cnt = vha->hw_err_cnt;
> +		i++;
> +	}
> +
> +	if (flags & QLA2XX_SHT_LNK_DWN) {
> +		rsp_data->entry[i].stat_type = QLA2XX_SHT_LNK_DWN;
> +		rsp_data->entry[i].tgt_num = 0x0;
> +		rsp_data->entry[i].cnt = vha->short_link_down_cnt;
> +		i++;
> +	}
> +
> +	if (flags & QLA2XX_INT_ERR) {
> +		rsp_data->entry[i].stat_type = QLA2XX_INT_ERR;
> +		rsp_data->entry[i].tgt_num = 0x0;
> +		rsp_data->entry[i].cnt = vha->interface_err_cnt;
> +		i++;
> +	}
> +
> +	if (flags & QLA2XX_CMD_TIMEOUT) {
> +		rsp_data->entry[i].stat_type = QLA2XX_CMD_TIMEOUT;
> +		rsp_data->entry[i].tgt_num = 0x0;
> +		rsp_data->entry[i].cnt = vha->cmd_timeout_cnt;
> +		i++;
> +	}
> +
> +	if (flags & QLA2XX_RESET_CMD_ERR) {
> +		rsp_data->entry[i].stat_type = QLA2XX_RESET_CMD_ERR;
> +		rsp_data->entry[i].tgt_num = 0x0;
> +		rsp_data->entry[i].cnt = vha->reset_cmd_err_cnt;
> +		i++;
> +	}
> +
> +	/* i will continue from previous loop, as target
> +	 * entries are after initiator
> +	 */
> +	if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
> +		spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
> +		list_for_each_entry(fcport, &vha->vp_fcports, list) {
> +			if (fcport->port_type != FCT_TARGET)
> +				continue;
> +			if (!fcport->rport)
> +				continue;
> +			rsp_data->entry[i].stat_type =
> QLA2XX_TGT_SHT_LNK_DOWN;
> +			rsp_data->entry[i].tgt_num = fcport->rport->number;
> +			rsp_data->entry[i].cnt = fcport-
> >tgt_short_link_down_cnt;
> +			i++;
> +		}
> +		spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
> +	}
> +	resp->status = EXT_STATUS_OK;
> +
> +	return 0;
> +}
> +
> +int qla2xxx_get_tgt_stats(struct Scsi_Host *host, u32 flags,
> +			  struct fc_rport *rport, void *data, u64 size)
> +{
> +	struct ql_vnd_tgt_stats_resp *tgt_data = data;
> +	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
> +
> +	tgt_data->status = 0;
> +	tgt_data->stats.entry_count = 1;
> +	tgt_data->stats.entry[0].stat_type = flags;
> +	tgt_data->stats.entry[0].tgt_num = rport->number;
> +	tgt_data->stats.entry[0].cnt = fcport->tgt_short_link_down_cnt;
> +
> +	return 0;
> +}
> +
> +int qla2xxx_disable_port(struct Scsi_Host *host)
> +{
> +	scsi_qla_host_t *vha = shost_priv(host);
> +
> +	vha->hw->flags.port_isolated = 1;
> +
> +	if (qla2x00_chip_is_down(vha))
> +		return 0;
> +
> +	if (vha->flags.online) {
> +		qla2x00_abort_isp_cleanup(vha);
> +		qla2x00_wait_for_sess_deletion(vha);
> +	}
> +
> +	return 0;
> +}
> +
> +int qla2xxx_enable_port(struct Scsi_Host *host)
> +{
> +	scsi_qla_host_t *vha = shost_priv(host);
> +
> +	vha->hw->flags.port_isolated = 0;
> +	/* Set the flag to 1, so that isp_abort can proceed */
> +	vha->flags.online = 1;
> +	set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
> +	qla2xxx_wake_dpc(vha);
> +
> +	return 0;
> +}
> diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
> index f9142dbec112..9cf8326ab9fc 100644
> --- a/drivers/scsi/qla2xxx/qla_isr.c
> +++ b/drivers/scsi/qla2xxx/qla_isr.c
> @@ -1059,6 +1059,9 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct
> rsp_que *rsp, uint16_t *mb)
> 
>  	case MBA_SYSTEM_ERR:		/* System Error */
>  		mbx = 0;
> +
> +		vha->hw_err_cnt++;
> +
>  		if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
>  		    IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
>  			u16 m[4];
> @@ -1112,6 +1115,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct
> rsp_que *rsp, uint16_t *mb)
>  		ql_log(ql_log_warn, vha, 0x5006,
>  		    "ISP Request Transfer Error (%x).\n",  mb[1]);
> 
> +		vha->hw_err_cnt++;
> +
>  		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
>  		break;
> 
> @@ -1119,6 +1124,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct
> rsp_que *rsp, uint16_t *mb)
>  		ql_log(ql_log_warn, vha, 0x5007,
>  		    "ISP Response Transfer Error (%x).\n", mb[1]);
> 
> +		vha->hw_err_cnt++;
> +
>  		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
>  		break;
> 
> @@ -1176,12 +1183,18 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct
> rsp_que *rsp, uint16_t *mb)
>  		vha->flags.management_server_logged_in = 0;
>  		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha-
> >link_data_rate);
> 
> +		if (vha->link_down_time < vha->hw->port_down_retry_count) {
> +			vha->short_link_down_cnt++;
> +			vha->link_down_time =
> QLA2XX_MAX_LINK_DOWN_TIME;
> +		}
> +
>  		break;
> 
>  	case MBA_LOOP_DOWN:		/* Loop Down Event */
>  		SAVE_TOPO(ha);
>  		ha->flags.lip_ae = 0;
>  		ha->current_topology = 0;
> +		vha->link_down_time = 0;
> 
>  		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
>  			? rd_reg_word(&reg24->mailbox4) : 0;
> @@ -1503,6 +1516,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct
> rsp_que *rsp, uint16_t *mb)
>  		ql_dbg(ql_dbg_async, vha, 0x5016,
>  		    "Discard RND Frame -- %04x %04x %04x.\n",
>  		    mb[1], mb[2], mb[3]);
> +		vha->interface_err_cnt++;
>  		break;
> 
>  	case MBA_TRACE_NOTIFICATION:
> @@ -1592,6 +1606,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct
> rsp_que *rsp, uint16_t *mb)
> 
>  	case MBA_IDC_AEN:
>  		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
> +			vha->hw_err_cnt++;
>  			qla27xx_handle_8200_aen(vha, mb);
>  		} else if (IS_QLA83XX(ha)) {
>  			mb[4] = rd_reg_word(&reg24->mailbox4);
> @@ -3101,6 +3116,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct
> rsp_que *rsp, void *pkt)
>  				    "Dropped frame(s) detected (0x%x of 0x%x
> bytes).\n",
>  				    resid, scsi_bufflen(cp));
> 
> +				vha->interface_err_cnt++;
> +
>  				res = DID_ERROR << 16 | lscsi_status;
>  				goto check_scsi_status;
>  			}
> @@ -3126,6 +3143,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct
> rsp_que *rsp, void *pkt)
>  			    "Dropped frame(s) detected (0x%x of 0x%x
> bytes).\n",
>  			    resid, scsi_bufflen(cp));
> 
> +			vha->interface_err_cnt++;
> +
>  			res = DID_ERROR << 16 | lscsi_status;
>  			goto check_scsi_status;
>  		} else {
> @@ -3208,6 +3227,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct
> rsp_que *rsp, void *pkt)
> 
>  	case CS_TRANSPORT:
>  		res = DID_ERROR << 16;
> +		vha->hw_err_cnt++;
> 
>  		if (!IS_PI_SPLIT_DET_CAPABLE(ha))
>  			break;
> @@ -3228,6 +3248,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct
> rsp_que *rsp, void *pkt)
>  		ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee,
>  		    pkt, sizeof(*sts24));
>  		res = DID_ERROR << 16;
> +		vha->hw_err_cnt++;
>  		break;
>  	default:
>  		res = DID_ERROR << 16;
> @@ -3839,6 +3860,7 @@ qla24xx_msix_default(int irq, void *dev_id)
>  			    hccr);
> 
>  			qla2xxx_check_risc_status(vha);
> +			vha->hw_err_cnt++;
> 
>  			ha->isp_ops->fw_dump(vha);
>  			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index d7d4ab65009c..f438cdedca23 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -180,6 +180,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha,
> mbx_cmd_t *mcp)
>  		ql_log(ql_log_warn, vha, 0xd035,
>  		    "Cmd access timeout, cmd=0x%x, Exiting.\n",
>  		    mcp->mb[0]);
> +		vha->hw_err_cnt++;
>  		atomic_dec(&ha->num_pend_mbx_stage1);
>  		return QLA_FUNCTION_TIMEOUT;
>  	}
> @@ -307,6 +308,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha,
> mbx_cmd_t *mcp)
>  				atomic_dec(&ha->num_pend_mbx_stage2);
>  				ql_dbg(ql_dbg_mbx, vha, 0x1012,
>  				    "Pending mailbox timeout, exiting.\n");
> +				vha->hw_err_cnt++;
>  				rval = QLA_FUNCTION_TIMEOUT;
>  				goto premature_exit;
>  			}
> @@ -418,6 +420,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha,
> mbx_cmd_t *mcp)
>  			    "mb[0-3]=[0x%x 0x%x 0x%x 0x%x] mb7 0x%x
> host_status 0x%x hccr 0x%x\n",
>  			    command, ictrl, jiffies, mb[0], mb[1], mb[2], mb[3],
>  			    mb[7], host_status, hccr);
> +			vha->hw_err_cnt++;
> 
>  		} else {
>  			mb[0] = RD_MAILBOX_REG(ha, &reg->isp, 0);
> @@ -425,6 +428,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha,
> mbx_cmd_t *mcp)
>  			ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119,
>  			    "MBX Command timeout for cmd %x, iocontrol=%x
> jiffies=%lx "
>  			    "mb[0]=0x%x\n", command, ictrl, jiffies, mb[0]);
> +			vha->hw_err_cnt++;
>  		}
>  		ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019);
> 
> @@ -497,6 +501,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha,
> mbx_cmd_t *mcp)
>  				    "mb[0]=0x%x, eeh_busy=0x%x. Scheduling
> ISP "
>  				    "abort.\n", command, mcp->mb[0],
>  				    ha->flags.eeh_busy);
> +				vha->hw_err_cnt++;
>  				set_bit(ISP_ABORT_NEEDED, &vha-
> >dpc_flags);
>  				qla2xxx_wake_dpc(vha);
>  			}
> @@ -521,6 +526,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha,
> mbx_cmd_t *mcp)
>  				    "Mailbox cmd timeout occurred, cmd=0x%x,
> "
>  				    "mb[0]=0x%x. Scheduling ISP abort ",
>  				    command, mcp->mb[0]);
> +				vha->hw_err_cnt++;
>  				set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
>  				clear_bit(ISP_ABORT_NEEDED, &vha-
> >dpc_flags);
>  				/* Allow next mbx cmd to come in. */
> @@ -625,6 +631,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t
> req_dma, uint32_t risc_addr,
>  		ql_dbg(ql_dbg_mbx, vha, 0x1023,
>  		    "Failed=%x mb[0]=%x mb[1]=%x.\n",
>  		    rval, mcp->mb[0], mcp->mb[1]);
> +		vha->hw_err_cnt++;
>  	} else {
>  		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1024,
>  		    "Done %s.\n", __func__);
> @@ -736,6 +743,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t
> risc_addr)
> 
>  		ql_dbg(ql_dbg_mbx, vha, 0x1026,
>  		    "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
> +		vha->hw_err_cnt++;
>  		return rval;
>  	}
> 
> @@ -1313,6 +1321,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
>  	if (rval != QLA_SUCCESS) {
>  		/*EMPTY*/
>  		ql_dbg(ql_dbg_mbx, vha, 0x1033, "Failed=%x.\n", rval);
> +		vha->hw_err_cnt++;
>  	} else {
>  		/*EMPTY*/
>  		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1034,
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index f80abe28f35a..a760cb38e487 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -1274,6 +1274,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
>  	sp = scsi_cmd_priv(cmd);
>  	qpair = sp->qpair;
> 
> +	vha->cmd_timeout_cnt++;
> +
>  	if ((sp->fcport && sp->fcport->deleted) || !qpair)
>  		return SUCCESS;
> 
> @@ -1442,6 +1444,7 @@ __qla2xxx_eh_generic_reset(char *name, enum
> nexus_wait_type type,
>  	    "%s RESET FAILED: %s nexus=%ld:%d:%llu cmd=%p.\n", name,
>  	    reset_errors[err], vha->host_no, cmd->device->id, cmd->device->lun,
>  	    cmd);
> +	vha->reset_cmd_err_cnt++;
>  	return FAILED;
>  }
> 
> @@ -3141,6 +3144,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const
> struct pci_device_id *id)
>  	ha->mr.fcport.supported_classes = FC_COS_UNSPECIFIED;
>  	ha->mr.fcport.scan_state = 1;
> 
> +	qla2xxx_reset_stats(host, QLA2XX_HW_ERROR |
> QLA2XX_SHT_LNK_DWN |
> +			    QLA2XX_INT_ERR | QLA2XX_CMD_TIMEOUT |
> +			    QLA2XX_RESET_CMD_ERR |
> QLA2XX_TGT_SHT_LNK_DOWN);
> +
>  	/* Set the SG table size based on ISP type */
>  	if (!IS_FWI2_CAPABLE(ha)) {
>  		if (IS_QLA2100(ha))
> @@ -5090,6 +5097,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host
> *vha, struct qla_work_evt *e)
>  			fcport->d_id = e->u.new_sess.id;
>  			fcport->flags |= FCF_FABRIC_DEVICE;
>  			fcport->fw_login_state = DSC_LS_PLOGI_PEND;
> +			fcport->tgt_short_link_down_cnt = 0;
> 
>  			memcpy(fcport->port_name, e-
> >u.new_sess.port_name,
>  			    WWN_SIZE);
> @@ -7061,6 +7069,8 @@ qla2x00_timer(struct timer_list *t)
>  	uint16_t        w;
>  	struct qla_hw_data *ha = vha->hw;
>  	struct req_que *req;
> +	unsigned long flags;
> +	fc_port_t *fcport = NULL;
> 
>  	if (ha->flags.eeh_busy) {
>  		ql_dbg(ql_dbg_timer, vha, 0x6000,
> @@ -7092,6 +7102,16 @@ qla2x00_timer(struct timer_list *t)
>  	if (!vha->vp_idx && IS_QLAFX00(ha))
>  		qlafx00_timer_routine(vha);
> 
> +	if (vha->link_down_time < QLA2XX_MAX_LINK_DOWN_TIME)
> +		vha->link_down_time++;
> +
> +	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
> +	list_for_each_entry(fcport, &vha->vp_fcports, list) {
> +		if (fcport->tgt_link_down_time <
> QLA2XX_MAX_LINK_DOWN_TIME)
> +			fcport->tgt_link_down_time++;
> +	}
> +	spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
> +
>  	/* Loop down handler. */
>  	if (atomic_read(&vha->loop_down_timer) > 0 &&
>  	    !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
> --
> 2.19.0.rc0


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

end of thread, other threads:[~2021-01-05  6:12 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-05  6:03 [PATCH v2 0/7] qla2xxx driver enhancements Nilesh Javali
2021-01-05  6:03 ` [PATCH v2 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
2021-01-05  6:11   ` Saurav Kashyap
2021-01-05  6:03 ` [PATCH v2 2/7] qla2xxx: Add error counters to debugfs node Nilesh Javali
2021-01-05  6:03 ` [PATCH v2 3/7] qla2xxx: Move some messages from debug to normal log level Nilesh Javali
2021-01-05  6:03 ` [PATCH v2 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe Nilesh Javali
2021-01-05  6:03 ` [PATCH v2 5/7] qla2xxx: Fix mailbox Ch erroneous error Nilesh Javali
2021-01-05  6:03 ` [PATCH v2 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER Nilesh Javali
2021-01-05  6:03 ` [PATCH v2 7/7] qla2xxx: Update version to 10.02.00.105-k Nilesh Javali

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.