* [PATCH v4 0/7] qla2xxx driver enhancements
@ 2021-01-11 9:31 Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
` (8 more replies)
0 siblings, 9 replies; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 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.
v4:
Use defined enums.
Make commit messages more descriptive.
Add Reviewed-by tag.
v3:
Add complete fix for the warning reported by kernel test robot.
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 | 83 ++++---
drivers/scsi/qla2xxx/qla_mbx.c | 18 +-
drivers/scsi/qla2xxx/qla_nvme.c | 91 +++++++-
drivers/scsi/qla2xxx/qla_os.c | 25 +++
drivers/scsi/qla2xxx/qla_version.h | 4 +-
16 files changed, 943 insertions(+), 41 deletions(-)
base-commit: be1b500212541a70006887bae558ff834d7365d0
--
2.19.0.rc0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v4 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
@ 2021-01-11 9:31 ` Nilesh Javali
2021-01-12 16:58 ` Himanshu Madhani
2021-01-11 9:31 ` [PATCH v4 2/7] qla2xxx: Add error counters to debugfs node Nilesh Javali
` (7 subsequent siblings)
8 siblings, 1 reply; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 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. It also provides a capability to isolate the port or bring it
out of isolation.
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..e45da05383cd 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 QLA_STOP:
+ ret = qla2xxx_stop_stats(vha->host, req_data->stat_type);
+ break;
+ case QLA_START:
+ ret = qla2xxx_start_stats(vha->host, req_data->stat_type);
+ break;
+ case QLA_CLEAR:
+ 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);
+
+ /* structure + size for one entry */
+ data = kzalloc(response_len, GFP_KERNEL);
+ if (!data) {
+ kfree(req_data);
+ return -ENOMEM;
+ }
+
+ 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;
+ }
+
+ 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);
+
+tgt_stat_out:
+ kfree(data);
+ 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 QLA_ENABLE:
+ ret = qla2xxx_enable_port(vha->host);
+ break;
+ case QLA_DISABLE:
+ 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..ca67be8b62ec 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 {
+ QLA_STOP = 0,
+ QLA_START,
+ QLA_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 {
+ QLA_ENABLE = 0,
+ QLA_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(®24->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(®24->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, ®->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] 12+ messages in thread
* [PATCH v4 2/7] qla2xxx: Add error counters to debugfs node
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
@ 2021-01-11 9:31 ` Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 3/7] qla2xxx: Move some messages from debug to normal log level Nilesh Javali
` (6 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 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>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.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] 12+ messages in thread
* [PATCH v4 3/7] qla2xxx: Move some messages from debug to normal log level
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 2/7] qla2xxx: Add error counters to debugfs node Nilesh Javali
@ 2021-01-11 9:31 ` Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe Nilesh Javali
` (5 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 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 arising because of dropped frame,
DIF errors, queue full etc 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] 12+ messages in thread
* [PATCH v4 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
` (2 preceding siblings ...)
2021-01-11 9:31 ` [PATCH v4 3/7] qla2xxx: Move some messages from debug to normal log level Nilesh Javali
@ 2021-01-11 9:31 ` Nilesh Javali
2021-01-12 14:40 ` Himanshu Madhani
2021-01-11 9:31 ` [PATCH v4 5/7] qla2xxx: Fix mailbox Ch erroneous error Nilesh Javali
` (4 subsequent siblings)
8 siblings, 1 reply; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 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 | 9 +++-
drivers/scsi/qla2xxx/qla_mbx.c | 6 +++
drivers/scsi/qla2xxx/qla_nvme.c | 91 ++++++++++++++++++++++++++++++++-
drivers/scsi/qla2xxx/qla_os.c | 5 ++
9 files changed, 160 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index ca67be8b62ec..49b42b430df4 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..5ceb45dfd6c7 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);
@@ -3438,7 +3440,12 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
return;
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..017b4c272531 100644
--- a/drivers/scsi/qla2xxx/qla_nvme.c
+++ b/drivers/scsi/qla2xxx/qla_nvme.c
@@ -245,6 +245,13 @@ 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 +291,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 +597,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 +751,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] 12+ messages in thread
* [PATCH v4 5/7] qla2xxx: Fix mailbox Ch erroneous error
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
` (3 preceding siblings ...)
2021-01-11 9:31 ` [PATCH v4 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe Nilesh Javali
@ 2021-01-11 9:31 ` Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER Nilesh Javali
` (3 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 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>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.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(®->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
wrt_reg_word(®->mailbox1, LSW(addr));
wrt_reg_word(®->mailbox8, MSW(addr));
+ wrt_reg_word(®->mailbox10, 0);
wrt_reg_word(®->mailbox2, MSW(LSD(dump_dma)));
wrt_reg_word(®->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] 12+ messages in thread
* [PATCH v4 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
` (4 preceding siblings ...)
2021-01-11 9:31 ` [PATCH v4 5/7] qla2xxx: Fix mailbox Ch erroneous error Nilesh Javali
@ 2021-01-11 9:31 ` Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 7/7] qla2xxx: Update version to 10.02.00.105-k Nilesh Javali
` (2 subsequent siblings)
8 siblings, 0 replies; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 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>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.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] 12+ messages in thread
* [PATCH v4 7/7] qla2xxx: Update version to 10.02.00.105-k
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
` (5 preceding siblings ...)
2021-01-11 9:31 ` [PATCH v4 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER Nilesh Javali
@ 2021-01-11 9:31 ` Nilesh Javali
2021-01-13 5:37 ` [PATCH v4 0/7] qla2xxx driver enhancements Martin K. Petersen
2021-01-15 4:08 ` Martin K. Petersen
8 siblings, 0 replies; 12+ messages in thread
From: Nilesh Javali @ 2021-01-11 9:31 UTC (permalink / raw)
To: martin.petersen; +Cc: linux-scsi, GR-QLogic-Storage-Upstream
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.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] 12+ messages in thread
* Re: [PATCH v4 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe
2021-01-11 9:31 ` [PATCH v4 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe Nilesh Javali
@ 2021-01-12 14:40 ` Himanshu Madhani
0 siblings, 0 replies; 12+ messages in thread
From: Himanshu Madhani @ 2021-01-12 14:40 UTC (permalink / raw)
To: Nilesh Javali; +Cc: Martin K. Petersen, linux-scsi, GR-QLogic-Storage-Upstream
> On Jan 11, 2021, at 3:31 AM, Nilesh Javali <njavali@marvell.com> wrote:
>
> 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 | 9 +++-
> drivers/scsi/qla2xxx/qla_mbx.c | 6 +++
> drivers/scsi/qla2xxx/qla_nvme.c | 91 ++++++++++++++++++++++++++++++++-
> drivers/scsi/qla2xxx/qla_os.c | 5 ++
> 9 files changed, 160 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index ca67be8b62ec..49b42b430df4 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..5ceb45dfd6c7 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);
> @@ -3438,7 +3440,12 @@ qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
> return;
>
> 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..017b4c272531 100644
> --- a/drivers/scsi/qla2xxx/qla_nvme.c
> +++ b/drivers/scsi/qla2xxx/qla_nvme.c
> @@ -245,6 +245,13 @@ 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 +291,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 +597,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 +751,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
>
Looks Good
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
--
Himanshu Madhani Oracle Linux Engineering
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port
2021-01-11 9:31 ` [PATCH v4 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
@ 2021-01-12 16:58 ` Himanshu Madhani
0 siblings, 0 replies; 12+ messages in thread
From: Himanshu Madhani @ 2021-01-12 16:58 UTC (permalink / raw)
To: Nilesh Javali; +Cc: Martin K. Petersen, linux-scsi, GR-QLogic-Storage-Upstream
> On Jan 11, 2021, at 3:31 AM, Nilesh Javali <njavali@marvell.com> wrote:
>
> From: Saurav Kashyap <skashyap@marvell.com>
>
> This statistics will help in debugging process and checking specific
> error counts. It also provides a capability to isolate the port or bring it
> out of isolation.
>
> 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..e45da05383cd 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 QLA_STOP:
> + ret = qla2xxx_stop_stats(vha->host, req_data->stat_type);
> + break;
> + case QLA_START:
> + ret = qla2xxx_start_stats(vha->host, req_data->stat_type);
> + break;
> + case QLA_CLEAR:
> + 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);
> +
> + /* structure + size for one entry */
> + data = kzalloc(response_len, GFP_KERNEL);
> + if (!data) {
> + kfree(req_data);
> + return -ENOMEM;
> + }
> +
> + 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;
> + }
> +
> + 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);
> +
> +tgt_stat_out:
> + kfree(data);
> + 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 QLA_ENABLE:
> + ret = qla2xxx_enable_port(vha->host);
> + break;
> + case QLA_DISABLE:
> + 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..ca67be8b62ec 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 {
> + QLA_STOP = 0,
> + QLA_START,
> + QLA_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 {
> + QLA_ENABLE = 0,
> + QLA_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(®24->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(®24->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, ®->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
>
Looks good.
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
--
Himanshu Madhani Oracle Linux Engineering
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/7] qla2xxx driver enhancements
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
` (6 preceding siblings ...)
2021-01-11 9:31 ` [PATCH v4 7/7] qla2xxx: Update version to 10.02.00.105-k Nilesh Javali
@ 2021-01-13 5:37 ` Martin K. Petersen
2021-01-15 4:08 ` Martin K. Petersen
8 siblings, 0 replies; 12+ messages in thread
From: Martin K. Petersen @ 2021-01-13 5:37 UTC (permalink / raw)
To: Nilesh Javali; +Cc: martin.petersen, linux-scsi, GR-QLogic-Storage-Upstream
Nilesh,
> Please apply the qla2xxx driver enhancements to the scsi tree at your
> earliest convenience.
Applied to 5.12/scsi-staging, thanks!
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v4 0/7] qla2xxx driver enhancements
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
` (7 preceding siblings ...)
2021-01-13 5:37 ` [PATCH v4 0/7] qla2xxx driver enhancements Martin K. Petersen
@ 2021-01-15 4:08 ` Martin K. Petersen
8 siblings, 0 replies; 12+ messages in thread
From: Martin K. Petersen @ 2021-01-15 4:08 UTC (permalink / raw)
To: Nilesh Javali; +Cc: Martin K . Petersen, GR-QLogic-Storage-Upstream, linux-scsi
On Mon, 11 Jan 2021 01:31:27 -0800, Nilesh Javali wrote:
> Martin,
>
> Please apply the qla2xxx driver enhancements to the scsi tree at your
> earliest convenience.
>
> v4:
> Use defined enums.
> Make commit messages more descriptive.
> Add Reviewed-by tag.
>
> [...]
Applied to 5.12/scsi-queue, thanks!
[1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port
https://git.kernel.org/mkp/scsi/c/dbf1f53cfd23
[2/7] qla2xxx: Add error counters to debugfs node
https://git.kernel.org/mkp/scsi/c/307862e6697a
[3/7] qla2xxx: Move some messages from debug to normal log level
https://git.kernel.org/mkp/scsi/c/daaecb41a278
[4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe
https://git.kernel.org/mkp/scsi/c/a04658594399
[5/7] qla2xxx: Fix mailbox Ch erroneous error
https://git.kernel.org/mkp/scsi/c/044c218b0450
[6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER
https://git.kernel.org/mkp/scsi/c/ffa018e3a5b4
[7/7] qla2xxx: Update version to 10.02.00.105-k
https://git.kernel.org/mkp/scsi/c/dc0d9b12b8a7
--
Martin K. Petersen Oracle Linux Engineering
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2021-01-15 4:09 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-11 9:31 [PATCH v4 0/7] qla2xxx driver enhancements Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 1/7] qla2xxx: Implementation to get and manage host, target stats and initiator port Nilesh Javali
2021-01-12 16:58 ` Himanshu Madhani
2021-01-11 9:31 ` [PATCH v4 2/7] qla2xxx: Add error counters to debugfs node Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 3/7] qla2xxx: Move some messages from debug to normal log level Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 4/7] qla2xxx: Wait for ABTS response on I/O timeouts for NVMe Nilesh Javali
2021-01-12 14:40 ` Himanshu Madhani
2021-01-11 9:31 ` [PATCH v4 5/7] qla2xxx: Fix mailbox Ch erroneous error Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 6/7] qla2xxx: Enable NVME CONF (BIT_7) when enabling SLER Nilesh Javali
2021-01-11 9:31 ` [PATCH v4 7/7] qla2xxx: Update version to 10.02.00.105-k Nilesh Javali
2021-01-13 5:37 ` [PATCH v4 0/7] qla2xxx driver enhancements Martin K. Petersen
2021-01-15 4:08 ` Martin K. Petersen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).