From 54d816d3d36293728ffc8488fae14b002d4b4a64 Mon Sep 17 00:00:00 2001 From: "Ewan D. Milne" Date: Fri, 29 Oct 2021 15:43:11 -0400 Subject: scsi: core: Simplify control flow in scmd_eh_abort_handler() Simplify the nested conditionals in the function by using a label for the error path. Introduce local "shost" to avoid repeated "sdev->shost" usage. Also remove scsi_eh_complete_abort() since there is now only one place it would be called. Link: https://lore.kernel.org/r/20211029194311.17504-3-emilne@redhat.com Signed-off-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 109 +++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2371edbc3af4..2db518f118bd 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -133,23 +133,6 @@ static bool scsi_eh_should_retry_cmd(struct scsi_cmnd *cmd) return true; } -static void scsi_eh_complete_abort(struct scsi_cmnd *scmd, struct Scsi_Host *shost) -{ - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - list_del_init(&scmd->eh_entry); - /* - * If the abort succeeds, and there is no further - * EH action, clear the ->last_reset time. - */ - if (list_empty(&shost->eh_abort_list) && - list_empty(&shost->eh_cmd_q)) - if (shost->eh_deadline != -1) - shost->last_reset = 0; - spin_unlock_irqrestore(shost->host_lock, flags); -} - /** * scmd_eh_abort_handler - Handle command aborts * @work: command to be aborted. @@ -166,54 +149,72 @@ scmd_eh_abort_handler(struct work_struct *work) struct scsi_cmnd *scmd = container_of(work, struct scsi_cmnd, abort_work.work); struct scsi_device *sdev = scmd->device; + struct Scsi_Host *shost = sdev->host; enum scsi_disposition rtn; unsigned long flags; - if (scsi_host_eh_past_deadline(sdev->host)) { + if (scsi_host_eh_past_deadline(shost)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, "eh timeout, not aborting\n")); - } else { - SCSI_LOG_ERROR_RECOVERY(3, + goto out; + } + + SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, "aborting command\n")); - rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd); - if (rtn == SUCCESS) { - set_host_byte(scmd, DID_TIME_OUT); - if (scsi_host_eh_past_deadline(sdev->host)) { - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "eh timeout, not retrying " - "aborted command\n")); - } else if (!scsi_noretry_cmd(scmd) && - scsi_cmd_retry_allowed(scmd) && - scsi_eh_should_retry_cmd(scmd)) { - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_WARNING, scmd, - "retry aborted command\n")); - scsi_eh_complete_abort(scmd, sdev->host); - scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); - return; - } else { - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_WARNING, scmd, - "finish aborted command\n")); - scsi_eh_complete_abort(scmd, sdev->host); - scsi_finish_command(scmd); - return; - } - } else { - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "cmd abort %s\n", - (rtn == FAST_IO_FAIL) ? - "not send" : "failed")); - } + rtn = scsi_try_to_abort_cmd(shost->hostt, scmd); + if (rtn != SUCCESS) { + SCSI_LOG_ERROR_RECOVERY(3, + scmd_printk(KERN_INFO, scmd, + "cmd abort %s\n", + (rtn == FAST_IO_FAIL) ? + "not send" : "failed")); + goto out; + } + set_host_byte(scmd, DID_TIME_OUT); + if (scsi_host_eh_past_deadline(shost)) { + SCSI_LOG_ERROR_RECOVERY(3, + scmd_printk(KERN_INFO, scmd, + "eh timeout, not retrying " + "aborted command\n")); + goto out; } - spin_lock_irqsave(sdev->host->host_lock, flags); + spin_lock_irqsave(shost->host_lock, flags); list_del_init(&scmd->eh_entry); - spin_unlock_irqrestore(sdev->host->host_lock, flags); + + /* + * If the abort succeeds, and there is no further + * EH action, clear the ->last_reset time. + */ + if (list_empty(&shost->eh_abort_list) && + list_empty(&shost->eh_cmd_q)) + if (shost->eh_deadline != -1) + shost->last_reset = 0; + + spin_unlock_irqrestore(shost->host_lock, flags); + + if (!scsi_noretry_cmd(scmd) && + scsi_cmd_retry_allowed(scmd) && + scsi_eh_should_retry_cmd(scmd)) { + SCSI_LOG_ERROR_RECOVERY(3, + scmd_printk(KERN_WARNING, scmd, + "retry aborted command\n")); + scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); + } else { + SCSI_LOG_ERROR_RECOVERY(3, + scmd_printk(KERN_WARNING, scmd, + "finish aborted command\n")); + scsi_finish_command(scmd); + } + return; + +out: + spin_lock_irqsave(shost->host_lock, flags); + list_del_init(&scmd->eh_entry); + spin_unlock_irqrestore(shost->host_lock, flags); + scsi_eh_scmd_add(scmd); } -- cgit v1.2.3 From 0a84486d6c1da1c2738544d8fc1b07b1d3ce046f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 16 Nov 2021 14:31:15 -0800 Subject: scsi: core: Remove Scsi_Host.shost_dev_attr_groups Simplify the scsi_host_alloc() implementation by setting the shost_class .dev_groups member instead of copying all host attribute group pointers into the shost_dev_attr_groups[] array. Link: https://lore.kernel.org/r/20211116223115.2103031-1-bvanassche@acm.org Cc: Steffen Maier Cc: Damien Le Moal Suggested-by: Benjamin Block Reviewed-by: Damien Le Moal Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 15 +++------------ drivers/scsi/scsi_priv.h | 2 +- drivers/scsi/scsi_sysfs.c | 7 ++++++- include/scsi/scsi_host.h | 6 ------ 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8049b00b6766..f69b77cbf538 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -61,6 +61,7 @@ static void scsi_host_cls_release(struct device *dev) static struct class shost_class = { .name = "scsi_host", .dev_release = scsi_host_cls_release, + .dev_groups = scsi_shost_groups, }; /** @@ -377,7 +378,7 @@ static struct device_type scsi_host_type = { struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { struct Scsi_Host *shost; - int index, i, j = 0; + int index; shost = kzalloc(sizeof(struct Scsi_Host) + privsize, GFP_KERNEL); if (!shost) @@ -483,17 +484,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->shost_dev.parent = &shost->shost_gendev; shost->shost_dev.class = &shost_class; dev_set_name(&shost->shost_dev, "host%d", shost->host_no); - shost->shost_dev.groups = shost->shost_dev_attr_groups; - shost->shost_dev_attr_groups[j++] = &scsi_shost_attr_group; - if (sht->shost_groups) { - for (i = 0; sht->shost_groups[i] && - j < ARRAY_SIZE(shost->shost_dev_attr_groups); - i++, j++) { - shost->shost_dev_attr_groups[j] = - sht->shost_groups[i]; - } - } - WARN_ON_ONCE(j >= ARRAY_SIZE(shost->shost_dev_attr_groups)); + shost->shost_dev.groups = sht->shost_groups; shost->ehandler = kthread_run(scsi_error_handler, shost, "scsi_eh_%d", shost->host_no); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index a278fc8948f4..0f5743f4769b 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -144,7 +144,7 @@ extern struct scsi_transport_template blank_transport_template; extern void __scsi_remove_device(struct scsi_device *); extern struct bus_type scsi_bus_type; -extern const struct attribute_group scsi_shost_attr_group; +extern const struct attribute_group *scsi_shost_groups[]; /* scsi_netlink.c */ #ifdef CONFIG_SCSI_NETLINK diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 55addd78fde4..61839773cc72 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -424,10 +424,15 @@ static struct attribute *scsi_sysfs_shost_attrs[] = { NULL }; -const struct attribute_group scsi_shost_attr_group = { +static const struct attribute_group scsi_shost_attr_group = { .attrs = scsi_sysfs_shost_attrs, }; +const struct attribute_group *scsi_shost_groups[] = { + &scsi_shost_attr_group, + NULL +}; + static void scsi_device_cls_release(struct device *class_dev) { struct scsi_device *sdev; diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index ebe059badba0..72e1a347baa6 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -691,12 +691,6 @@ struct Scsi_Host { /* ldm bits */ struct device shost_gendev, shost_dev; - /* - * The array size 3 provides space for one attribute group defined by - * the SCSI core, one attribute group defined by the SCSI LLD and one - * terminating NULL pointer. - */ - const struct attribute_group *shost_dev_attr_groups[3]; /* * Points to the transport data (if any) which is allocated -- cgit v1.2.3 From adcc796b4f55c18ee5fca8190a592c84cf8682e0 Mon Sep 17 00:00:00 2001 From: Chunguang Xu Date: Wed, 10 Nov 2021 09:23:32 +0800 Subject: scsi: core: Use eh_timeout for START STOP UNIT In some scenarios START STOP UNIT may time out. The default recovery time of 30 seconds is relatively large. Modifying rq_timeout to adjust the START STOP UNIT timeout value will affect the regular I/O. Commit 9728c0814ecb ("[SCSI] make scsi_eh_try_stu use block timeout") switched to rq_timeout for the START STOP UNIT command. However commit 0816c9251a71 ("[SCSI] Allow error handling timeout to be specified") introduced an explicit eh_timeout parameter. It makes more sense to use this value as the timeout for START STOP UNIT. Link: https://lore.kernel.org/r/1636507412-21678-1-git-send-email-brookxu.cn@gmail.com Reviewed-by: Christoph Hellwig Reviewed-by: Wu Bo Signed-off-by: Chunguang Xu Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_error.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2db518f118bd..9cb0f9df621a 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1430,7 +1430,8 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) enum scsi_disposition rtn = NEEDS_RETRY; for (i = 0; rtn == NEEDS_RETRY && i < 2; i++) - rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, scmd->device->request_queue->rq_timeout, 0); + rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, + scmd->device->eh_timeout, 0); if (rtn == SUCCESS) return 0; -- cgit v1.2.3 From 744798fcd2b31b806ebf09f86989cbf2806fa9ea Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Mon, 1 Nov 2021 16:28:22 -0700 Subject: scsi: pm80xx: Apply byte mask for phy ID in mpi_phy_start_resp() Phy ID is located in the least significant byte of the 4-byte field. mpi_phy_stop_resp() already applies such mask. Link: https://lore.kernel.org/r/20211101232825.2350233-2-ipylypiv@google.com Reviewed-by: Vishakha Channapattan Acked-by: Jack Wang Signed-off-by: Igor Pylypiv Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm80xx_hwi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index b9f6d83ff380..88541ca2a629 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -3519,7 +3519,7 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) u32 status = le32_to_cpu(pPayload->status); u32 phy_id = - le32_to_cpu(pPayload->phyid); + le32_to_cpu(pPayload->phyid) & 0xFF; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; pm8001_dbg(pm8001_ha, INIT, -- cgit v1.2.3 From 60de1a67d66db11319a82bd95f11c2b12b75dee0 Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Mon, 1 Nov 2021 16:28:23 -0700 Subject: scsi: pm80xx: Do not check the address-of value for NULL Address-of operator cannot return NULL. Link: https://lore.kernel.org/r/20211101232825.2350233-3-ipylypiv@google.com Reviewed-by: Vishakha Channapattan Acked-by: Jack Wang Signed-off-by: Igor Pylypiv Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 24 ++++-------------------- drivers/scsi/pm8001/pm80xx_hwi.c | 29 ++++++++--------------------- 2 files changed, 12 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 124cb69740c6..9f95369bfe7b 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -2304,21 +2304,17 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) psataPayload = (struct sata_completion_resp *)(piomb + 4); status = le32_to_cpu(psataPayload->status); + param = le32_to_cpu(psataPayload->param); tag = le32_to_cpu(psataPayload->tag); if (!tag) { pm8001_dbg(pm8001_ha, FAIL, "tag null\n"); return; } + ccb = &pm8001_ha->ccb_info[tag]; - param = le32_to_cpu(psataPayload->param); - if (ccb) { - t = ccb->task; - pm8001_dev = ccb->device; - } else { - pm8001_dbg(pm8001_ha, FAIL, "ccb null\n"); - return; - } + t = ccb->task; + pm8001_dev = ccb->device; if (t) { if (t->dev && (t->dev->lldd_dev)) @@ -2335,10 +2331,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) } ts = &t->task_status; - if (!ts) { - pm8001_dbg(pm8001_ha, FAIL, "ts null\n"); - return; - } if (status) pm8001_dbg(pm8001_ha, IOERR, @@ -2695,14 +2687,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb) u32 dev_id = le32_to_cpu(psataPayload->device_id); unsigned long flags; - ccb = &pm8001_ha->ccb_info[tag]; - - if (ccb) { - t = ccb->task; - pm8001_dev = ccb->device; - } else { - pm8001_dbg(pm8001_ha, FAIL, "No CCB !!!. returning\n"); - } if (event) pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 88541ca2a629..b81e8e7160ff 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -2400,21 +2400,17 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, psataPayload = (struct sata_completion_resp *)(piomb + 4); status = le32_to_cpu(psataPayload->status); + param = le32_to_cpu(psataPayload->param); tag = le32_to_cpu(psataPayload->tag); if (!tag) { pm8001_dbg(pm8001_ha, FAIL, "tag null\n"); return; } + ccb = &pm8001_ha->ccb_info[tag]; - param = le32_to_cpu(psataPayload->param); - if (ccb) { - t = ccb->task; - pm8001_dev = ccb->device; - } else { - pm8001_dbg(pm8001_ha, FAIL, "ccb null\n"); - return; - } + t = ccb->task; + pm8001_dev = ccb->device; if (t) { if (t->dev && (t->dev->lldd_dev)) @@ -2431,10 +2427,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, } ts = &t->task_status; - if (!ts) { - pm8001_dbg(pm8001_ha, FAIL, "ts null\n"); - return; - } if (status != IO_SUCCESS) { pm8001_dbg(pm8001_ha, FAIL, @@ -2830,15 +2822,6 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, u32 dev_id = le32_to_cpu(psataPayload->device_id); unsigned long flags; - ccb = &pm8001_ha->ccb_info[tag]; - - if (ccb) { - t = ccb->task; - pm8001_dev = ccb->device; - } else { - pm8001_dbg(pm8001_ha, FAIL, "No CCB !!!. returning\n"); - return; - } if (event) pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event); @@ -2852,6 +2835,10 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, return; } + ccb = &pm8001_ha->ccb_info[tag]; + t = ccb->task; + pm8001_dev = ccb->device; + if (unlikely(!t || !t->lldd_task || !t->dev)) { pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); return; -- cgit v1.2.3 From 606c54ae975ad3af540b505b46b55a687501711f Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Mon, 1 Nov 2021 16:28:24 -0700 Subject: scsi: pm80xx: Update WARN_ON check in pm8001_mpi_build_cmd() Starting from commit 05c6c029a44d ("scsi: pm80xx: Increase number of supported queues") driver initializes only max_q_num queues. Do not use an invalid queue if the WARN_ON condition is true. Link: https://lore.kernel.org/r/20211101232825.2350233-4-ipylypiv@google.com Fixes: 7640e1eb8c5d ("scsi: pm80xx: Make mpi_build_cmd locking consistent") Reviewed-by: Vishakha Channapattan Acked-by: Jack Wang Signed-off-by: Igor Pylypiv Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 9f95369bfe7b..f8e29d588f95 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1325,7 +1325,9 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, int q_index = circularQ - pm8001_ha->inbnd_q_tbl; int rv; - WARN_ON(q_index >= PM8001_MAX_INB_NUM); + if (WARN_ON(q_index >= pm8001_ha->max_q_num)) + return -EINVAL; + spin_lock_irqsave(&circularQ->iq_lock, flags); rv = pm8001_mpi_msg_free_get(circularQ, pm8001_ha->iomb_size, &pMessage); -- cgit v1.2.3 From 853615582d6f99c0a4b4424a63b4f01aa8fcebef Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Mon, 1 Nov 2021 16:28:25 -0700 Subject: scsi: pm80xx: Use bitmap_zalloc() for tags bitmap allocation We used to allocate X bytes while we only need X bits. Link: https://lore.kernel.org/r/20211101232825.2350233-5-ipylypiv@google.com Reviewed-by: Vishakha Channapattan Acked-by: Jack Wang Signed-off-by: Igor Pylypiv Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index bed8cc125544..7ffd39214263 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -179,7 +179,7 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) } PM8001_CHIP_DISP->chip_iounmap(pm8001_ha); flush_workqueue(pm8001_wq); - kfree(pm8001_ha->tags); + bitmap_free(pm8001_ha->tags); kfree(pm8001_ha); } @@ -1194,7 +1194,7 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost, can_queue = ccb_count - PM8001_RESERVE_SLOT; shost->can_queue = can_queue; - pm8001_ha->tags = kzalloc(ccb_count, GFP_KERNEL); + pm8001_ha->tags = bitmap_zalloc(ccb_count, GFP_KERNEL); if (!pm8001_ha->tags) goto err_out; -- cgit v1.2.3 From 8ceddda38d4272683fe0c5d8f310109affae0b63 Mon Sep 17 00:00:00 2001 From: Changyuan Lyu Date: Mon, 15 Nov 2021 13:57:49 -0800 Subject: scsi: pm80xx: Add tracepoints Tracepoints for tracking controller and ATA commands issued and completed. Link: https://lore.kernel.org/r/20211115215750.131696-2-changyuanl@google.com Acked-by: Jack Wang Co-developed-by: Akshat Jain Signed-off-by: Akshat Jain Signed-off-by: Changyuan Lyu Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/Makefile | 7 ++- drivers/scsi/pm8001/pm8001_sas.c | 16 ++++++ drivers/scsi/pm8001/pm80xx_hwi.c | 7 +++ drivers/scsi/pm8001/pm80xx_tracepoints.c | 10 ++++ drivers/scsi/pm8001/pm80xx_tracepoints.h | 85 ++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 drivers/scsi/pm8001/pm80xx_tracepoints.c create mode 100644 drivers/scsi/pm8001/pm80xx_tracepoints.h diff --git a/drivers/scsi/pm8001/Makefile b/drivers/scsi/pm8001/Makefile index 02b7338999cc..bbb51b7312f1 100644 --- a/drivers/scsi/pm8001/Makefile +++ b/drivers/scsi/pm8001/Makefile @@ -6,9 +6,12 @@ obj-$(CONFIG_SCSI_PM8001) += pm80xx.o + +CFLAGS_pm80xx_tracepoints.o := -I$(src) + pm80xx-y += pm8001_init.o \ pm8001_sas.o \ pm8001_ctl.o \ pm8001_hwi.o \ - pm80xx_hwi.o - + pm80xx_hwi.o \ + pm80xx_tracepoints.o diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 83e73009db5c..c9a16eef38c1 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -40,6 +40,7 @@ #include #include "pm8001_sas.h" +#include "pm80xx_tracepoints.h" /** * pm8001_find_tag - from sas task to find out tag that belongs to this task @@ -527,6 +528,9 @@ int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags) void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha, struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx) { + struct ata_queued_cmd *qc; + struct pm8001_device *pm8001_dev; + if (!ccb->task) return; if (!sas_protocol_ata(task->task_proto)) @@ -549,6 +553,18 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha, /* do nothing */ break; } + + if (sas_protocol_ata(task->task_proto)) { + // For SCSI/ATA commands uldd_task points to ata_queued_cmd + qc = task->uldd_task; + pm8001_dev = ccb->device; + trace_pm80xx_request_complete(pm8001_ha->id, + pm8001_dev ? pm8001_dev->attached_phy : PM8001_MAX_PHYS, + ccb_idx, 0 /* ctlr_opcode not known */, + qc ? qc->tf.command : 0, // ata opcode + pm8001_dev ? atomic_read(&pm8001_dev->running_req) : -1); + } + task->lldd_task = NULL; ccb->task = NULL; ccb->ccb_tag = 0xFFFFFFFF; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index b81e8e7160ff..0849ecc913c7 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -42,6 +42,7 @@ #include "pm80xx_hwi.h" #include "pm8001_chips.h" #include "pm8001_ctl.h" +#include "pm80xx_tracepoints.h" #define SMP_DIRECT 1 #define SMP_INDIRECT 2 @@ -4530,6 +4531,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, struct sas_task *task = ccb->task; struct domain_device *dev = task->dev; struct pm8001_device *pm8001_ha_dev = dev->lldd_dev; + struct ata_queued_cmd *qc = task->uldd_task; u32 tag = ccb->ccb_tag; int ret; u32 q_index, cpu_id; @@ -4749,6 +4751,11 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, } } } + trace_pm80xx_request_issue(pm8001_ha->id, + ccb->device ? ccb->device->attached_phy : PM8001_MAX_PHYS, + ccb->ccb_tag, opc, + qc ? qc->tf.command : 0, // ata opcode + ccb->device ? atomic_read(&ccb->device->running_req) : 0); ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, sizeof(sata_cmd), q_index); return ret; diff --git a/drivers/scsi/pm8001/pm80xx_tracepoints.c b/drivers/scsi/pm8001/pm80xx_tracepoints.c new file mode 100644 index 000000000000..344aface9cdb --- /dev/null +++ b/drivers/scsi/pm8001/pm80xx_tracepoints.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Trace events in pm8001 driver. + * + * Copyright 2020 Google LLC + * Author: Akshat Jain + */ + +#define CREATE_TRACE_POINTS +#include "pm80xx_tracepoints.h" diff --git a/drivers/scsi/pm8001/pm80xx_tracepoints.h b/drivers/scsi/pm8001/pm80xx_tracepoints.h new file mode 100644 index 000000000000..84fcfecfd624 --- /dev/null +++ b/drivers/scsi/pm8001/pm80xx_tracepoints.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Trace events in pm8001 driver. + * + * Copyright 2020 Google LLC + * Author: Akshat Jain + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM pm80xx + +#if !defined(_TRACE_PM80XX_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_PM80XX_H + +#include +#include "pm8001_sas.h" + +TRACE_EVENT(pm80xx_request_issue, + TP_PROTO(u32 id, u32 phy_id, u32 htag, u32 ctlr_opcode, + u16 ata_opcode, int running_req), + + TP_ARGS(id, phy_id, htag, ctlr_opcode, ata_opcode, running_req), + + TP_STRUCT__entry( + __field(u32, id) + __field(u32, phy_id) + __field(u32, htag) + __field(u32, ctlr_opcode) + __field(u16, ata_opcode) + __field(int, running_req) + ), + + TP_fast_assign( + __entry->id = id; + __entry->phy_id = phy_id; + __entry->htag = htag; + __entry->ctlr_opcode = ctlr_opcode; + __entry->ata_opcode = ata_opcode; + __entry->running_req = running_req; + ), + + TP_printk("ctlr_id = %u phy_id = %u htag = %#x, ctlr_opcode = %#x ata_opcode = %#x running_req = %d", + __entry->id, __entry->phy_id, __entry->htag, + __entry->ctlr_opcode, __entry->ata_opcode, + __entry->running_req) +); + +TRACE_EVENT(pm80xx_request_complete, + TP_PROTO(u32 id, u32 phy_id, u32 htag, u32 ctlr_opcode, + u16 ata_opcode, int running_req), + + TP_ARGS(id, phy_id, htag, ctlr_opcode, ata_opcode, running_req), + + TP_STRUCT__entry( + __field(u32, id) + __field(u32, phy_id) + __field(u32, htag) + __field(u32, ctlr_opcode) + __field(u16, ata_opcode) + __field(int, running_req) + ), + + TP_fast_assign( + __entry->id = id; + __entry->phy_id = phy_id; + __entry->htag = htag; + __entry->ctlr_opcode = ctlr_opcode; + __entry->ata_opcode = ata_opcode; + __entry->running_req = running_req; + ), + + TP_printk("ctlr_id = %u phy_id = %u htag = %#x, ctlr_opcode = %#x ata_opcode = %#x running_req = %d", + __entry->id, __entry->phy_id, __entry->htag, + __entry->ctlr_opcode, __entry->ata_opcode, + __entry->running_req) +); + +#endif /* _TRACE_PM80XX_H_ */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE pm80xx_tracepoints + +#include -- cgit v1.2.3 From 0137b129f215fb5d0209c5c91984b2f44f2d98cc Mon Sep 17 00:00:00 2001 From: Changyuan Lyu Date: Mon, 15 Nov 2021 13:57:50 -0800 Subject: scsi: pm80xx: Add pm80xx_mpi_build_cmd() tracepoint pm8001_mpi_build_cmd() prepares and sends all commands to a controller. Having pm80xx_mpi_build_cmd tracepoint can help us with latency issues. this patch depends on patch "scsi: pm80xx: Add tracepoints". Link: https://lore.kernel.org/r/20211115215750.131696-3-changyuanl@google.com Acked-by: Jack Wang Co-developed-by: Igor Pylypiv Signed-off-by: Igor Pylypiv Signed-off-by: Changyuan Lyu Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 5 +++++ drivers/scsi/pm8001/pm80xx_tracepoints.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index f8e29d588f95..c814e5071712 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -42,6 +42,7 @@ #include "pm8001_hwi.h" #include "pm8001_chips.h" #include "pm8001_ctl.h" + #include "pm80xx_tracepoints.h" /** * read_main_config_table - read the configure table and save it. @@ -1324,6 +1325,10 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, unsigned long flags; int q_index = circularQ - pm8001_ha->inbnd_q_tbl; int rv; + u32 htag = le32_to_cpu(*(__le32 *)payload); + + trace_pm80xx_mpi_build_cmd(pm8001_ha->id, opCode, htag, q_index, + circularQ->producer_idx, le32_to_cpu(circularQ->consumer_index)); if (WARN_ON(q_index >= pm8001_ha->max_q_num)) return -EINVAL; diff --git a/drivers/scsi/pm8001/pm80xx_tracepoints.h b/drivers/scsi/pm8001/pm80xx_tracepoints.h index 84fcfecfd624..5e669a8a9344 100644 --- a/drivers/scsi/pm8001/pm80xx_tracepoints.h +++ b/drivers/scsi/pm8001/pm80xx_tracepoints.h @@ -75,6 +75,34 @@ TRACE_EVENT(pm80xx_request_complete, __entry->running_req) ); +TRACE_EVENT(pm80xx_mpi_build_cmd, + TP_PROTO(u32 id, u32 opc, u32 htag, u32 qi, u32 pi, u32 ci), + + TP_ARGS(id, opc, htag, qi, pi, ci), + + TP_STRUCT__entry( + __field(u32, id) + __field(u32, opc) + __field(u32, htag) + __field(u32, qi) + __field(u32, pi) + __field(u32, ci) + ), + + TP_fast_assign( + __entry->id = id; + __entry->opc = opc; + __entry->htag = htag; + __entry->qi = qi; + __entry->pi = pi; + __entry->ci = ci; + ), + + TP_printk("ctlr_id = %u opc = %#x htag = %#x QI = %u PI = %u CI = %u", + __entry->id, __entry->opc, __entry->htag, __entry->qi, + __entry->pi, __entry->ci) +); + #endif /* _TRACE_PM80XX_H_ */ #undef TRACE_INCLUDE_PATH -- cgit v1.2.3 From d28a78537d1d79f1ba6b9e68f5d44cc869045afe Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 6 Nov 2021 17:46:50 +0100 Subject: scsi: ufs: Wrap Universal Flash Storage drivers in SCSI_UFSHCD The build only descends into drivers/scsi/ufs/ if SCSI_UFSHCD is enabled. Hence all later config symbols should depend on SCSI_UFSHCD to prevent asking the user about config symbols for driver code that won't be built anyway. Unfortunately not all symbols have that dependency. Fix this by wrapping them all into a big if/endif block. Remove the now superfluous explicit dependencies on SCSI_UFSHCD from all symbols that already had it. Link: https://lore.kernel.org/r/20211106164650.1571068-1-geert@linux-m68k.org Signed-off-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index b2521b830be7..a43f4d947f1b 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -50,9 +50,11 @@ config SCSI_UFSHCD However, do not compile this as a module if your root file system (the one containing the directory /) is located on a UFS device. +if SCSI_UFSHCD + config SCSI_UFSHCD_PCI tristate "PCI bus based UFS Controller support" - depends on SCSI_UFSHCD && PCI + depends on PCI help This selects the PCI UFS Host Controller Interface. Select this if you have UFS Host Controller with PCI Interface. @@ -71,7 +73,6 @@ config SCSI_UFS_DWC_TC_PCI config SCSI_UFSHCD_PLATFORM tristate "Platform bus based UFS Controller support" - depends on SCSI_UFSHCD depends on HAS_IOMEM help This selects the UFS host controller support. Select this if @@ -147,7 +148,6 @@ config SCSI_UFS_TI_J721E config SCSI_UFS_BSG bool "Universal Flash Storage BSG device node" - depends on SCSI_UFSHCD select BLK_DEV_BSGLIB help Universal Flash Storage (UFS) is SCSI transport specification for @@ -177,7 +177,7 @@ config SCSI_UFS_EXYNOS config SCSI_UFS_CRYPTO bool "UFS Crypto Engine Support" - depends on SCSI_UFSHCD && BLK_INLINE_ENCRYPTION + depends on BLK_INLINE_ENCRYPTION help Enable Crypto Engine Support in UFS. Enabling this makes it possible for the kernel to use the crypto @@ -186,7 +186,6 @@ config SCSI_UFS_CRYPTO config SCSI_UFS_HPB bool "Support UFS Host Performance Booster" - depends on SCSI_UFSHCD help The UFS HPB feature improves random read performance. It caches L2P (logical to physical) map of UFS to host DRAM. The driver uses HPB @@ -195,7 +194,7 @@ config SCSI_UFS_HPB config SCSI_UFS_FAULT_INJECTION bool "UFS Fault Injection Support" - depends on SCSI_UFSHCD && FAULT_INJECTION + depends on FAULT_INJECTION help Enable fault injection support in the UFS driver. This makes it easier to test the UFS error handler and abort handler. @@ -208,3 +207,5 @@ config SCSI_UFS_HWMON a hardware monitoring device will be created for the UFS device. If unsure, say N. + +endif -- cgit v1.2.3 From 659109a45c6c5a3c81a8ce35dea59318c44cfa6e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 6 Nov 2021 17:47:41 +0100 Subject: scsi: ufs: Fix double space in SCSI_UFS_HWMON description There's no reason to have a double space between "UFS" and "Temperature", hence drop it. Link: https://lore.kernel.org/r/20211106164741.1571206-1-geert@linux-m68k.org Fixes: e88e2d32200a ("scsi: ufs: core: Probe for temperature notification support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index a43f4d947f1b..9fe27b01904e 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -200,7 +200,7 @@ config SCSI_UFS_FAULT_INJECTION to test the UFS error handler and abort handler. config SCSI_UFS_HWMON - bool "UFS Temperature Notification" + bool "UFS Temperature Notification" depends on SCSI_UFSHCD=HWMON || HWMON=y help This provides support for UFS hardware monitoring. If enabled, -- cgit v1.2.3 From ddba1cf7a506b09b3583bcac2d64ec88bd4e3a96 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 27 Oct 2021 16:06:14 +0300 Subject: scsi: ufs: Let devices remain runtime suspended during system suspend If the UFS Device WLUN is runtime suspended and is in the same power mode, link state, and b_rpm_dev_flush_capable (BKOP or WB buffer flush etc) state, then it can remain runtime suspended instead of being runtime resumed and then system suspended. The following patch has cleared the way for that to happen: scsi: core: pm: Only runtime resume if necessary So amend the logic accordingly. Note, the ufs-hisi driver uses different RPM and SPM, but it is made explicit by a new parameter to suspend prepare. Link: https://lore.kernel.org/r/20211027130614.406985-2-adrian.hunter@intel.com Reviewed-by: Asutosh Das Reviewed-by: Bean Huo Signed-off-by: Adrian Hunter Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-hisi.c | 8 +++++++- drivers/scsi/ufs/ufshcd.c | 45 ++++++++++++++++++++++++++++++++++++++++----- drivers/scsi/ufs/ufshcd.h | 11 +++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index 8c7e8d321746..ab1a7ebd89b1 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -396,6 +396,12 @@ out: return ret; } +static int ufs_hisi_suspend_prepare(struct device *dev) +{ + /* RPM and SPM are different. Refer ufs_hisi_suspend() */ + return __ufshcd_suspend_prepare(dev, false); +} + static int ufs_hisi_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, enum ufs_notify_change_status status) { @@ -578,7 +584,7 @@ static int ufs_hisi_remove(struct platform_device *pdev) static const struct dev_pm_ops ufs_hisi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume) SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL) - .prepare = ufshcd_suspend_prepare, + .prepare = ufs_hisi_suspend_prepare, .complete = ufshcd_resume_complete, }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index afd38142b1c0..024f6d958341 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -9708,7 +9708,27 @@ void ufshcd_resume_complete(struct device *dev) } EXPORT_SYMBOL_GPL(ufshcd_resume_complete); -int ufshcd_suspend_prepare(struct device *dev) +static bool ufshcd_rpm_ok_for_spm(struct ufs_hba *hba) +{ + struct device *dev = &hba->sdev_ufs_device->sdev_gendev; + enum ufs_dev_pwr_mode dev_pwr_mode; + enum uic_link_state link_state; + unsigned long flags; + bool res; + + spin_lock_irqsave(&dev->power.lock, flags); + dev_pwr_mode = ufs_get_pm_lvl_to_dev_pwr_mode(hba->spm_lvl); + link_state = ufs_get_pm_lvl_to_link_pwr_state(hba->spm_lvl); + res = pm_runtime_suspended(dev) && + hba->curr_dev_pwr_mode == dev_pwr_mode && + hba->uic_link_state == link_state && + !hba->dev_info.b_rpm_dev_flush_capable; + spin_unlock_irqrestore(&dev->power.lock, flags); + + return res; +} + +int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm) { struct ufs_hba *hba = dev_get_drvdata(dev); int ret; @@ -9720,15 +9740,30 @@ int ufshcd_suspend_prepare(struct device *dev) * Refer ufshcd_resume_complete() */ if (hba->sdev_ufs_device) { - ret = ufshcd_rpm_get_sync(hba); - if (ret < 0 && ret != -EACCES) { - ufshcd_rpm_put(hba); - return ret; + /* Prevent runtime suspend */ + ufshcd_rpm_get_noresume(hba); + /* + * Check if already runtime suspended in same state as system + * suspend would be. + */ + if (!rpm_ok_for_spm || !ufshcd_rpm_ok_for_spm(hba)) { + /* RPM state is not ok for SPM, so runtime resume */ + ret = ufshcd_rpm_resume(hba); + if (ret < 0 && ret != -EACCES) { + ufshcd_rpm_put(hba); + return ret; + } } hba->complete_put = true; } return 0; } +EXPORT_SYMBOL_GPL(__ufshcd_suspend_prepare); + +int ufshcd_suspend_prepare(struct device *dev) +{ + return __ufshcd_suspend_prepare(dev, true); +} EXPORT_SYMBOL_GPL(ufshcd_suspend_prepare); #ifdef CONFIG_PM_SLEEP diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 54750d72c8fb..6103e98e9a08 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -1211,6 +1211,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable); int ufshcd_suspend_prepare(struct device *dev); +int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm); void ufshcd_resume_complete(struct device *dev); /* Wrapper functions for safely calling variant operations */ @@ -1420,6 +1421,16 @@ static inline int ufshcd_rpm_put_sync(struct ufs_hba *hba) return pm_runtime_put_sync(&hba->sdev_ufs_device->sdev_gendev); } +static inline void ufshcd_rpm_get_noresume(struct ufs_hba *hba) +{ + pm_runtime_get_noresume(&hba->sdev_ufs_device->sdev_gendev); +} + +static inline int ufshcd_rpm_resume(struct ufs_hba *hba) +{ + return pm_runtime_resume(&hba->sdev_ufs_device->sdev_gendev); +} + static inline int ufshcd_rpm_put(struct ufs_hba *hba) { return pm_runtime_put(&hba->sdev_ufs_device->sdev_gendev); -- cgit v1.2.3 From 6d8619f034f01c841fb3836d4a1bc682571db995 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 26 Nov 2021 12:17:07 -0800 Subject: scsi: qedi: Remove set but unused 'page' variable The variable 'page' is set but never used throughout qedi_alloc_bdq(). Therefore remove it. Link: https://lore.kernel.org/r/20211126201708.27140-2-f.fainelli@gmail.com Reported-by: kernel test robot Acked-by: Manish Rangankar Signed-off-by: Florian Fainelli Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 1dec814d8788..f1c933070884 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1538,7 +1538,6 @@ static int qedi_alloc_bdq(struct qedi_ctx *qedi) int i; struct scsi_bd *pbl; u64 *list; - dma_addr_t page; /* Alloc dma memory for BDQ buffers */ for (i = 0; i < QEDI_BDQ_NUM; i++) { @@ -1608,11 +1607,9 @@ static int qedi_alloc_bdq(struct qedi_ctx *qedi) qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / QEDI_PAGE_SIZE; list = (u64 *)qedi->bdq_pbl_list; - page = qedi->bdq_pbl_list_dma; for (i = 0; i < qedi->bdq_pbl_list_num_entries; i++) { *list = qedi->bdq_pbl_dma; list++; - page += QEDI_PAGE_SIZE; } return 0; -- cgit v1.2.3 From 776141dda77f153379a2eea0887f76cb3e6c8062 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:45:58 -0800 Subject: scsi: core: Suppress a kernel-doc warning Suppress the following kernel-doc warning: drivers/scsi/scsi_scan.c:129: warning: Function parameter or member 'dev' not described in 'scsi_enable_async_suspend' Link: https://lore.kernel.org/r/20211129194609.3466071-2-bvanassche@acm.org Fixes: a19a93e4c6a9 ("scsi: core: pm: Rely on the device driver core for async power management") Reported-by: Stephen Rothwell Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 23e1c0acdeae..2f80509fa036 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -122,7 +122,7 @@ struct async_scan_data { struct completion prev_finished; }; -/** +/* * scsi_enable_async_suspend - Enable async suspend and resume */ void scsi_enable_async_suspend(struct device *dev) -- cgit v1.2.3 From 7cc5aad6c98e0b7e9ab744d1ac7e385e886bb869 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:45:59 -0800 Subject: scsi: core: Declare 'scsi_scan_type' static 'scsi_scan_type' is only used in one source file. Hence declare it static. Link: https://lore.kernel.org/r/20211129194609.3466071-3-bvanassche@acm.org Fixes: a19a93e4c6a9 ("scsi: core: pm: Rely on the device driver core for async power management") Reported-by: kernel test robot Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 2f80509fa036..3520b9384428 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -97,7 +97,7 @@ MODULE_PARM_DESC(max_luns, #define SCSI_SCAN_TYPE_DEFAULT "sync" #endif -char scsi_scan_type[7] = SCSI_SCAN_TYPE_DEFAULT; +static char scsi_scan_type[7] = SCSI_SCAN_TYPE_DEFAULT; module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO|S_IWUSR); -- cgit v1.2.3 From 3369046e54ca8f82e0cb17740643da2d80d3cfa8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:00 -0800 Subject: scsi: core: Show SCMD_LAST in text form The SCSI debugfs code supports showing information about pending commands, including translating SCSI command flags from numeric into text format. Also convert the SCMD_LAST flag from numeric into text form. Link: https://lore.kernel.org/r/20211129194609.3466071-4-bvanassche@acm.org Fixes: 8930a6c20791 ("scsi: core: add support for request batching") Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debugfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_debugfs.c b/drivers/scsi/scsi_debugfs.c index d9109771f274..db8517f1a485 100644 --- a/drivers/scsi/scsi_debugfs.c +++ b/drivers/scsi/scsi_debugfs.c @@ -9,6 +9,7 @@ static const char *const scsi_cmd_flags[] = { SCSI_CMD_FLAG_NAME(TAGGED), SCSI_CMD_FLAG_NAME(INITIALIZED), + SCSI_CMD_FLAG_NAME(LAST), }; #undef SCSI_CMD_FLAG_NAME -- cgit v1.2.3 From 332053e87cda4db58fbeb83fcb7144f88936f3ed Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:01 -0800 Subject: scsi: a100u2w: Fix a kernel-doc warning Fix the following kernel-doc warning: drivers/scsi/a100u2w.c:915: warning: Excess function parameter 'done' description in 'inia100_queue_lck' Link: https://lore.kernel.org/r/20211129194609.3466071-5-bvanassche@acm.org Fixes: af049dfd0b10 ("scsi: core: Remove the 'done' argument from SCSI queuecommand_lck functions") Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/a100u2w.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index 564ade03b530..d02eb5b213d0 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -904,13 +904,11 @@ static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struc /** * inia100_queue_lck - queue command with host * @cmd: Command block - * @done: Completion function * * Called by the mid layer to queue a command. Process the command * block, build the host specific scb structures and if there is room * queue the command down to the controller */ - static int inia100_queue_lck(struct scsi_cmnd *cmd) { struct orc_scb *scb; -- cgit v1.2.3 From 471d6840559ae8bd1ed7e222d68f15373f6890f9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:02 -0800 Subject: scsi: atp870u: Fix a kernel-doc warning Fix the following kernel-doc warning: drivers/scsi/atp870u.c:622: warning: Excess function parameter 'done' description in 'atp870u_queuecommand_lck' Link: https://lore.kernel.org/r/20211129194609.3466071-6-bvanassche@acm.org Fixes: af049dfd0b10 ("scsi: core: Remove the 'done' argument from SCSI queuecommand_lck functions") Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/atp870u.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index dcd6fae65a88..7143418d690f 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -614,7 +614,6 @@ static irqreturn_t atp870u_intr_handle(int irq, void *dev_id) /** * atp870u_queuecommand_lck - Queue SCSI command * @req_p: request block - * @done: completion function * * Queue a command to the ATP queue. Called with the host lock held. */ -- cgit v1.2.3 From 69e623791eb3ff3457c71ef734fdc82f6f3cc3c1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:03 -0800 Subject: scsi: bfa: Declare 'bfad_im_vport_attrs' static Fix the following kernel-doc warning: 'bfad_im_vport_attrs' is only used in one source file. Hence declare this array static. Link: https://lore.kernel.org/r/20211129194609.3466071-7-bvanassche@acm.org Fixes: e73af234a1a2 ("scsi: bfa: Switch to attribute groups") Reported-by: kernel test robot Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfad_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index c8b947c16069..f46989bd083c 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -981,7 +981,7 @@ const struct attribute_group *bfad_im_host_groups[] = { NULL }; -struct attribute *bfad_im_vport_attrs[] = { +static struct attribute *bfad_im_vport_attrs[] = { &dev_attr_serial_number.attr, &dev_attr_model.attr, &dev_attr_model_description.attr, -- cgit v1.2.3 From 013d14eafd5c3d07f54ff8ff075df3cb0254e1a9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:04 -0800 Subject: scsi: dc395x: Fix a kernel-doc warning Fix the following kernel-doc warning: drivers/scsi/dc395x.c:964: warning: Excess function parameter 'done' description in 'dc395x_queue_command_lck' Link: https://lore.kernel.org/r/20211129194609.3466071-8-bvanassche@acm.org Fixes: af049dfd0b10 ("scsi: core: Remove the 'done' argument from SCSI queuecommand_lck functions") Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/dc395x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 9b8796c9e634..c11916b8ae00 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -946,7 +946,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, * layer, invoke 'done' on completion * * @cmd: pointer to scsi command object - * @done: function pointer to be invoked on completion * * Returns 1 if the adapter (host) is busy, else returns 0. One * reason for an adapter to be busy is that the number @@ -959,7 +958,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave") * and is expected to be held on return. * - **/ + */ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; -- cgit v1.2.3 From 0addfa5877971a123b489caa3b73c860111e96a8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:05 -0800 Subject: scsi: initio: Fix a kernel-doc warning Fix the following kernel-doc warning: drivers/scsi/initio.c:2613: warning: Excess function parameter 'done' description in 'i91u_queuecommand_lck' Link: https://lore.kernel.org/r/20211129194609.3466071-9-bvanassche@acm.org Fixes: af049dfd0b10 ("scsi: core: Remove the 'done' argument from SCSI queuecommand_lck functions") Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/initio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index fd6da96bc51a..9cdee38f5ba3 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2602,13 +2602,11 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c /** * i91u_queuecommand_lck - Queue a new command if possible * @cmd: SCSI command block from the mid layer - * @done: Completion handler * * Attempts to queue a new command with the host adapter. Will return * zero if successful or indicate a host busy condition if not (which * will cause the mid layer to call us again later with the command) */ - static int i91u_queuecommand_lck(struct scsi_cmnd *cmd) { struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata; -- cgit v1.2.3 From acad9c4324992b6fcfe4f714a3b6f3a8cf8af929 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:06 -0800 Subject: scsi: megaraid: Fix a kernel-doc warning Fix the following kernel-doc warning: drivers/scsi/megaraid/megaraid_mbox.c:1439: warning: Excess function parameter 'done' description in 'megaraid_queue_command_lck' Link: https://lore.kernel.org/r/20211129194609.3466071-10-bvanassche@acm.org Fixes: af049dfd0b10 ("scsi: core: Remove the 'done' argument from SCSI queuecommand_lck functions") Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_mbox.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 14f930d27ca1..2a339d4a7e9d 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -1431,7 +1431,6 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb) /** * megaraid_queue_command_lck - generic queue entry point for all LLDs * @scp : pointer to the scsi command to be executed - * @done : callback routine to be called after the cmd has be completed * * Queue entry point for mailbox based controllers. */ -- cgit v1.2.3 From d6e71a43b11c67cae3f3c595beef020899ec68e9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:07 -0800 Subject: scsi: pm8001: Fix kernel-doc warnings Fix the following kernel-doc warnings: drivers/scsi/pm8001/pm8001_ctl.c:900: warning: cannot understand function prototype: 'const char *const mpiStateText[] = ' drivers/scsi/pm8001/pm8001_ctl.c:930: warning: Function parameter or member 'attr' not described in 'ctl_hmi_error_show' drivers/scsi/pm8001/pm8001_ctl.c:951: warning: Function parameter or member 'attr' not described in 'ctl_raae_count_show' drivers/scsi/pm8001/pm8001_ctl.c:972: warning: Function parameter or member 'attr' not described in 'ctl_iop0_count_show' drivers/scsi/pm8001/pm8001_ctl.c:993: warning: Function parameter or member 'attr' not described in 'ctl_iop1_count_show' Link: https://lore.kernel.org/r/20211129194609.3466071-11-bvanassche@acm.org Fixes: 4ddbea1b6f51 ("scsi: pm80xx: Add sysfs attribute to check MPI state") Acked-by: Jack Wang Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 397eb9f6a1dd..41a63c9b719b 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -889,14 +889,6 @@ static ssize_t pm8001_show_update_fw(struct device *cdev, static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP, pm8001_show_update_fw, pm8001_store_update_fw); -/** - * ctl_mpi_state_show - controller MPI state check - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ - static const char *const mpiStateText[] = { "MPI is not initialized", "MPI is successfully initialized", @@ -904,6 +896,14 @@ static const char *const mpiStateText[] = { "MPI initialization failed with error in [31:16]" }; +/** + * ctl_mpi_state_show - controller MPI state check + * @cdev: pointer to embedded class device + * @attr: device attribute (unused) + * @buf: the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ static ssize_t ctl_mpi_state_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -920,11 +920,11 @@ static DEVICE_ATTR_RO(ctl_mpi_state); /** * ctl_hmi_error_show - controller MPI initialization fails * @cdev: pointer to embedded class device + * @attr: device attribute (unused) * @buf: the buffer returned * * A sysfs 'read-only' shost attribute. */ - static ssize_t ctl_hmi_error_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -941,11 +941,11 @@ static DEVICE_ATTR_RO(ctl_hmi_error); /** * ctl_raae_count_show - controller raae count check * @cdev: pointer to embedded class device + * @attr: device attribute (unused) * @buf: the buffer returned * * A sysfs 'read-only' shost attribute. */ - static ssize_t ctl_raae_count_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -962,11 +962,11 @@ static DEVICE_ATTR_RO(ctl_raae_count); /** * ctl_iop0_count_show - controller iop0 count check * @cdev: pointer to embedded class device + * @attr: device attribute (unused) * @buf: the buffer returned * * A sysfs 'read-only' shost attribute. */ - static ssize_t ctl_iop0_count_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -983,11 +983,11 @@ static DEVICE_ATTR_RO(ctl_iop0_count); /** * ctl_iop1_count_show - controller iop1 count check * @cdev: pointer to embedded class device + * @attr: device attribute (unused) * @buf: the buffer returned * * A sysfs 'read-only' shost attribute. */ - static ssize_t ctl_iop1_count_show(struct device *cdev, struct device_attribute *attr, char *buf) { -- cgit v1.2.3 From b558fa11e4b53027776c451553437aeda4463e4d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:08 -0800 Subject: scsi: pmcraid: Fix a kernel-doc warning Fix the following kernel-doc warning: drivers/scsi/pmcraid.c:3317: warning: Excess function parameter 'done' description in 'pmcraid_queuecommand_lck' Link: https://lore.kernel.org/r/20211129194609.3466071-12-bvanassche@acm.org Fixes: af049dfd0b10 ("scsi: core: Remove the 'done' argument from SCSI queuecommand_lck functions") Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 88046a793767..2fe7a0019fff 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3302,7 +3302,6 @@ static int pmcraid_copy_sglist( /** * pmcraid_queuecommand_lck - Queue a mid-layer request * @scsi_cmd: scsi command struct - * @done: done function * * This function queues a request generated by the mid-layer. Midlayer calls * this routine within host->lock. Some of the functions called by queuecommand -- cgit v1.2.3 From db33028647a3eca9e3e6fccf170d75f3b56a466c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 29 Nov 2021 11:46:09 -0800 Subject: scsi: Remove superfluous #include directives Remove this include directive from code that does not use any functionality from kernel/async.c. Link: https://lore.kernel.org/r/20211129194609.3466071-13-bvanassche@acm.org Reviewed-by: Daejun Park Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 - drivers/scsi/libsas/sas_discover.c | 1 - drivers/scsi/scsi.c | 1 - drivers/scsi/scsi_pm.c | 1 - drivers/scsi/scsi_priv.h | 1 - drivers/scsi/sd.c | 1 - drivers/scsi/ufs/ufshpb.c | 1 - 7 files changed, 7 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 2213a91923a5..ed9419643235 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -8,7 +8,6 @@ #define _HISI_SAS_H_ #include -#include #include #include #include diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 12e1e36d7c04..758213694091 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include "sas_internal.h" diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index f6af1562cba4..dee4d9c6046d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -55,7 +55,6 @@ #include #include #include -#include #include #include diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index b5a858c29488..0e841e8761c5 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -8,7 +8,6 @@ #include #include -#include #include #include diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 0f5743f4769b..5c4786310a31 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -3,7 +3,6 @@ #define _SCSI_PRIV_H #include -#include #include #include diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 65875a598d62..2a50a840a00c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c index 2e31e1413826..9778d4fd03cc 100644 --- a/drivers/scsi/ufs/ufshpb.c +++ b/drivers/scsi/ufs/ufshpb.c @@ -10,7 +10,6 @@ */ #include -#include #include "ufshcd.h" #include "ufshpb.h" -- cgit v1.2.3 From 13202ebf5f331ca83f5ab47eb90ca4ef5489ac80 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 1 Dec 2021 14:28:30 +0000 Subject: scsi: sd_zbc: Simplify zone full condition check According to the ZBC (and ZAC) specification, a zone that has Zone Type set to Conventional, must also have its Zone Condition set to "Not Write Pointer". Therefore, a conventional zone will never have Zone Condition set to "Full", which means that we can omit the non-conventional prerequisite from the zone full condition check. Link: https://lore.kernel.org/r/20211201142821.64650-1-Niklas.Cassel@wdc.com Suggested-by: Damien Le Moal Reviewed-by: Damien Le Moal Reviewed-by: Johannes Thumshirn Signed-off-by: Niklas Cassel Signed-off-by: Martin K. Petersen --- drivers/scsi/sd_zbc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index ed06798983f8..749c5e5a70c7 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -62,8 +62,7 @@ static int sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf, zone.capacity = zone.len; zone.start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16])); zone.wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); - if (zone.type != ZBC_ZONE_TYPE_CONV && - zone.cond == ZBC_ZONE_COND_FULL) + if (zone.cond == ZBC_ZONE_COND_FULL) zone.wp = zone.start + zone.len; ret = cb(&zone, idx, data); -- cgit v1.2.3 From bf3f120fd61c42c2f4aed8995e5417776d788c37 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 1 Dec 2021 14:28:31 +0000 Subject: scsi: sd_zbc: Clean up sd_zbc_parse_report() setting of wp Make sd_zbc_parse_report() use if/else when setting the write pointer, instead of setting it unconditionally and then conditionally updating it. Link: https://lore.kernel.org/r/20211201142821.64650-2-Niklas.Cassel@wdc.com Reviewed-by: Johannes Thumshirn Signed-off-by: Niklas Cassel Signed-off-by: Martin K. Petersen --- drivers/scsi/sd_zbc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 749c5e5a70c7..4735cc7f682c 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -61,9 +61,10 @@ static int sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf, zone.len = logical_to_sectors(sdp, get_unaligned_be64(&buf[8])); zone.capacity = zone.len; zone.start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16])); - zone.wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); if (zone.cond == ZBC_ZONE_COND_FULL) zone.wp = zone.start + zone.len; + else + zone.wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); ret = cb(&zone, idx, data); if (ret) -- cgit v1.2.3 From 54585ec62fbdbb45d9005bba3f988a11621ef42c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 26 Nov 2021 22:15:21 +0100 Subject: scsi: hisi_sas: Use devm_bitmap_zalloc() when applicable 'hisi_hba->slot_index_tags' is a bitmap. Use 'devm_bitmap_zalloc()' to simplify code, improve the semantic, and avoid some open-coded arithmetic in allocator arguments. Link: https://lore.kernel.org/r/4afa3f71e66c941c660627c7f5b0223b51968ebb.1637961191.git.christophe.jaillet@wanadoo.fr Acked-by: John Garry Signed-off-by: Christophe JAILLET Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index f206c433de32..6ecb42d5ce81 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2516,9 +2516,8 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) if (!hisi_hba->breakpoint) goto err_out; - hisi_hba->slot_index_count = max_command_entries; - s = hisi_hba->slot_index_count / BITS_PER_BYTE; - hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL); + s = hisi_hba->slot_index_count = max_command_entries; + hisi_hba->slot_index_tags = devm_bitmap_zalloc(dev, s, GFP_KERNEL); if (!hisi_hba->slot_index_tags) goto err_out; -- cgit v1.2.3 From d43efddf6271a185d13895c5a38c889791e96bff Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 26 Nov 2021 22:18:25 +0100 Subject: scsi: hisi_sas: Remove some useless code in hisi_sas_alloc() The 'hisi_hba->slot_index_tags' bitmap is allocated with bitmap_zalloc() so it is already cleared. There is no need to clear it another time, one bit at a time. Remove the corresponding useless code. Link: https://lore.kernel.org/r/41c86e7e3e05a13bd586d8ee1b81296140b7a6eb.1637961191.git.christophe.jaillet@wanadoo.fr Acked-by: John Garry Signed-off-by: Christophe JAILLET Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 6ecb42d5ce81..d4f5d093bde4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -206,14 +206,6 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, return index; } -static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba) -{ - int i; - - for (i = 0; i < hisi_hba->slot_index_count; ++i) - hisi_sas_slot_index_clear(hisi_hba, i); -} - void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot) { @@ -2535,7 +2527,6 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) if (!hisi_hba->sata_breakpoint) goto err_out; - hisi_sas_slot_index_init(hisi_hba); hisi_hba->last_slot_index = HISI_SAS_UNRESERVED_IPTT; hisi_hba->wq = create_singlethread_workqueue(dev_name(dev)); -- cgit v1.2.3 From 4d6942e2666efb3a415213ed12ba72b7700620f3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 26 Nov 2021 22:18:26 +0100 Subject: scsi: hisi_sas: Use non-atomic bitmap functions when possible All uses of the 'hisi_hba->slot_index_tags' bitmap are protected with the 'hisi_hba->lock' spinlock. Prefer the non-atomic '__[set|clear]_bit()' functions to save a few cycles. Link: https://lore.kernel.org/r/8ee33e463523db080e6a2c06f332e47abb69359b.1637961191.git.christophe.jaillet@wanadoo.fr Acked-by: John Garry Signed-off-by: Christophe JAILLET Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d4f5d093bde4..889c36fa9309 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -158,7 +158,7 @@ static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx) { void *bitmap = hisi_hba->slot_index_tags; - clear_bit(slot_idx, bitmap); + __clear_bit(slot_idx, bitmap); } static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx) @@ -175,7 +175,7 @@ static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx) { void *bitmap = hisi_hba->slot_index_tags; - set_bit(slot_idx, bitmap); + __set_bit(slot_idx, bitmap); } static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, -- cgit v1.2.3 From 9f9b7fa946beaa36681a7011a286da7cbb953816 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 30 Nov 2021 12:38:12 -0800 Subject: scsi: qedi: Fix SYSFS_FLAG_FW_SEL_BOOT formatting The format used for formatting SYSFS_FLAG_FW_SEL_BOOT creates the following warning: drivers/scsi/qedi/qedi_main.c:2259:35: warning: format specifies type 'char' but the argument has type 'int' [-Wformat] rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); Fix this to cast the constant as a char since the intention is to print it via sysfs as a byte. Link: https://lore.kernel.org/r/20211130203813.12138-2-f.fainelli@gmail.com Reported-by: kernel test robot Acked-by: Manish Rangankar Signed-off-by: Florian Fainelli Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index f1c933070884..832a856dd367 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -2086,8 +2086,7 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf) rc = snprintf(buf, ip_len, fmt, gw); break; case ISCSI_BOOT_ETH_FLAGS: - rc = snprintf(buf, 3, "%hhd\n", - SYSFS_FLAG_FW_SEL_BOOT); + rc = snprintf(buf, 3, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT); break; case ISCSI_BOOT_ETH_INDEX: rc = snprintf(buf, 3, "0\n"); @@ -2254,7 +2253,7 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type, mchap_secret); break; case ISCSI_BOOT_TGT_FLAGS: - rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT); + rc = snprintf(buf, 3, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT); break; case ISCSI_BOOT_TGT_NIC_ASSOC: rc = snprintf(buf, 3, "0\n"); -- cgit v1.2.3 From 74d80152538535e7acf3d56863876a18a218261a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 30 Nov 2021 12:38:13 -0800 Subject: scsi: qla4xxx: Format SYSFS_FLAG_FW_SEL_BOOT as byte qedi formats SYSFS_FLAG_FW_SEL_BOOT as a byte and the qla4xxx driver does exactly the same thing. Align them for consistency. Link: https://lore.kernel.org/r/20211130203813.12138-3-f.fainelli@gmail.com Suggested-by: Martin K. Petersen Acked-by: Manish Rangankar Signed-off-by: Florian Fainelli Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 8987acc24dac..0ae936d839f1 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -5734,7 +5734,7 @@ static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) switch (type) { case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); + rc = sprintf(str, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT); break; case ISCSI_BOOT_ETH_INDEX: rc = sprintf(str, "0\n"); @@ -5843,7 +5843,7 @@ qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, (char *)&boot_conn->chap.intr_secret); break; case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); + rc = sprintf(str, "%d\n", (char)SYSFS_FLAG_FW_SEL_BOOT); break; case ISCSI_BOOT_TGT_NIC_ASSOC: rc = sprintf(str, "0\n"); -- cgit v1.2.3 From 4c3e3f8cfc05116d1adf83d95322090f335d2091 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 2 Dec 2021 21:11:41 +0100 Subject: scsi: be2iscsi: Remove maintainers The email addresses of Subbu Seetharaman Jitendra Bhivare are no longer working. Remove Subbu and Jitendra as maintainers. Link: https://lore.kernel.org/r/20211202201141.cytqe73ish6oa356@linutronix.de Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7a2345ce8521..57f7656fe513 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7001,9 +7001,7 @@ S: Maintained F: drivers/mmc/host/cqhci* EMULEX 10Gbps iSCSI - OneConnect DRIVER -M: Subbu Seetharaman M: Ketan Mukadam -M: Jitendra Bhivare L: linux-scsi@vger.kernel.org S: Supported W: http://www.broadcom.com -- cgit v1.2.3 From c27fd25db39b8f16aeda8563d4be6f33e59d07d1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 5 Dec 2021 22:59:01 +0000 Subject: scsi: mptfusion: Remove redundant variable r Variable r is being assigned a value that is never read. The assignment is redundant and so is the variable, so remove these. Remove unnecessary the {} braces in the if statement too. Link: https://lore.kernel.org/r/20211205225901.54362-1-colin.i.king@gmail.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/message/fusion/mptbase.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index b94d5e4fdc23..24a4532053e4 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1274,8 +1274,6 @@ mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) { - int r = 0; - /* return if in use */ if (CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE) @@ -1289,9 +1287,9 @@ mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int slee (access_control_value<<12))); /* Wait for IOC to clear Doorbell Status bit */ - if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { + if (WaitForDoorbellAck(ioc, 5, sleepFlag) < 0) return -2; - }else + else return 0; } -- cgit v1.2.3 From 4bc3bffc1a885eb5cb259e4a25146a4c7b1034e3 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:34 -0800 Subject: scsi: core: Fix scsi_device_max_queue_depth() The comment above scsi_device_max_queue_depth() and also the description of commit ca4453213951 ("scsi: core: Make sure sdev->queue_depth is <= max(shost->can_queue, 1024)") contradict the implementation of the function scsi_device_max_queue_depth(). Additionally, the maximum queue depth of a SCSI LUN never exceeds host->can_queue. Fix scsi_device_max_queue_depth() by changing max_t() into min_t(). Link: https://lore.kernel.org/r/20211203231950.193369-2-bvanassche@acm.org Fixes: ca4453213951 ("scsi: core: Make sure sdev->queue_depth is <= max(shost->can_queue, 1024)") Cc: Hannes Reinecke Cc: Sumanesh Samanta Tested-by: Bean Huo Reviewed-by: Ming Lei Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index dee4d9c6046d..211aace69c22 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -200,11 +200,11 @@ void scsi_finish_command(struct scsi_cmnd *cmd) /* - * 1024 is big enough for saturating the fast scsi LUN now + * 1024 is big enough for saturating fast SCSI LUNs. */ int scsi_device_max_queue_depth(struct scsi_device *sdev) { - return max_t(int, sdev->host->can_queue, 1024); + return min_t(int, sdev->host->can_queue, 1024); } /** -- cgit v1.2.3 From b427609e11ee98b88e745f9fe17aae437b2e2d80 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:35 -0800 Subject: scsi: ufs: Rename a function argument The new name makes it clear what the meaning of the function argument is. Link: https://lore.kernel.org/r/20211203231950.193369-3-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Chanho Park Reviewed-by: Keoseong Park Reviewed-by: Bean Huo Acked-by: Alim Akhtar Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-exynos.c | 4 ++-- drivers/scsi/ufs/ufshcd.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c index cd26bc82462e..474a4a064a68 100644 --- a/drivers/scsi/ufs/ufs-exynos.c +++ b/drivers/scsi/ufs/ufs-exynos.c @@ -853,14 +853,14 @@ static int exynos_ufs_post_pwr_mode(struct ufs_hba *hba, } static void exynos_ufs_specify_nexus_t_xfer_req(struct ufs_hba *hba, - int tag, bool op) + int tag, bool is_scsi_cmd) { struct exynos_ufs *ufs = ufshcd_get_variant(hba); u32 type; type = hci_readl(ufs, HCI_UTRL_NEXUS_TYPE); - if (op) + if (is_scsi_cmd) hci_writel(ufs, type | (1 << tag), HCI_UTRL_NEXUS_TYPE); else hci_writel(ufs, type & ~(1 << tag), HCI_UTRL_NEXUS_TYPE); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 6103e98e9a08..28c1bbe9fa7d 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -338,7 +338,8 @@ struct ufs_hba_variant_ops { enum ufs_notify_change_status status, struct ufs_pa_layer_attr *, struct ufs_pa_layer_attr *); - void (*setup_xfer_req)(struct ufs_hba *, int, bool); + void (*setup_xfer_req)(struct ufs_hba *hba, int tag, + bool is_scsi_cmd); void (*setup_task_mgmt)(struct ufs_hba *, int, u8); void (*hibern8_notify)(struct ufs_hba *, enum uic_cmd_dme, enum ufs_notify_change_status); -- cgit v1.2.3 From d656dc9b0b79e868e46ff78b6ca7a6a70df23566 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:36 -0800 Subject: scsi: ufs: Remove is_rpmb_wlun() Commit edc0596cc04b ("scsi: ufs: core: Stop clearing UNIT ATTENTIONS") removed all callers of is_rpmb_wlun(). Hence also remove the function itself. Link: https://lore.kernel.org/r/20211203231950.193369-4-bvanassche@acm.org Reported-by: kernel test robot Tested-by: Bean Huo Reviewed-by: Asutosh Das Reviewed-by: Alim Akhtar Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 024f6d958341..4821ad9912bb 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2650,11 +2650,6 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id) return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE; } -static inline bool is_rpmb_wlun(struct scsi_device *sdev) -{ - return sdev->lun == ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN); -} - static inline bool is_device_wlun(struct scsi_device *sdev) { return sdev->lun == -- cgit v1.2.3 From 59830c095cf01978d71a25ba1f8660f23f8312c7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:37 -0800 Subject: scsi: ufs: Remove the sdev_rpmb member Since the sdev_rpmb member of struct ufs_hba is only used inside ufshcd_scsi_add_wlus(), convert it into a local variable. Link: https://lore.kernel.org/r/20211203231950.193369-5-bvanassche@acm.org Suggested-by: Jaegeuk Kim Tested-by: Bean Huo Reviewed-by: Asutosh Das Reviewed-by: Alim Akhtar Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 12 ++++++------ drivers/scsi/ufs/ufshcd.h | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 4821ad9912bb..973b7b083dbe 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7412,7 +7412,7 @@ static inline void ufshcd_blk_pm_runtime_init(struct scsi_device *sdev) static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) { int ret = 0; - struct scsi_device *sdev_boot; + struct scsi_device *sdev_boot, *sdev_rpmb; hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL); @@ -7423,14 +7423,14 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) } scsi_device_put(hba->sdev_ufs_device); - hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0, + sdev_rpmb = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL); - if (IS_ERR(hba->sdev_rpmb)) { - ret = PTR_ERR(hba->sdev_rpmb); + if (IS_ERR(sdev_rpmb)) { + ret = PTR_ERR(sdev_rpmb); goto remove_sdev_ufs_device; } - ufshcd_blk_pm_runtime_init(hba->sdev_rpmb); - scsi_device_put(hba->sdev_rpmb); + ufshcd_blk_pm_runtime_init(sdev_rpmb); + scsi_device_put(sdev_rpmb); sdev_boot = __scsi_add_device(hba->host, 0, 0, ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 28c1bbe9fa7d..ecc6c545a19d 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -809,7 +809,6 @@ struct ufs_hba { * "UFS device" W-LU. */ struct scsi_device *sdev_ufs_device; - struct scsi_device *sdev_rpmb; #ifdef CONFIG_SCSI_UFS_HWMON struct device *hwmon_device; -- cgit v1.2.3 From d77ea8226b3be23b0b45aa42851243b62a27bda1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:38 -0800 Subject: scsi: ufs: Remove dead code Commit 7252a3603015 ("scsi: ufs: Avoid busy-waiting by eliminating tag conflicts") guarantees that 'tag' is not in use by any SCSI command. Remove the check that returns early if a conflict occurs. Link: https://lore.kernel.org/r/20211203231950.193369-6-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Bean Huo Acked-by: Avri Altman Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 973b7b083dbe..d4996ada55b6 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6730,11 +6730,6 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, tag = req->tag; WARN_ONCE(tag < 0, "Invalid tag %d\n", tag); - if (unlikely(test_bit(tag, &hba->outstanding_reqs))) { - err = -EBUSY; - goto out; - } - lrbp = &hba->lrb[tag]; WARN_ON(lrbp->cmd); lrbp->cmd = NULL; @@ -6802,8 +6797,8 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, ufshcd_add_query_upiu_trace(hba, err ? UFS_QUERY_ERR : UFS_QUERY_COMP, (struct utp_upiu_req *)lrbp->ucd_rsp_ptr); -out: blk_mq_free_request(req); + out_unlock: up_read(&hba->clk_scaling_lock); return err; -- cgit v1.2.3 From 21ad0e49085deb22c094f91f9da57319a97188e4 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:39 -0800 Subject: scsi: ufs: Fix race conditions related to driver data The driver data pointer must be set before any callbacks are registered that use that pointer. Hence move the initialization of that pointer from after the ufshcd_init() call to inside ufshcd_init(). Link: https://lore.kernel.org/r/20211203231950.193369-7-bvanassche@acm.org Fixes: 3b1d05807a9a ("[SCSI] ufs: Segregate PCI Specific Code") Reported-by: Alexey Dobriyan Tested-by: Bean Huo Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/tc-dwc-g210-pci.c | 1 - drivers/scsi/ufs/ufshcd-pci.c | 2 -- drivers/scsi/ufs/ufshcd-pltfrm.c | 2 -- drivers/scsi/ufs/ufshcd.c | 7 +++++++ 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c index 679289e1a78e..7b08e2e07cc5 100644 --- a/drivers/scsi/ufs/tc-dwc-g210-pci.c +++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c @@ -110,7 +110,6 @@ tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return err; } - pci_set_drvdata(pdev, hba); pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index 51424557810d..a673eedb2f05 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -522,8 +522,6 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return err; } - pci_set_drvdata(pdev, hba); - hba->vops = (struct ufs_hba_variant_ops *)id->driver_data; err = ufshcd_init(hba, mmio_base, pdev->irq); diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index eaeae83b999f..8b16bbbcb806 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -361,8 +361,6 @@ int ufshcd_pltfrm_init(struct platform_device *pdev, goto dealloc_host; } - platform_set_drvdata(pdev, hba); - pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d4996ada55b6..04a19b826837 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -9481,6 +9481,13 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) struct device *dev = hba->dev; char eh_wq_name[sizeof("ufs_eh_wq_00")]; + /* + * dev_set_drvdata() must be called before any callbacks are registered + * that use dev_get_drvdata() (frequency scaling, clock scaling, hwmon, + * sysfs). + */ + dev_set_drvdata(dev, hba); + if (!mmio_base) { dev_err(hba->dev, "Invalid memory reference for mmio_base is NULL\n"); -- cgit v1.2.3 From bd0b35383193d0d31a0cce3d7c7f7e4be1cc7905 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:40 -0800 Subject: scsi: ufs: Remove ufshcd_any_tag_in_use() Use hba->outstanding_reqs instead of ufshcd_any_tag_in_use(). This patch prepares for removal of the blk_mq_start_request() call from ufshcd_wait_for_dev_cmd(). blk_mq_tagset_busy_iter() only iterates over started requests. Link: https://lore.kernel.org/r/20211203231950.193369-8-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 04a19b826837..974bf47e733c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1352,25 +1352,6 @@ out: return ret; } -static bool ufshcd_is_busy(struct request *req, void *priv, bool reserved) -{ - int *busy = priv; - - WARN_ON_ONCE(reserved); - (*busy)++; - return false; -} - -/* Whether or not any tag is in use by a request that is in progress. */ -static bool ufshcd_any_tag_in_use(struct ufs_hba *hba) -{ - struct request_queue *q = hba->cmd_queue; - int busy = 0; - - blk_mq_tagset_busy_iter(q->tag_set, ufshcd_is_busy, &busy); - return busy; -} - static int ufshcd_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) { @@ -1769,7 +1750,7 @@ static void ufshcd_gate_work(struct work_struct *work) if (hba->clk_gating.active_reqs || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL - || ufshcd_any_tag_in_use(hba) || hba->outstanding_tasks + || hba->outstanding_reqs || hba->outstanding_tasks || hba->active_uic_cmd || hba->uic_async_done) goto rel_lock; -- cgit v1.2.3 From fc21da8a840a93fd3512e5d779cbb0996cc1b4f1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:41 -0800 Subject: scsi: ufs: Rework ufshcd_change_queue_depth() Prepare for making sdev->host->can_queue less than hba->nutrs. This patch does not change any functionality. Link: https://lore.kernel.org/r/20211203231950.193369-9-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 974bf47e733c..2d0f59424b00 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4936,11 +4936,7 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev) */ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth) { - struct ufs_hba *hba = shost_priv(sdev->host); - - if (depth > hba->nutrs) - depth = hba->nutrs; - return scsi_change_queue_depth(sdev, depth); + return scsi_change_queue_depth(sdev, min(depth, sdev->host->can_queue)); } static void ufshcd_hpb_destroy(struct ufs_hba *hba, struct scsi_device *sdev) -- cgit v1.2.3 From 945c3cca05d78351bba29fa65d93834cb7934c7b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:42 -0800 Subject: scsi: ufs: Fix a deadlock in the error handler The following deadlock has been observed on a test setup: - All tags allocated - The SCSI error handler calls ufshcd_eh_host_reset_handler() - ufshcd_eh_host_reset_handler() queues work that calls ufshcd_err_handler() - ufshcd_err_handler() locks up as follows: Workqueue: ufs_eh_wq_0 ufshcd_err_handler.cfi_jt Call trace: __switch_to+0x298/0x5d8 __schedule+0x6cc/0xa94 schedule+0x12c/0x298 blk_mq_get_tag+0x210/0x480 __blk_mq_alloc_request+0x1c8/0x284 blk_get_request+0x74/0x134 ufshcd_exec_dev_cmd+0x68/0x640 ufshcd_verify_dev_init+0x68/0x35c ufshcd_probe_hba+0x12c/0x1cb8 ufshcd_host_reset_and_restore+0x88/0x254 ufshcd_reset_and_restore+0xd0/0x354 ufshcd_err_handler+0x408/0xc58 process_one_work+0x24c/0x66c worker_thread+0x3e8/0xa4c kthread+0x150/0x1b4 ret_from_fork+0x10/0x30 Fix this lockup by making ufshcd_exec_dev_cmd() allocate a reserved request. Link: https://lore.kernel.org/r/20211203231950.193369-10-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Adrian Hunter Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 53 +++++++++++++---------------------------------- drivers/scsi/ufs/ufshcd.h | 2 ++ 2 files changed, 16 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2d0f59424b00..da4714aaa850 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -128,8 +128,9 @@ EXPORT_SYMBOL_GPL(ufshcd_dump_regs); enum { UFSHCD_MAX_CHANNEL = 0, UFSHCD_MAX_ID = 1, - UFSHCD_CMD_PER_LUN = 32, - UFSHCD_CAN_QUEUE = 32, + UFSHCD_NUM_RESERVED = 1, + UFSHCD_CMD_PER_LUN = 32 - UFSHCD_NUM_RESERVED, + UFSHCD_CAN_QUEUE = 32 - UFSHCD_NUM_RESERVED, }; static const char *const ufshcd_state_name[] = { @@ -2170,6 +2171,7 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1; hba->nutmrs = ((hba->capabilities & MASK_TASK_MANAGEMENT_REQUEST_SLOTS) >> 16) + 1; + hba->reserved_slot = hba->nutrs - 1; /* Read crypto capabilities */ err = ufshcd_hba_init_crypto_capabilities(hba); @@ -2912,30 +2914,15 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, int timeout) { - struct request_queue *q = hba->cmd_queue; DECLARE_COMPLETION_ONSTACK(wait); - struct request *req; + const u32 tag = hba->reserved_slot; struct ufshcd_lrb *lrbp; int err; - int tag; - down_read(&hba->clk_scaling_lock); + /* Protects use of hba->reserved_slot. */ + lockdep_assert_held(&hba->dev_cmd.lock); - /* - * Get free slot, sleep if slots are unavailable. - * Even though we use wait_event() which sleeps indefinitely, - * the maximum wait time is bounded by SCSI request timeout. - */ - req = blk_mq_alloc_request(q, REQ_OP_DRV_OUT, 0); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto out_unlock; - } - tag = req->tag; - WARN_ONCE(tag < 0, "Invalid tag %d\n", tag); - /* Set the timeout such that the SCSI error handler is not activated. */ - req->timeout = msecs_to_jiffies(2 * timeout); - blk_mq_start_request(req); + down_read(&hba->clk_scaling_lock); lrbp = &hba->lrb[tag]; WARN_ON(lrbp->cmd); @@ -2953,8 +2940,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, (struct utp_upiu_req *)lrbp->ucd_rsp_ptr); out: - blk_mq_free_request(req); -out_unlock: up_read(&hba->clk_scaling_lock); return err; } @@ -6689,23 +6674,16 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, enum query_opcode desc_op) { - struct request_queue *q = hba->cmd_queue; DECLARE_COMPLETION_ONSTACK(wait); - struct request *req; + const u32 tag = hba->reserved_slot; struct ufshcd_lrb *lrbp; int err = 0; - int tag; u8 upiu_flags; - down_read(&hba->clk_scaling_lock); + /* Protects use of hba->reserved_slot. */ + lockdep_assert_held(&hba->dev_cmd.lock); - req = blk_mq_alloc_request(q, REQ_OP_DRV_OUT, 0); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto out_unlock; - } - tag = req->tag; - WARN_ONCE(tag < 0, "Invalid tag %d\n", tag); + down_read(&hba->clk_scaling_lock); lrbp = &hba->lrb[tag]; WARN_ON(lrbp->cmd); @@ -6774,9 +6752,6 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, ufshcd_add_query_upiu_trace(hba, err ? UFS_QUERY_ERR : UFS_QUERY_COMP, (struct utp_upiu_req *)lrbp->ucd_rsp_ptr); - blk_mq_free_request(req); - -out_unlock: up_read(&hba->clk_scaling_lock); return err; } @@ -9507,8 +9482,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Configure LRB */ ufshcd_host_memory_configure(hba); - host->can_queue = hba->nutrs; - host->cmd_per_lun = hba->nutrs; + host->can_queue = hba->nutrs - UFSHCD_NUM_RESERVED; + host->cmd_per_lun = hba->nutrs - UFSHCD_NUM_RESERVED; host->max_id = UFSHCD_MAX_ID; host->max_lun = UFS_MAX_LUNS; host->max_channel = UFSHCD_MAX_CHANNEL; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index ecc6c545a19d..c3c2792f309f 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -745,6 +745,7 @@ struct ufs_hba_monitor { * @capabilities: UFS Controller Capabilities * @nutrs: Transfer Request Queue depth supported by controller * @nutmrs: Task Management Queue depth supported by controller + * @reserved_slot: Used to submit device commands. Protected by @dev_cmd.lock. * @ufs_version: UFS Version to which controller complies * @vops: pointer to variant specific operations * @priv: pointer to variant specific private data @@ -836,6 +837,7 @@ struct ufs_hba { u32 capabilities; int nutrs; int nutmrs; + u32 reserved_slot; u32 ufs_version; const struct ufs_hba_variant_ops *vops; struct ufs_hba_variant_params *vps; -- cgit v1.2.3 From 511a083b8b6bf63f5609a4e4e3db748ab3719451 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:43 -0800 Subject: scsi: ufs: Remove hba->cmd_queue The previous patch removed all code that uses hba->cmd_queue. Hence also remove hba->cmd_queue itself. Link: https://lore.kernel.org/r/20211203231950.193369-11-bvanassche@acm.org Suggested-by: Adrian Hunter Tested-by: Bean Huo Reviewed-by: Adrian Hunter Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 11 +---------- drivers/scsi/ufs/ufshcd.h | 2 -- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index da4714aaa850..2cd777d92c7b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -9331,7 +9331,6 @@ void ufshcd_remove(struct ufs_hba *hba) ufs_sysfs_remove_nodes(hba->dev); blk_cleanup_queue(hba->tmf_queue); blk_mq_free_tag_set(&hba->tmf_tag_set); - blk_cleanup_queue(hba->cmd_queue); scsi_remove_host(hba->host); /* disable interrupts */ ufshcd_disable_intr(hba, hba->intr_mask); @@ -9551,12 +9550,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) goto out_disable; } - hba->cmd_queue = blk_mq_init_queue(&hba->host->tag_set); - if (IS_ERR(hba->cmd_queue)) { - err = PTR_ERR(hba->cmd_queue); - goto out_remove_scsi_host; - } - hba->tmf_tag_set = (struct blk_mq_tag_set) { .nr_hw_queues = 1, .queue_depth = hba->nutmrs, @@ -9565,7 +9558,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) }; err = blk_mq_alloc_tag_set(&hba->tmf_tag_set); if (err < 0) - goto free_cmd_queue; + goto out_remove_scsi_host; hba->tmf_queue = blk_mq_init_queue(&hba->tmf_tag_set); if (IS_ERR(hba->tmf_queue)) { err = PTR_ERR(hba->tmf_queue); @@ -9634,8 +9627,6 @@ free_tmf_queue: blk_cleanup_queue(hba->tmf_queue); free_tmf_tag_set: blk_mq_free_tag_set(&hba->tmf_tag_set); -free_cmd_queue: - blk_cleanup_queue(hba->cmd_queue); out_remove_scsi_host: scsi_remove_host(hba->host); out_disable: diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c3c2792f309f..8e942762e668 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -738,7 +738,6 @@ struct ufs_hba_monitor { * @host: Scsi_Host instance of the driver * @dev: device handle * @lrb: local reference block - * @cmd_queue: Used to allocate command tags from hba->host->tag_set. * @outstanding_tasks: Bits representing outstanding task requests * @outstanding_lock: Protects @outstanding_reqs. * @outstanding_reqs: Bits representing outstanding transfer requests @@ -804,7 +803,6 @@ struct ufs_hba { struct Scsi_Host *host; struct device *dev; - struct request_queue *cmd_queue; /* * This field is to keep a reference to "scsi_device" corresponding to * "UFS device" W-LU. -- cgit v1.2.3 From 3eb9dcc027e2b2bbd8f377d3ef9271b7abfe103d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:44 -0800 Subject: scsi: ufs: Remove the 'update_scaling' local variable This patch does not change any functionality but makes the next patch in this series easier to read. Link: https://lore.kernel.org/r/20211203231950.193369-12-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 2cd777d92c7b..27574aef5374 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5225,7 +5225,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, struct scsi_cmnd *cmd; int result; int index; - bool update_scaling = false; for_each_set_bit(index, &completed_reqs, hba->nutrs) { lrbp = &hba->lrb[index]; @@ -5243,18 +5242,16 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, /* Do not touch lrbp after scsi done */ scsi_done(cmd); ufshcd_release(hba); - update_scaling = true; + ufshcd_clk_scaling_update_busy(hba); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { if (hba->dev_cmd.complete) { ufshcd_add_command_trace(hba, index, UFS_DEV_COMP); complete(hba->dev_cmd.complete); - update_scaling = true; + ufshcd_clk_scaling_update_busy(hba); } } - if (update_scaling) - ufshcd_clk_scaling_update_busy(hba); } } -- cgit v1.2.3 From 6f8dafdee6ae836763e753a9df288d10b35e9679 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:45 -0800 Subject: scsi: ufs: Introduce ufshcd_release_scsi_cmd() The only functional change in this patch is that scsi_done() is now called after ufshcd_release() and ufshcd_clk_scaling_update_busy() instead of before. The next patch in this series will introduce a call to ufshcd_release_scsi_cmd() in the abort handler. Link: https://lore.kernel.org/r/20211203231950.193369-13-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Adrian Hunter Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 27574aef5374..5a641610dd74 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5213,6 +5213,18 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) return retval; } +/* Release the resources allocated for processing a SCSI command. */ +static void ufshcd_release_scsi_cmd(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp) +{ + struct scsi_cmnd *cmd = lrbp->cmd; + + scsi_dma_unmap(cmd); + lrbp->cmd = NULL; /* Mark the command as completed. */ + ufshcd_release(hba); + ufshcd_clk_scaling_update_busy(hba); +} + /** * __ufshcd_transfer_req_compl - handle SCSI and query command completion * @hba: per adapter instance @@ -5223,7 +5235,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, { struct ufshcd_lrb *lrbp; struct scsi_cmnd *cmd; - int result; int index; for_each_set_bit(index, &completed_reqs, hba->nutrs) { @@ -5234,15 +5245,10 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, if (unlikely(ufshcd_should_inform_monitor(hba, lrbp))) ufshcd_update_monitor(hba, lrbp); ufshcd_add_command_trace(hba, index, UFS_CMD_COMP); - result = ufshcd_transfer_rsp_status(hba, lrbp); - scsi_dma_unmap(cmd); - cmd->result = result; - /* Mark completed command as NULL in LRB */ - lrbp->cmd = NULL; + cmd->result = ufshcd_transfer_rsp_status(hba, lrbp); + ufshcd_release_scsi_cmd(hba, lrbp); /* Do not touch lrbp after scsi done */ scsi_done(cmd); - ufshcd_release(hba); - ufshcd_clk_scaling_update_busy(hba); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) { if (hba->dev_cmd.complete) { -- cgit v1.2.3 From 1fbaa02dfd05229312404aaef8bc9317b4ff8750 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:46 -0800 Subject: scsi: ufs: Improve SCSI abort handling further Release resources when aborting a command. Make sure that aborted commands are completed once by clearing the corresponding tag bit from hba->outstanding_reqs. This patch is an improved version of commit 3ff1f6b6ba6f ("scsi: ufs: core: Improve SCSI abort handling"). Link: https://lore.kernel.org/r/20211203231950.193369-14-bvanassche@acm.org Fixes: 7a3e97b0dc4b ("[SCSI] ufshcd: UFS Host controller driver") Tested-by: Bean Huo Reviewed-by: Adrian Hunter Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5a641610dd74..06954a6e9d5d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6984,6 +6984,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) struct ufshcd_lrb *lrbp = &hba->lrb[tag]; unsigned long flags; int err = FAILED; + bool outstanding; u32 reg; WARN_ONCE(tag < 0, "Invalid tag %d\n", tag); @@ -7061,6 +7062,17 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) goto release; } + /* + * Clear the corresponding bit from outstanding_reqs since the command + * has been aborted successfully. + */ + spin_lock_irqsave(&hba->outstanding_lock, flags); + outstanding = __test_and_clear_bit(tag, &hba->outstanding_reqs); + spin_unlock_irqrestore(&hba->outstanding_lock, flags); + + if (outstanding) + ufshcd_release_scsi_cmd(hba, lrbp); + err = SUCCESS; release: -- cgit v1.2.3 From 3489c34bd02b73a72646037d673a122a53cee174 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:47 -0800 Subject: scsi: ufs: Fix a kernel crash during shutdown Fix the following kernel crash: Unable to handle kernel paging request at virtual address ffffffc91e735000 Call trace: __queue_work+0x26c/0x624 queue_work_on+0x6c/0xf0 ufshcd_hold+0x12c/0x210 __ufshcd_wl_suspend+0xc0/0x400 ufshcd_wl_shutdown+0xb8/0xcc device_shutdown+0x184/0x224 kernel_restart+0x4c/0x124 __arm64_sys_reboot+0x194/0x264 el0_svc_common+0xc8/0x1d4 do_el0_svc+0x30/0x8c el0_svc+0x20/0x30 el0_sync_handler+0x84/0xe4 el0_sync+0x1bc/0x1c0 Fix this crash by ungating the clock before destroying the work queue on which clock gating work is queued. Link: https://lore.kernel.org/r/20211203231950.193369-15-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 06954a6e9d5d..d434d76aa657 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1648,7 +1648,8 @@ int ufshcd_hold(struct ufs_hba *hba, bool async) bool flush_result; unsigned long flags; - if (!ufshcd_is_clkgating_allowed(hba)) + if (!ufshcd_is_clkgating_allowed(hba) || + !hba->clk_gating.is_initialized) goto out; spin_lock_irqsave(hba->host->host_lock, flags); hba->clk_gating.active_reqs++; @@ -1808,7 +1809,7 @@ static void __ufshcd_release(struct ufs_hba *hba) if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL || - hba->outstanding_tasks || + hba->outstanding_tasks || !hba->clk_gating.is_initialized || hba->active_uic_cmd || hba->uic_async_done || hba->clk_gating.state == CLKS_OFF) return; @@ -1943,11 +1944,15 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) { if (!hba->clk_gating.is_initialized) return; + ufshcd_remove_clk_gating_sysfs(hba); - cancel_work_sync(&hba->clk_gating.ungate_work); - cancel_delayed_work_sync(&hba->clk_gating.gate_work); - destroy_workqueue(hba->clk_gating.clk_gating_workq); + + /* Ungate the clock if necessary. */ + ufshcd_hold(hba, false); hba->clk_gating.is_initialized = false; + ufshcd_release(hba); + + destroy_workqueue(hba->clk_gating.clk_gating_workq); } /* Must be called with host lock acquired */ -- cgit v1.2.3 From 5675c381ea51360b4968b78f23aefda73e3de90d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:48 -0800 Subject: scsi: ufs: Stop using the clock scaling lock in the error handler Instead of locking and unlocking the clock scaling lock, surround the command queueing code with an RCU reader lock and call synchronize_rcu(). This patch prepares for removal of the clock scaling lock. Link: https://lore.kernel.org/r/20211203231950.193369-16-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Adrian Hunter Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d434d76aa657..9f0a1f637030 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2684,6 +2684,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (!down_read_trylock(&hba->clk_scaling_lock)) return SCSI_MLQUEUE_HOST_BUSY; + /* + * Allows the UFS error handler to wait for prior ufshcd_queuecommand() + * calls. + */ + rcu_read_lock(); + switch (hba->ufshcd_state) { case UFSHCD_STATE_OPERATIONAL: break; @@ -2762,7 +2768,10 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) } ufshcd_send_command(hba, tag); + out: + rcu_read_unlock(); + up_read(&hba->clk_scaling_lock); if (ufs_trigger_eh()) { @@ -5951,8 +5960,7 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba) } ufshcd_scsi_block_requests(hba); /* Drain ufshcd_queuecommand() */ - down_write(&hba->clk_scaling_lock); - up_write(&hba->clk_scaling_lock); + synchronize_rcu(); cancel_work_sync(&hba->eeh_work); } -- cgit v1.2.3 From 8d077ede48c1532d791c027467d152ae137c54ab Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:49 -0800 Subject: scsi: ufs: Optimize the command queueing code Remove the clock scaling lock from ufshcd_queuecommand() since it is a performance bottleneck. Instead check the SCSI device budget bitmaps in the code that waits for ongoing ufshcd_queuecommand() calls. A bit is set in sdev->budget_map just before scsi_queue_rq() is called and a bit is cleared from that bitmap if scsi_queue_rq() does not submit the request or after the request has finished. See also the blk_mq_{get,put}_dispatch_budget() calls in the block layer. There is no risk for a livelock since the block layer delays queue reruns if queueing a request fails because the SCSI host has been blocked. Link: https://lore.kernel.org/r/20211203231950.193369-17-bvanassche@acm.org Cc: Asutosh Das (asd) Reviewed-by: Asutosh Das Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 33 +++++++++++++++++++++++---------- drivers/scsi/ufs/ufshcd.h | 1 + 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9f0a1f637030..650dddf960c2 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1070,13 +1070,31 @@ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba, return false; } +/* + * Determine the number of pending commands by counting the bits in the SCSI + * device budget maps. This approach has been selected because a bit is set in + * the budget map before scsi_host_queue_ready() checks the host_self_blocked + * flag. The host_self_blocked flag can be modified by calling + * scsi_block_requests() or scsi_unblock_requests(). + */ +static u32 ufshcd_pending_cmds(struct ufs_hba *hba) +{ + struct scsi_device *sdev; + u32 pending = 0; + + shost_for_each_device(sdev, hba->host) + pending += sbitmap_weight(&sdev->budget_map); + + return pending; +} + static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) { unsigned long flags; int ret = 0; u32 tm_doorbell; - u32 tr_doorbell; + u32 tr_pending; bool timeout = false, do_last_check = false; ktime_t start; @@ -1094,8 +1112,8 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, } tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL); - tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); - if (!tm_doorbell && !tr_doorbell) { + tr_pending = ufshcd_pending_cmds(hba); + if (!tm_doorbell && !tr_pending) { timeout = false; break; } else if (do_last_check) { @@ -1115,12 +1133,12 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, do_last_check = true; } spin_lock_irqsave(hba->host->host_lock, flags); - } while (tm_doorbell || tr_doorbell); + } while (tm_doorbell || tr_pending); if (timeout) { dev_err(hba->dev, "%s: timedout waiting for doorbell to clear (tm=0x%x, tr=0x%x)\n", - __func__, tm_doorbell, tr_doorbell); + __func__, tm_doorbell, tr_pending); ret = -EBUSY; } out: @@ -2681,9 +2699,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) WARN_ONCE(tag < 0, "Invalid tag %d\n", tag); - if (!down_read_trylock(&hba->clk_scaling_lock)) - return SCSI_MLQUEUE_HOST_BUSY; - /* * Allows the UFS error handler to wait for prior ufshcd_queuecommand() * calls. @@ -2772,8 +2787,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) out: rcu_read_unlock(); - up_read(&hba->clk_scaling_lock); - if (ufs_trigger_eh()) { unsigned long flags; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 8e942762e668..88c20f3608c2 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -778,6 +778,7 @@ struct ufs_hba_monitor { * @clk_list_head: UFS host controller clocks list node head * @pwr_info: holds current power mode * @max_pwr_info: keeps the device max valid pwm + * @clk_scaling_lock: used to serialize device commands and clock scaling * @desc_size: descriptor sizes reported by device * @urgent_bkops_lvl: keeps track of urgent bkops level for device * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for -- cgit v1.2.3 From eaab9b57305496067e225155ca86bf77c9a982f7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 3 Dec 2021 15:19:50 -0800 Subject: scsi: ufs: Implement polling support The time spent in io_schedule() and also the interrupt latency are significant when submitting direct I/O to a UFS device. Hence this patch that implements polling support. User space software can enable polling by passing the RWF_HIPRI flag to the preadv2() system call or the IORING_SETUP_IOPOLL flag to the io_uring interface. Although the block layer supports to partition the tag space for interrupt-based completions (HCTX_TYPE_DEFAULT) purposes and polling (HCTX_TYPE_POLL), the choice has been made to use the same hardware queue for both hctx types because partitioning the tag space would negatively affect performance. On my test setup this patch increases IOPS from 2736 to 22000 (8x) for the following test: for hipri in 0 1; do fio --ioengine=io_uring --iodepth=1 --rw=randread \ --runtime=60 --time_based=1 --direct=1 --name=qd1 \ --filename=/dev/block/sda --ioscheduler=none --gtod_reduce=1 \ --norandommap --hipri=$hipri done Link: https://lore.kernel.org/r/20211203231950.193369-18-bvanassche@acm.org Tested-by: Bean Huo Reviewed-by: Bean Huo Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 85 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 650dddf960c2..6dd517267f1b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2662,6 +2662,36 @@ static inline bool is_device_wlun(struct scsi_device *sdev) ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN); } +/* + * Associate the UFS controller queue with the default and poll HCTX types. + * Initialize the mq_map[] arrays. + */ +static int ufshcd_map_queues(struct Scsi_Host *shost) +{ + int i, ret; + + for (i = 0; i < shost->nr_maps; i++) { + struct blk_mq_queue_map *map = &shost->tag_set.map[i]; + + switch (i) { + case HCTX_TYPE_DEFAULT: + case HCTX_TYPE_POLL: + map->nr_queues = 1; + break; + case HCTX_TYPE_READ: + map->nr_queues = 0; + break; + default: + WARN_ON_ONCE(true); + } + map->queue_offset = 0; + ret = blk_mq_map_queues(map); + WARN_ON_ONCE(ret); + } + + return 0; +} + static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) { struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr; @@ -2697,7 +2727,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) struct ufshcd_lrb *lrbp; int err = 0; - WARN_ONCE(tag < 0, "Invalid tag %d\n", tag); + WARN_ONCE(tag < 0 || tag >= hba->nutrs, "Invalid tag %d\n", tag); /* * Allows the UFS error handler to wait for prior ufshcd_queuecommand() @@ -5288,6 +5318,31 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, } } +/* + * Returns > 0 if one or more commands have been completed or 0 if no + * requests have been completed. + */ +static int ufshcd_poll(struct Scsi_Host *shost, unsigned int queue_num) +{ + struct ufs_hba *hba = shost_priv(shost); + unsigned long completed_reqs, flags; + u32 tr_doorbell; + + spin_lock_irqsave(&hba->outstanding_lock, flags); + tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); + completed_reqs = ~tr_doorbell & hba->outstanding_reqs; + WARN_ONCE(completed_reqs & ~hba->outstanding_reqs, + "completed: %#lx; outstanding: %#lx\n", completed_reqs, + hba->outstanding_reqs); + hba->outstanding_reqs &= ~completed_reqs; + spin_unlock_irqrestore(&hba->outstanding_lock, flags); + + if (completed_reqs) + __ufshcd_transfer_req_compl(hba, completed_reqs); + + return completed_reqs; +} + /** * ufshcd_transfer_req_compl - handle SCSI and query command completion * @hba: per adapter instance @@ -5298,9 +5353,6 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, */ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) { - unsigned long completed_reqs, flags; - u32 tr_doorbell; - /* Resetting interrupt aggregation counters first and reading the * DOOR_BELL afterward allows us to handle all the completed requests. * In order to prevent other interrupts starvation the DB is read once @@ -5315,21 +5367,13 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) if (ufs_fail_completion()) return IRQ_HANDLED; - spin_lock_irqsave(&hba->outstanding_lock, flags); - tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); - completed_reqs = ~tr_doorbell & hba->outstanding_reqs; - WARN_ONCE(completed_reqs & ~hba->outstanding_reqs, - "completed: %#lx; outstanding: %#lx\n", completed_reqs, - hba->outstanding_reqs); - hba->outstanding_reqs &= ~completed_reqs; - spin_unlock_irqrestore(&hba->outstanding_lock, flags); + /* + * Ignore the ufshcd_poll() return value and return IRQ_HANDLED since we + * do not want polling to trigger spurious interrupt complaints. + */ + ufshcd_poll(hba->host, 0); - if (completed_reqs) { - __ufshcd_transfer_req_compl(hba, completed_reqs); - return IRQ_HANDLED; - } else { - return IRQ_NONE; - } + return IRQ_HANDLED; } int __ufshcd_write_ee_control(struct ufs_hba *hba, u32 ee_ctrl_mask) @@ -6581,6 +6625,8 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, spin_lock_irqsave(host->host_lock, flags); task_tag = req->tag; + WARN_ONCE(task_tag < 0 || task_tag >= hba->nutmrs, "Invalid tag %d\n", + task_tag); hba->tmf_rqs[req->tag] = req; treq->upiu_req.req_header.dword_0 |= cpu_to_be32(task_tag); @@ -8144,7 +8190,9 @@ static struct scsi_host_template ufshcd_driver_template = { .module = THIS_MODULE, .name = UFSHCD, .proc_name = UFSHCD, + .map_queues = ufshcd_map_queues, .queuecommand = ufshcd_queuecommand, + .mq_poll = ufshcd_poll, .slave_alloc = ufshcd_slave_alloc, .slave_configure = ufshcd_slave_configure, .slave_destroy = ufshcd_slave_destroy, @@ -9432,6 +9480,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle) err = -ENOMEM; goto out_error; } + host->nr_maps = HCTX_TYPE_POLL + 1; hba = shost_priv(host); hba->host = host; hba->dev = dev; -- cgit v1.2.3 From f0d3919697492950f57a26a1093aee53880d669d Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:36 -0800 Subject: scsi: lpfc: Fix leaked lpfc_dmabuf mbox allocations with NPIV During rmmod testing, messages appeared indicating lpfc_mbuf_pool entries were still busy. This situation was only seen doing rmmod after at least 1 vport (NPIV) instance was created and destroyed. The number of messages scaled with the number of vports created. When a vport is created, it can receive a PLOGI from another initiator Nport. When this happens, the driver prepares to ack the PLOGI and prepares an RPI for registration (via mbx cmd) which includes an mbuf allocation. During the unsolicited PLOGI processing and after the RPI preparation, the driver recognizes it is one of the vport instances and decides to reject the PLOGI. During the LS_RJT preparation for the PLOGI, the mailbox struct allocated for RPI registration is freed, but the mbuf that was also allocated is not released. Fix by freeing the mbuf with the mailbox struct in the LS_RJT path. As part of the code review to figure the issue out a couple of other areas where found that also would not have released the mbuf. Those are cleaned up as well. Link: https://lore.kernel.org/r/20211204002644.116455-2-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 6 +++++- drivers/scsi/lpfc/lpfc_init.c | 8 ++++++-- drivers/scsi/lpfc/lpfc_nportdisc.c | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b940e0268f96..67335aae683e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -6904,6 +6904,7 @@ static int lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context) { LPFC_MBOXQ_t *mbox = NULL; + struct lpfc_dmabuf *mp; int rc; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -6919,8 +6920,11 @@ lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context) mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_page_a0; mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + mp = (struct lpfc_dmabuf *)mbox->ctx_buf; + lpfc_mbuf_free(phba, mp->virt, mp->phys); goto issue_mbox_fail; + } return 0; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ba17a8f740a9..7628b0634c57 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5373,8 +5373,10 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, */ if (!(phba->hba_flag & HBA_FCOE_MODE)) { rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); goto out_free_dmabuf; + } return; } /* @@ -6337,8 +6339,10 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) } rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); goto out_free_dmabuf; + } return; out_free_dmabuf: diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 27263f02ab9f..7d717a4ac14d 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -322,6 +322,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; + struct lpfc_dmabuf *mp; uint64_t nlp_portwwn = 0; uint32_t *lp; IOCB_t *icmd; @@ -571,6 +572,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * a default RPI. */ if (phba->sli_rev == LPFC_SLI_REV4) { + mp = (struct lpfc_dmabuf *)login_mbox->ctx_buf; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } mempool_free(login_mbox, phba->mbox_mem_pool); login_mbox = NULL; } else { -- cgit v1.2.3 From 2e81b1a374da5d6024208c16c4a5224a70cafa64 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:37 -0800 Subject: scsi: lpfc: Change return code on I/Os received during link bounce During heavy I/O testing with issue_lip to bounce the link, occasionally I/O is terminated with status 3 result 9, which means the RPI is suspended. The I/O is completed and this type of error will result in immediate retry by the SCSI layer. The retry count expires and the I/O fails and returns error to the application. To avoid these quick retry/retries exhausted scenarios change the return code given to the midlayer to DID_REQUEUE rather than DID_ERROR. This gets them retried, and eventually succeed when the link recovers. Link: https://lore.kernel.org/r/20211204002644.116455-3-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw.h | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 634f8fff7425..61c9db31d9da 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -3746,7 +3746,7 @@ typedef struct { #define IOERR_ILLEGAL_COMMAND 0x06 #define IOERR_XCHG_DROPPED 0x07 #define IOERR_ILLEGAL_FIELD 0x08 -#define IOERR_BAD_CONTINUE 0x09 +#define IOERR_RPI_SUSPENDED 0x09 #define IOERR_TOO_MANY_BUFFERS 0x0A #define IOERR_RCV_BUFFER_WAITING 0x0B #define IOERR_NO_CONNECTION 0x0C diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 6ccf573acdec..5a3da38a9067 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -4393,6 +4393,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, if (lpfc_cmd->result == IOERR_INVALID_RPI || lpfc_cmd->result == IOERR_NO_RESOURCES || lpfc_cmd->result == IOERR_ABORT_REQUESTED || + lpfc_cmd->result == IOERR_RPI_SUSPENDED || lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) { cmd->result = DID_REQUEUE << 16; break; @@ -4448,10 +4449,11 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, "9039 Iodone <%d/%llu> cmd x%px, error " - "x%x SNS x%x x%x Data: x%x x%x\n", + "x%x SNS x%x x%x LBA x%llx Data: x%x x%x\n", cmd->device->id, cmd->device->lun, cmd, - cmd->result, *lp, *(lp + 3), cmd->retries, - scsi_get_resid(cmd)); + cmd->result, *lp, *(lp + 3), + (u64)scsi_get_lba(cmd), + cmd->retries, scsi_get_resid(cmd)); } lpfc_update_stats(vport, lpfc_cmd); -- cgit v1.2.3 From 7576d48c64f36f6fea9df2882f710a474fa35f40 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:38 -0800 Subject: scsi: lpfc: Fix lpfc_force_rscn ndlp kref imbalance Issuing lpfc_force_rscn twice results in an ndlp kref use-after-free call trace. A prior patch reworked the get/put handling by ensuring nlp_get was done before WQE submission and a put was done in the completion path. Unfortunately, the issue_els_rscn path had a piece of legacy code that did a nlp_put, causing an imbalance on the ref counts. Fixed by removing the unnecessary legacy code snippet. Link: https://lore.kernel.org/r/20211204002644.116455-4-jsmart2021@gmail.com Fixes: 4430f7fd09ec ("scsi: lpfc: Rework locations of ndlp reference taking") Cc: # v5.11+ Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 67335aae683e..ba90ece8b81e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3538,11 +3538,6 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) return 1; } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of node. - */ - if (!(vport->fc_flag & FC_PT2PT)) - lpfc_nlp_put(ndlp); return 0; } -- cgit v1.2.3 From 8ed190a91950564775cbaae9e8e8083a69a8da23 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:39 -0800 Subject: scsi: lpfc: Fix NPIV port deletion crash The driver is calling schedule_timeout after the DA_ID nameserver request and LOGO commands are issued to the fabric by the initiator virtual endport. These fixed delay functions are causing long delays in the driver's worker thread when processing discovery I/Os in a serialized fashion, which is then triggering mailbox timeout errors artificially. To fix this, don't wait on the DA_ID request to complete and call wait_event_timeout to allow the vport delete thread to make progress on an event driven basis rather than fixing the wait time. Link: https://lore.kernel.org/r/20211204002644.116455-5-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 2 - drivers/scsi/lpfc/lpfc_els.c | 11 +++++- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 - drivers/scsi/lpfc/lpfc_vport.c | 83 ++++++++++++++++++++++++++++++---------- 4 files changed, 73 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 2f8e6d0a926f..a04995832459 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -669,8 +669,6 @@ struct lpfc_vport { struct timer_list els_tmofunc; struct timer_list delayed_disc_tmo; - int unreg_vpi_cmpl; - uint8_t load_flag; #define FC_LOADING 0x1 /* HBA in process of loading drvr */ #define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index ba90ece8b81e..3c14ada12363 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -10978,10 +10978,19 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_can_disctmo(vport); } + if (ndlp->save_flags & NLP_WAIT_FOR_LOGO) { + /* Wake up lpfc_vport_delete if waiting...*/ + if (ndlp->logo_waitq) + wake_up(ndlp->logo_waitq); + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~(NLP_ISSUE_LOGO | NLP_LOGO_SND); + ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; + spin_unlock_irq(&ndlp->lock); + } + /* Safe to release resources now. */ lpfc_els_free_iocb(phba, cmdiocb); lpfc_nlp_put(ndlp); - vport->unreg_vpi_cmpl = VPORT_ERROR; } /** diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 9fe6e5b386ce..802fd30a9fb8 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -3928,7 +3928,6 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport->vpi_state &= ~LPFC_VPI_REGISTERED; vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); - vport->unreg_vpi_cmpl = VPORT_OK; mempool_free(pmb, phba->mbox_mem_pool); lpfc_cleanup_vports_rrqs(vport, NULL); /* @@ -3958,7 +3957,6 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "1800 Could not issue unreg_vpi\n"); mempool_free(mbox, phba->mbox_mem_pool); - vport->unreg_vpi_cmpl = VPORT_ERROR; return rc; } return 0; diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index da9a1f72d938..d694d0cff5a5 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -485,23 +485,68 @@ error_out: return rc; } +static int +lpfc_send_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + int rc; + struct lpfc_hba *phba = vport->phba; + + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); + + spin_lock_irq(&ndlp->lock); + if (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO) && + !ndlp->logo_waitq) { + ndlp->logo_waitq = &waitq; + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_flag |= NLP_ISSUE_LOGO; + ndlp->save_flags |= NLP_WAIT_FOR_LOGO; + } + spin_unlock_irq(&ndlp->lock); + rc = lpfc_issue_els_npiv_logo(vport, ndlp); + if (!rc) { + wait_event_timeout(waitq, + (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO)), + msecs_to_jiffies(phba->fc_ratov * 2000)); + + if (!(ndlp->save_flags & NLP_WAIT_FOR_LOGO)) + goto logo_cmpl; + /* LOGO wait failed. Correct status. */ + rc = -EINTR; + } else { + rc = -EIO; + } + + /* Error - clean up node flags. */ + spin_lock_irq(&ndlp->lock); + ndlp->nlp_flag &= ~NLP_ISSUE_LOGO; + ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; + spin_unlock_irq(&ndlp->lock); + + logo_cmpl: + lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, + "1824 Issue LOGO completes with status %d\n", + rc); + spin_lock_irq(&ndlp->lock); + ndlp->logo_waitq = NULL; + spin_unlock_irq(&ndlp->lock); + return rc; +} + static int disable_vport(struct fc_vport *fc_vport) { struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - long timeout; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + /* Can't disable during an outstanding delete. */ + if (vport->load_flag & FC_UNLOADING) + return 0; + ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (ndlp && phba->link_state >= LPFC_LINK_UP) { - vport->unreg_vpi_cmpl = VPORT_INVAL; - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_issue_els_npiv_logo(vport, ndlp)) - while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) - timeout = schedule_timeout(timeout); - } + if (ndlp && phba->link_state >= LPFC_LINK_UP) + (void)lpfc_send_npiv_logo(vport, ndlp); lpfc_sli_host_down(vport); @@ -600,7 +645,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - long timeout; + int rc; if (vport->port_type == LPFC_PHYSICAL_PORT) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, @@ -665,15 +710,14 @@ lpfc_vport_delete(struct fc_vport *fc_vport) phba->fc_topology != LPFC_TOPOLOGY_LOOP) { if (vport->cfg_enable_da_id) { /* Send DA_ID and wait for a completion. */ - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0)) - while (vport->ct_flags && timeout) - timeout = schedule_timeout(timeout); - else + rc = lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0); + if (rc) { lpfc_printf_log(vport->phba, KERN_WARNING, LOG_VPORT, "1829 CT command failed to " - "delete objects on fabric\n"); + "delete objects on fabric, " + "rc %d\n", rc); + } } /* @@ -688,11 +732,10 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) goto skip_logo; - vport->unreg_vpi_cmpl = VPORT_INVAL; - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_issue_els_npiv_logo(vport, ndlp)) - while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) - timeout = schedule_timeout(timeout); + + rc = lpfc_send_npiv_logo(vport, ndlp); + if (rc) + goto skip_logo; } if (!(phba->pport->load_flag & FC_UNLOADING)) -- cgit v1.2.3 From 7dd2e2a923173d637c272e483966be8e96a72b64 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:40 -0800 Subject: scsi: lpfc: Trigger SLI4 firmware dump before doing driver cleanup Extraneous teardown routines are present in the firmware dump path causing altered states in firmware captures. When a firmware dump is requested via sysfs, trigger the dump immediately without tearing down structures and changing adapter state. The driver shall rely on pre-existing firmware error state clean up handlers to restore the adapter. Link: https://lore.kernel.org/r/20211204002644.116455-6-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 2 +- drivers/scsi/lpfc/lpfc_attr.c | 62 ++++++++++++++++++++++++++-------------- drivers/scsi/lpfc/lpfc_hbadisc.c | 8 +++++- drivers/scsi/lpfc/lpfc_sli.c | 6 ---- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a04995832459..e652926fb47a 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1021,7 +1021,6 @@ struct lpfc_hba { #define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ #define HBA_IOQ_FLUSH 0x8000 /* FCP/NVME I/O queues being flushed */ -#define HBA_FW_DUMP_OP 0x10000 /* Skips fn reset before FW dump */ #define HBA_RECOVERABLE_UE 0x20000 /* Firmware supports recoverable UE */ #define HBA_FORCED_LINK_SPEED 0x40000 /* * Firmware supports Forced Link Speed @@ -1038,6 +1037,7 @@ struct lpfc_hba { #define HBA_HBEAT_TMO 0x8000000 /* HBEAT initiated after timeout */ #define HBA_FLOGI_OUTSTANDING 0x10000000 /* FLOGI is outstanding */ + struct completion *fw_dump_cmpl; /* cmpl event tracker for fw_dump */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index dd4c51b6ef4e..7a7f17d71811 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1709,25 +1709,25 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) before_fc_flag = phba->pport->fc_flag; sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn; - /* Disable SR-IOV virtual functions if enabled */ - if (phba->cfg_sriov_nr_virtfn) { - pci_disable_sriov(pdev); - phba->cfg_sriov_nr_virtfn = 0; - } + if (opcode == LPFC_FW_DUMP) { + init_completion(&online_compl); + phba->fw_dump_cmpl = &online_compl; + } else { + /* Disable SR-IOV virtual functions if enabled */ + if (phba->cfg_sriov_nr_virtfn) { + pci_disable_sriov(pdev); + phba->cfg_sriov_nr_virtfn = 0; + } - if (opcode == LPFC_FW_DUMP) - phba->hba_flag |= HBA_FW_DUMP_OP; + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); + if (status != 0) + return status; - if (status != 0) { - phba->hba_flag &= ~HBA_FW_DUMP_OP; - return status; + /* wait for the device to be quiesced before firmware reset */ + msleep(100); } - /* wait for the device to be quiesced before firmware reset */ - msleep(100); - reg_val = readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET); @@ -1756,24 +1756,42 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3153 Fail to perform the requested " "access: x%x\n", reg_val); + if (phba->fw_dump_cmpl) + phba->fw_dump_cmpl = NULL; return rc; } /* keep the original port state */ - if (before_fc_flag & FC_OFFLINE_MODE) - goto out; - - init_completion(&online_compl); - job_posted = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (!job_posted) + if (before_fc_flag & FC_OFFLINE_MODE) { + if (phba->fw_dump_cmpl) + phba->fw_dump_cmpl = NULL; goto out; + } - wait_for_completion(&online_compl); + /* Firmware dump will trigger an HA_ERATT event, and + * lpfc_handle_eratt_s4 routine already handles bringing the port back + * online. + */ + if (opcode == LPFC_FW_DUMP) { + wait_for_completion(phba->fw_dump_cmpl); + } else { + init_completion(&online_compl); + job_posted = lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + if (!job_posted) + goto out; + wait_for_completion(&online_compl); + } out: /* in any case, restore the virtual functions enabled as before */ if (sriov_nr_virtfn) { + /* If fw_dump was performed, first disable to clean up */ + if (opcode == LPFC_FW_DUMP) { + pci_disable_sriov(pdev); + phba->cfg_sriov_nr_virtfn = 0; + } + sriov_err = lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn); if (!sriov_err) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 802fd30a9fb8..816fc406135b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -869,10 +869,16 @@ lpfc_work_done(struct lpfc_hba *phba) if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) lpfc_sli4_post_async_mbox(phba); - if (ha_copy & HA_ERATT) + if (ha_copy & HA_ERATT) { /* Handle the error attention event */ lpfc_handle_eratt(phba); + if (phba->fw_dump_cmpl) { + complete(phba->fw_dump_cmpl); + phba->fw_dump_cmpl = NULL; + } + } + if (ha_copy & HA_MBATT) lpfc_sli_handle_mb_event(phba); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 5dedb3de271d..513a78d08b1d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5046,12 +5046,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->fcf.fcf_flag = 0; spin_unlock_irq(&phba->hbalock); - /* SLI4 INTF 2: if FW dump is being taken skip INIT_PORT */ - if (phba->hba_flag & HBA_FW_DUMP_OP) { - phba->hba_flag &= ~HBA_FW_DUMP_OP; - return rc; - } - /* Now physically reset the device */ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0389 Performing PCI function reset!\n"); -- cgit v1.2.3 From a6269f837045acb02904f31f05acde847ec8f8a7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:41 -0800 Subject: scsi: lpfc: Adjust CMF total bytes and rxmonitor Calculate any extra bytes needed to account for timer accuracy. If we are less than LPFC_CMF_INTERVAL, then calculate the adjustment needed for total to reflect a full LPFC_CMF_INTERVAL. Add additional info to rxmonitor, and adjust some log formatting. Link: https://lore.kernel.org/r/20211204002644.116455-7-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_debugfs.c | 14 ++++++++------ drivers/scsi/lpfc/lpfc_debugfs.h | 2 +- drivers/scsi/lpfc/lpfc_init.c | 20 ++++++++++++-------- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index e652926fb47a..49abbf132bee 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1602,6 +1602,7 @@ struct lpfc_hba { #define LPFC_MAX_RXMONITOR_ENTRY 800 #define LPFC_MAX_RXMONITOR_DUMP 32 struct rxtable_entry { + uint64_t cmf_bytes; /* Total no of read bytes for CMF_SYNC_WQE */ uint64_t total_bytes; /* Total no of read bytes requested */ uint64_t rcv_bytes; /* Total no of read bytes completed */ uint64_t avg_io_size; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index bd6d459afce5..ab2550ad0597 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -5561,22 +5561,24 @@ lpfc_rx_monitor_read(struct file *file, char __user *buf, size_t nbytes, start = tail; len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len, - " MaxBPI\t Total Data Cmd Total Data Cmpl " - " Latency(us) Avg IO Size\tMax IO Size IO cnt " - "Info BWutil(ms)\n"); + " MaxBPI Tot_Data_CMF Tot_Data_Cmd " + "Tot_Data_Cmpl Lat(us) Avg_IO Max_IO " + "Bsy IO_cnt Info BWutil(ms)\n"); get_table: for (i = start; i < last; i++) { entry = &phba->rxtable[i]; len += scnprintf(buffer + len, MAX_DEBUGFS_RX_TABLE_SIZE - len, - "%3d:%12lld %12lld\t%12lld\t" - "%8lldus\t%8lld\t%10lld " - "%8d %2d %2d(%2d)\n", + "%3d:%12lld %12lld %12lld %12lld " + "%7lldus %8lld %7lld " + "%2d %4d %2d %2d(%2d)\n", i, entry->max_bytes_per_interval, + entry->cmf_bytes, entry->total_bytes, entry->rcv_bytes, entry->avg_io_latency, entry->avg_io_size, entry->max_read_cnt, + entry->cmf_busy, entry->io_cnt, entry->cmf_info, entry->timer_utilization, diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index a5bf71b34972..6dd361c1fd31 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -282,7 +282,7 @@ struct lpfc_idiag { void *ptr_private; }; -#define MAX_DEBUGFS_RX_TABLE_SIZE (100 * LPFC_MAX_RXMONITOR_ENTRY) +#define MAX_DEBUGFS_RX_TABLE_SIZE (128 * LPFC_MAX_RXMONITOR_ENTRY) struct lpfc_rx_monitor_debug { char *i_private; char *buffer; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7628b0634c57..132f2e60bdb4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5927,7 +5927,7 @@ lpfc_cmf_timer(struct hrtimer *timer) uint32_t io_cnt; uint32_t head, tail; uint32_t busy, max_read; - uint64_t total, rcv, lat, mbpi, extra; + uint64_t total, rcv, lat, mbpi, extra, cnt; int timer_interval = LPFC_CMF_INTERVAL; uint32_t ms; struct lpfc_cgn_stat *cgs; @@ -5998,20 +5998,23 @@ lpfc_cmf_timer(struct hrtimer *timer) /* Calculate any extra bytes needed to account for the * timer accuracy. If we are less than LPFC_CMF_INTERVAL - * add an extra 3% slop factor, equal to LPFC_CMF_INTERVAL - * add an extra 2%. The goal is to equalize total with a - * time > LPFC_CMF_INTERVAL or <= LPFC_CMF_INTERVAL + 1 + * calculate the adjustment needed for total to reflect + * a full LPFC_CMF_INTERVAL. */ - if (ms == LPFC_CMF_INTERVAL) - extra = div_u64(total, 50); - else if (ms < LPFC_CMF_INTERVAL) - extra = div_u64(total, 33); + if (ms && ms < LPFC_CMF_INTERVAL) { + cnt = div_u64(total, ms); /* bytes per ms */ + cnt *= LPFC_CMF_INTERVAL; /* what total should be */ + if (cnt > mbpi) + cnt = mbpi; + extra = cnt - total; + } lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total + extra); } else { /* For Monitor mode or link down we want mbpi * to be the full link speed */ mbpi = phba->cmf_link_byte_count; + extra = 0; } phba->cmf_timer_cnt++; @@ -6042,6 +6045,7 @@ lpfc_cmf_timer(struct hrtimer *timer) LPFC_RXMONITOR_TABLE_IN_USE); entry = &phba->rxtable[head]; entry->total_bytes = total; + entry->cmf_bytes = total + extra; entry->rcv_bytes = rcv; entry->cmf_busy = busy; entry->cmf_info = phba->cmf_active_info; -- cgit v1.2.3 From 05116ef9c4b444f7fdbb56f9e13c2ec941726639 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:42 -0800 Subject: scsi: lpfc: Cap CMF read bytes to MBPI Ensure read bytes data does not go over MBPI for CMF timer intervals that are purposely shortened. Link: https://lore.kernel.org/r/20211204002644.116455-8-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 2 +- drivers/scsi/lpfc/lpfc_init.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 49abbf132bee..3faadcfcdcbb 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1028,7 +1028,7 @@ struct lpfc_hba { */ #define HBA_PCI_ERR 0x80000 /* The PCI slot is offline */ #define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */ -#define HBA_CGN_RSVD1 0x200000 /* Reserved CGN flag */ +#define HBA_SHORT_CMF 0x200000 /* shorter CMF timer routine */ #define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */ #define HBA_DEFER_FLOGI 0x800000 /* Defer FLOGI till read_sparm cmpl */ #define HBA_SETUP 0x1000000 /* Signifies HBA setup is completed */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 132f2e60bdb4..2fe7d9d885d9 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -6004,8 +6004,13 @@ lpfc_cmf_timer(struct hrtimer *timer) if (ms && ms < LPFC_CMF_INTERVAL) { cnt = div_u64(total, ms); /* bytes per ms */ cnt *= LPFC_CMF_INTERVAL; /* what total should be */ - if (cnt > mbpi) + + /* If the timeout is scheduled to be shorter, + * this value may skew the data, so cap it at mbpi. + */ + if ((phba->hba_flag & HBA_SHORT_CMF) && cnt > mbpi) cnt = mbpi; + extra = cnt - total; } lpfc_issue_cmf_sync_wqe(phba, LPFC_CMF_INTERVAL, total + extra); @@ -6088,6 +6093,8 @@ lpfc_cmf_timer(struct hrtimer *timer) /* Each minute save Fabric and Driver congestion information */ lpfc_cgn_save_evt_cnt(phba); + phba->hba_flag &= ~HBA_SHORT_CMF; + /* Since we need to call lpfc_cgn_save_evt_cnt every minute, on the * minute, adjust our next timer interval, if needed, to ensure a * 1 minute granularity when we get the next timer interrupt. @@ -6098,6 +6105,8 @@ lpfc_cmf_timer(struct hrtimer *timer) jiffies); if (timer_interval <= 0) timer_interval = LPFC_CMF_INTERVAL; + else + phba->hba_flag |= HBA_SHORT_CMF; /* If we adjust timer_interval, max_bytes_per_interval * needs to be adjusted as well. -- cgit v1.2.3 From 6014a2468f0e49194f612b1f09f99eacee0a409a Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:43 -0800 Subject: scsi: lpfc: Add additional debugfs support for CMF Dump raw CMF parameter information in debugfs cgn_buffer. Link: https://lore.kernel.org/r/20211204002644.116455-9-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_debugfs.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index ab2550ad0597..21152c9a96ef 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -5484,7 +5484,7 @@ lpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes, if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) { len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, "Truncated . . .\n"); - break; + goto out; } len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, "%03x: %08x %08x %08x %08x " @@ -5495,6 +5495,17 @@ lpfc_cgn_buffer_read(struct file *file, char __user *buf, size_t nbytes, cnt += 32; ptr += 8; } + if (len > (LPFC_CGN_BUF_SIZE - LPFC_DEBUG_OUT_LINE_SZ)) { + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Truncated . . .\n"); + goto out; + } + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "Parameter Data\n"); + ptr = (uint32_t *)&phba->cgn_p; + len += scnprintf(buffer + len, LPFC_CGN_BUF_SIZE - len, + "%08x %08x %08x %08x\n", + *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3)); out: return simple_read_from_buffer(buf, nbytes, ppos, buffer, len); } -- cgit v1.2.3 From 4437503bfbec2f02b41b2492520fe627715889a7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 3 Dec 2021 16:26:44 -0800 Subject: scsi: lpfc: Update lpfc version to 14.0.0.4 Update lpfc version to 14.0.0.4. Link: https://lore.kernel.org/r/20211204002644.116455-10-jsmart2021@gmail.com Co-developed-by: Justin Tee Signed-off-by: Justin Tee Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 5a4d3b24fbce..2e9348a6897c 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.0.0.3" +#define LPFC_DRIVER_VERSION "14.0.0.4" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.2.3 From 532adda9f405d69ef1837f59e60512313fdf0f63 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 8 Dec 2021 11:59:57 -0800 Subject: scsi: lpfc: Use struct_group() to initialize struct lpfc_cgn_info In preparation for FORTIFY_SOURCE performing compile-time and run-time field bounds checking for memset(), avoid intentionally writing across neighboring fields. Add struct_group() to mark "stat" region of struct lpfc_cgn_info that should be initialized to zero, and refactor the "data" region memset() to wipe everything up to the cgn_stats region. Link: https://lore.kernel.org/r/20211208195957.1603092-1-keescook@chromium.org Reviewed-by: James Smart Signed-off-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 90 +++++++++++++++++++++---------------------- drivers/scsi/lpfc/lpfc_init.c | 4 +- 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 3faadcfcdcbb..4878c94761f9 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -496,52 +496,50 @@ struct lpfc_cgn_info { __le32 cgn_alarm_hr[24]; __le32 cgn_alarm_day[LPFC_MAX_CGN_DAYS]; - /* Start of congestion statistics */ - uint8_t cgn_stat_npm; /* Notifications per minute */ - - /* Start Time */ - uint8_t cgn_stat_month; - uint8_t cgn_stat_day; - uint8_t cgn_stat_year; - uint8_t cgn_stat_hour; - uint8_t cgn_stat_minute; - uint8_t cgn_pad2[2]; - - __le32 cgn_notification; - __le32 cgn_peer_notification; - __le32 link_integ_notification; - __le32 delivery_notification; - - uint8_t cgn_stat_cgn_month; /* Last congestion notification FPIN */ - uint8_t cgn_stat_cgn_day; - uint8_t cgn_stat_cgn_year; - uint8_t cgn_stat_cgn_hour; - uint8_t cgn_stat_cgn_min; - uint8_t cgn_stat_cgn_sec; - - uint8_t cgn_stat_peer_month; /* Last peer congestion FPIN */ - uint8_t cgn_stat_peer_day; - uint8_t cgn_stat_peer_year; - uint8_t cgn_stat_peer_hour; - uint8_t cgn_stat_peer_min; - uint8_t cgn_stat_peer_sec; - - uint8_t cgn_stat_lnk_month; /* Last link integrity FPIN */ - uint8_t cgn_stat_lnk_day; - uint8_t cgn_stat_lnk_year; - uint8_t cgn_stat_lnk_hour; - uint8_t cgn_stat_lnk_min; - uint8_t cgn_stat_lnk_sec; - - uint8_t cgn_stat_del_month; /* Last delivery notification FPIN */ - uint8_t cgn_stat_del_day; - uint8_t cgn_stat_del_year; - uint8_t cgn_stat_del_hour; - uint8_t cgn_stat_del_min; - uint8_t cgn_stat_del_sec; -#define LPFC_CGN_STAT_SIZE 48 -#define LPFC_CGN_DATA_SIZE (sizeof(struct lpfc_cgn_info) - \ - LPFC_CGN_STAT_SIZE - sizeof(uint32_t)) + struct_group(cgn_stat, + uint8_t cgn_stat_npm; /* Notifications per minute */ + + /* Start Time */ + uint8_t cgn_stat_month; + uint8_t cgn_stat_day; + uint8_t cgn_stat_year; + uint8_t cgn_stat_hour; + uint8_t cgn_stat_minute; + uint8_t cgn_pad2[2]; + + __le32 cgn_notification; + __le32 cgn_peer_notification; + __le32 link_integ_notification; + __le32 delivery_notification; + + uint8_t cgn_stat_cgn_month; /* Last congestion notification FPIN */ + uint8_t cgn_stat_cgn_day; + uint8_t cgn_stat_cgn_year; + uint8_t cgn_stat_cgn_hour; + uint8_t cgn_stat_cgn_min; + uint8_t cgn_stat_cgn_sec; + + uint8_t cgn_stat_peer_month; /* Last peer congestion FPIN */ + uint8_t cgn_stat_peer_day; + uint8_t cgn_stat_peer_year; + uint8_t cgn_stat_peer_hour; + uint8_t cgn_stat_peer_min; + uint8_t cgn_stat_peer_sec; + + uint8_t cgn_stat_lnk_month; /* Last link integrity FPIN */ + uint8_t cgn_stat_lnk_day; + uint8_t cgn_stat_lnk_year; + uint8_t cgn_stat_lnk_hour; + uint8_t cgn_stat_lnk_min; + uint8_t cgn_stat_lnk_sec; + + uint8_t cgn_stat_del_month; /* Last delivery notification FPIN */ + uint8_t cgn_stat_del_day; + uint8_t cgn_stat_del_year; + uint8_t cgn_stat_del_hour; + uint8_t cgn_stat_del_min; + uint8_t cgn_stat_del_sec; + ); __le32 cgn_info_crc; #define LPFC_CGN_CRC32_MAGIC_NUMBER 0x1EDC6F41 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 2fe7d9d885d9..c18000d05379 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -13483,7 +13483,7 @@ lpfc_init_congestion_buf(struct lpfc_hba *phba) phba->cgn_evt_minute = 0; phba->hba_flag &= ~HBA_CGN_DAY_WRAP; - memset(cp, 0xff, LPFC_CGN_DATA_SIZE); + memset(cp, 0xff, offsetof(struct lpfc_cgn_info, cgn_stat)); cp->cgn_info_size = cpu_to_le16(LPFC_CGN_INFO_SZ); cp->cgn_info_version = LPFC_CGN_INFO_V3; @@ -13542,7 +13542,7 @@ lpfc_init_congestion_stat(struct lpfc_hba *phba) return; cp = (struct lpfc_cgn_info *)phba->cgn_i->virt; - memset(&cp->cgn_stat_npm, 0, LPFC_CGN_STAT_SIZE); + memset(&cp->cgn_stat, 0, sizeof(cp->cgn_stat)); ktime_get_real_ts64(&cmpl_time); time64_to_tm(cmpl_time.tv_sec, 0, &broken); -- cgit v1.2.3 From c167dd0b2a7afcf2c25e44b9b6168cba3a51d27d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 3 Dec 2021 14:33:51 -0800 Subject: scsi: lpfc: Use struct_group to isolate cast to larger object When building under -Warray-bounds, a warning is generated when casting a u32 into MAILBOX_t (which is larger). This warning is conservative, but it's not an unreasonable change to make to improve future robustness. Use a tagged struct_group that can refer to either the specific fields or the first u32 separately, silencing this warning: drivers/scsi/lpfc/lpfc_sli.c: In function 'lpfc_reset_barrier': drivers/scsi/lpfc/lpfc_sli.c:4787:29: error: array subscript 'MAILBOX_t[0]' is partly outside array bounds of 'volatile uint32_t[1]' {aka 'volatile unsigned int[1]'} [-Werror=array-bounds] 4787 | ((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD; | ^~ drivers/scsi/lpfc/lpfc_sli.c:4752:27: note: while referencing 'mbox' 4752 | volatile uint32_t mbox; | ^~~~ There is no change to the resulting executable instruction code. Link: https://lore.kernel.org/r/20211203223351.107323-1-keescook@chromium.org Reviewed-by: James Smart Signed-off-by: Kees Cook Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw.h | 27 +++++++++++++++++---------- drivers/scsi/lpfc/lpfc_sli.c | 32 +++++++++++++++----------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 61c9db31d9da..4461c3d6fc4f 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -3675,19 +3675,26 @@ union sli_var { }; typedef struct { + struct_group_tagged(MAILBOX_word0, bits, + union { + struct { #ifdef __BIG_ENDIAN_BITFIELD - uint16_t mbxStatus; - uint8_t mbxCommand; - uint8_t mbxReserved:6; - uint8_t mbxHc:1; - uint8_t mbxOwner:1; /* Low order bit first word */ + uint16_t mbxStatus; + uint8_t mbxCommand; + uint8_t mbxReserved:6; + uint8_t mbxHc:1; + uint8_t mbxOwner:1; /* Low order bit first word */ #else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t mbxOwner:1; /* Low order bit first word */ - uint8_t mbxHc:1; - uint8_t mbxReserved:6; - uint8_t mbxCommand; - uint16_t mbxStatus; + uint8_t mbxOwner:1; /* Low order bit first word */ + uint8_t mbxHc:1; + uint8_t mbxReserved:6; + uint8_t mbxCommand; + uint16_t mbxStatus; #endif + }; + u32 word0; + }; + ); MAILVARIANTS un; union sli_var us; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 513a78d08b1d..cd26c0f8c281 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4749,7 +4749,7 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) { uint32_t __iomem *resp_buf; uint32_t __iomem *mbox_buf; - volatile uint32_t mbox; + volatile struct MAILBOX_word0 mbox; uint32_t hc_copy, ha_copy, resp_data; int i; uint8_t hdrtype; @@ -4783,13 +4783,13 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) phba->pport->stopped = 1; } - mbox = 0; - ((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD; - ((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP; + mbox.word0 = 0; + mbox.mbxCommand = MBX_KILL_BOARD; + mbox.mbxOwner = OWN_CHIP; writel(BARRIER_TEST_PATTERN, (resp_buf + 1)); mbox_buf = phba->MBslimaddr; - writel(mbox, mbox_buf); + writel(mbox.word0, mbox_buf); for (i = 0; i < 50; i++) { if (lpfc_readl((resp_buf + 1), &resp_data)) @@ -4810,12 +4810,12 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) goto clear_errat; } - ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST; + mbox.mbxOwner = OWN_HOST; resp_data = 0; for (i = 0; i < 500; i++) { if (lpfc_readl(resp_buf, &resp_data)) return; - if (resp_data != mbox) + if (resp_data != mbox.word0) mdelay(1); else break; @@ -5085,9 +5085,8 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) static int lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) { - MAILBOX_t *mb; + volatile struct MAILBOX_word0 mb; struct lpfc_sli *psli; - volatile uint32_t word0; void __iomem *to_slim; uint32_t hba_aer_enabled; @@ -5104,24 +5103,23 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) (phba->pport) ? phba->pport->port_state : 0, psli->sli_flag); - word0 = 0; - mb = (MAILBOX_t *) &word0; - mb->mbxCommand = MBX_RESTART; - mb->mbxHc = 1; + mb.word0 = 0; + mb.mbxCommand = MBX_RESTART; + mb.mbxHc = 1; lpfc_reset_barrier(phba); to_slim = phba->MBslimaddr; - writel(*(uint32_t *) mb, to_slim); + writel(mb.word0, to_slim); readl(to_slim); /* flush */ /* Only skip post after fc_ffinit is completed */ if (phba->pport && phba->pport->port_state) - word0 = 1; /* This is really setting up word1 */ + mb.word0 = 1; /* This is really setting up word1 */ else - word0 = 0; /* This is really setting up word1 */ + mb.word0 = 0; /* This is really setting up word1 */ to_slim = phba->MBslimaddr + sizeof (uint32_t); - writel(*(uint32_t *) mb, to_slim); + writel(mb.word0, to_slim); readl(to_slim); /* flush */ lpfc_sli_brdreset(phba); -- cgit v1.2.3 From 8c2d04551545d3722c1e6891ecce46f44c5406ec Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 9 Dec 2021 22:11:56 +0100 Subject: scsi: hpsa: Remove an unused variable in hpsa_update_scsi_devices() 'lunzerobits' is unused. Remove it. This a left over of commit 2d62a33e05d4 ("hpsa: eliminate fake lun0 enclosures") Link: https://lore.kernel.org/r/9f80ea569867b5f7ae1e0f99d656e5a8bacad34e.1639084205.git.christophe.jaillet@wanadoo.fr Signed-off-by: Christophe JAILLET Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cdf3328cc065..a47bcce3c9c7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4354,7 +4354,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) int i, ndevs_to_allocate; int raid_ctlr_position; bool physical_device; - DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); currentsd = kcalloc(HPSA_MAX_DEVICES, sizeof(*currentsd), GFP_KERNEL); physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL); @@ -4368,7 +4367,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) dev_err(&h->pdev->dev, "out of memory\n"); goto out; } - memset(lunzerobits, 0, sizeof(lunzerobits)); h->drv_req_rescan = 0; /* cancel scheduled rescan - we're doing it. */ -- cgit v1.2.3 From baea0e833f7612483dcb2351240da19f0d0bc011 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 14 Dec 2021 12:11:39 +0100 Subject: scsi: qla2xxx: Synchronize rport dev_loss_tmo setting Currently, the dev_loss_tmo setting is only ever used for SCSI devices. This patch reshuffles initialisation such that the SCSI remote ports are registered before the NVMe ones, allowing the dev_loss_tmo setting to be synchronized between SCSI and NVMe. Link: https://lore.kernel.org/r/20211214111139.52503-1-dwagner@suse.de Reviewed-by: Himanshu Madhani Signed-off-by: Hannes Reinecke Signed-off-by: Daniel Wagner Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 6 ++++++ drivers/scsi/qla2xxx/qla_init.c | 10 +++------- drivers/scsi/qla2xxx/qla_nvme.c | 5 ++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 032efb294ee5..db55737000ab 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -2700,7 +2700,13 @@ qla2x00_get_starget_port_id(struct scsi_target *starget) static inline void qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) { + fc_port_t *fcport = *(fc_port_t **)rport->dd_data; + rport->dev_loss_tmo = timeout ? timeout : 1; + + if (IS_ENABLED(CONFIG_NVME_FC) && fcport && fcport->nvme_remote_port) + nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, + rport->dev_loss_tmo); } static void diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 070b636802d0..1fe4966fc2f6 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5828,13 +5828,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_dfs_create_rport(vha, fcport); - if (NVME_TARGET(vha->hw, fcport)) { - qla_nvme_register_remote(vha, fcport); - qla2x00_set_fcport_disc_state(fcport, DSC_LOGIN_COMPLETE); - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - return; - } - qla24xx_update_fcport_fcp_prio(vha, fcport); switch (vha->host->active_mode) { @@ -5856,6 +5849,9 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) break; } + if (NVME_TARGET(vha->hw, fcport)) + qla_nvme_register_remote(vha, fcport); + qla2x00_set_fcport_state(fcport, FCS_ONLINE); if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) { diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 138ffdb5c92c..e22ec7cb65db 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -43,7 +43,7 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) req.port_name = wwn_to_u64(fcport->port_name); req.node_name = wwn_to_u64(fcport->node_name); req.port_role = 0; - req.dev_loss_tmo = 0; + req.dev_loss_tmo = fcport->dev_loss_tmo; if (fcport->nvme_prli_service_param & NVME_PRLI_SP_INITIATOR) req.port_role = FC_PORT_ROLE_NVME_INITIATOR; @@ -70,6 +70,9 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) return ret; } + nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, + fcport->dev_loss_tmo); + if (fcport->nvme_prli_service_param & NVME_PRLI_SP_SLER) ql_log(ql_log_info, vha, 0x212a, "PortID:%06x Supports SLER\n", req.port_id); -- cgit v1.2.3 From 99c66a8868e33522ebc6fd8a99e32f0d544a014f Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 14 Dec 2021 13:05:37 +0100 Subject: scsi: ufs: core: Fix deadlock issue in ufshcd_wait_for_doorbell_clr() Call shost_for_each_device() with holding host->host_lock will cause a deadlock situation, which will cause the system to stall (the log as follow). Fix this issue by using __shost_for_each_device() in ufshcd_pending_cmds(). stalls on CPUs/tasks: all trace: __switch_to+0x120/0x170 0xffff800011643998 ask dump for CPU 5: ask:kworker/u16:2 state:R running task stack: 0 pid: 80 ppid: 2 flags:0x0000000a orkqueue: events_unbound async_run_entry_fn all trace: __switch_to+0x120/0x170 0x0 ask dump for CPU 6: ask:kworker/u16:6 state:R running task stack: 0 pid: 164 ppid: 2 flags:0x0000000a orkqueue: events_unbound async_run_entry_fn all trace: __switch_to+0x120/0x170 0xffff54e7c4429f80 ask dump for CPU 7: ask:kworker/u16:4 state:R running task stack: 0 pid: 153 ppid: 2 flags:0x0000000a orkqueue: events_unbound async_run_entry_fn all trace: __switch_to+0x120/0x170 blk_mq_run_hw_queue+0x34/0x110 blk_mq_sched_insert_request+0xb0/0x120 blk_execute_rq_nowait+0x68/0x88 blk_execute_rq+0x4c/0xd8 __scsi_execute+0xec/0x1d0 scsi_vpd_inquiry+0x84/0xf0 scsi_get_vpd_buf+0x34/0xb8 scsi_attach_vpd+0x34/0x140 scsi_probe_and_add_lun+0xa6c/0xab8 __scsi_scan_target+0x438/0x4f8 scsi_scan_channel+0x6c/0xa8 scsi_scan_host_selected+0xf0/0x150 do_scsi_scan_host+0x88/0x90 scsi_scan_host+0x1b4/0x1d0 ufshcd_async_scan+0x248/0x310 async_run_entry_fn+0x30/0x178 process_one_work+0x1e8/0x368 worker_thread+0x40/0x478 kthread+0x174/0x180 ret_from_fork+0x10/0x20 Link: https://lore.kernel.org/r/20211214120537.531628-1-huobean@gmail.com Fixes: 8d077ede48c1 ("scsi: ufs: Optimize the command queueing code") Reported-by: YongQin Liu Reported-by: Amit Pundir Tested-by: John Stultz Tested-by: Bjorn Andersson Reviewed-by: Bjorn Andersson Co-developed-by: Bart Van Assche Signed-off-by: Bart Van Assche Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 47968f8d8fc4..1049e41abd5b 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1082,7 +1082,8 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba) struct scsi_device *sdev; u32 pending = 0; - shost_for_each_device(sdev, hba->host) + lockdep_assert_held(hba->host->host_lock); + __shost_for_each_device(sdev, hba->host) pending += sbitmap_weight(&sdev->budget_map); return pending; -- cgit v1.2.3 From efac162a4e4dc4cebcc658e02676821ca834b56c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 14 Dec 2021 17:36:05 +0100 Subject: scsi: efct: Don't pass GFP_DMA to dma_alloc_coherent() dma_alloc_coherent() ignores the zone specifiers so this is pointless and confusing. Link: https://lore.kernel.org/r/20211214163605.416288-1-hch@lst.de Reviewed-by: James Smart Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/elx/efct/efct_driver.c | 2 +- drivers/scsi/elx/efct/efct_hw.c | 10 +++++----- drivers/scsi/elx/efct/efct_io.c | 2 +- drivers/scsi/elx/libefc/efc_cmds.c | 4 ++-- drivers/scsi/elx/libefc/efc_els.c | 4 ++-- drivers/scsi/elx/libefc_sli/sli4.c | 14 +++++++------- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/elx/efct/efct_driver.c b/drivers/scsi/elx/efct/efct_driver.c index b2b61bc45f12..ae62fc3c9ee3 100644 --- a/drivers/scsi/elx/efct/efct_driver.c +++ b/drivers/scsi/elx/efct/efct_driver.c @@ -261,7 +261,7 @@ efct_firmware_write(struct efct *efct, const u8 *buf, size_t buf_len, dma.size = FW_WRITE_BUFSIZE; dma.virt = dma_alloc_coherent(&efct->pci->dev, - dma.size, &dma.phys, GFP_DMA); + dma.size, &dma.phys, GFP_KERNEL); if (!dma.virt) return -ENOMEM; diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c index ba8256b4c782..d4bb37960a3c 100644 --- a/drivers/scsi/elx/efct/efct_hw.c +++ b/drivers/scsi/elx/efct/efct_hw.c @@ -516,7 +516,7 @@ efct_hw_setup_io(struct efct_hw *hw) dma = &hw->xfer_rdy; dma->size = sizeof(struct fcp_txrdy) * hw->config.n_io; dma->virt = dma_alloc_coherent(&efct->pci->dev, - dma->size, &dma->phys, GFP_DMA); + dma->size, &dma->phys, GFP_KERNEL); if (!dma->virt) return -ENOMEM; } @@ -562,7 +562,7 @@ efct_hw_setup_io(struct efct_hw *hw) sizeof(struct sli4_sge); dma->virt = dma_alloc_coherent(&efct->pci->dev, dma->size, &dma->phys, - GFP_DMA); + GFP_KERNEL); if (!dma->virt) { efc_log_err(hw->os, "dma_alloc fail %d\n", i); memset(&io->def_sgl, 0, @@ -618,7 +618,7 @@ efct_hw_init_prereg_io(struct efct_hw *hw) memset(&req, 0, sizeof(struct efc_dma)); req.size = 32 + sgls_per_request * 16; req.virt = dma_alloc_coherent(&efct->pci->dev, req.size, &req.phys, - GFP_DMA); + GFP_KERNEL); if (!req.virt) { kfree(sgls); return -ENOMEM; @@ -1063,7 +1063,7 @@ efct_hw_init(struct efct_hw *hw) dma = &hw->loop_map; dma->size = SLI4_MIN_LOOP_MAP_BYTES; dma->virt = dma_alloc_coherent(&hw->os->pci->dev, dma->size, &dma->phys, - GFP_DMA); + GFP_KERNEL); if (!dma->virt) return -EIO; @@ -1192,7 +1192,7 @@ efct_hw_rx_buffer_alloc(struct efct_hw *hw, u32 rqindex, u32 count, prq->dma.virt = dma_alloc_coherent(&efct->pci->dev, prq->dma.size, &prq->dma.phys, - GFP_DMA); + GFP_KERNEL); if (!prq->dma.virt) { efc_log_err(hw->os, "DMA allocation failed\n"); kfree(rq_buf); diff --git a/drivers/scsi/elx/efct/efct_io.c b/drivers/scsi/elx/efct/efct_io.c index 71e21655916a..c3247b951a76 100644 --- a/drivers/scsi/elx/efct/efct_io.c +++ b/drivers/scsi/elx/efct/efct_io.c @@ -48,7 +48,7 @@ efct_io_pool_create(struct efct *efct, u32 num_sgl) io->rspbuf.size = SCSI_RSP_BUF_LENGTH; io->rspbuf.virt = dma_alloc_coherent(&efct->pci->dev, io->rspbuf.size, - &io->rspbuf.phys, GFP_DMA); + &io->rspbuf.phys, GFP_KERNEL); if (!io->rspbuf.virt) { efc_log_err(efct, "dma_alloc rspbuf failed\n"); efct_io_pool_free(io_pool); diff --git a/drivers/scsi/elx/libefc/efc_cmds.c b/drivers/scsi/elx/libefc/efc_cmds.c index f8665d48904a..da4ac8a4ce12 100644 --- a/drivers/scsi/elx/libefc/efc_cmds.c +++ b/drivers/scsi/elx/libefc/efc_cmds.c @@ -179,7 +179,7 @@ efc_nport_alloc_read_sparm64(struct efc *efc, struct efc_nport *nport) nport->dma.size = EFC_SPARAM_DMA_SZ; nport->dma.virt = dma_alloc_coherent(&efc->pci->dev, nport->dma.size, &nport->dma.phys, - GFP_DMA); + GFP_KERNEL); if (!nport->dma.virt) { efc_log_err(efc, "Failed to allocate DMA memory\n"); efc_nport_free_resources(nport, EFC_EVT_NPORT_ALLOC_FAIL, data); @@ -466,7 +466,7 @@ efc_cmd_domain_alloc(struct efc *efc, struct efc_domain *domain, u32 fcf) domain->dma.size = EFC_SPARAM_DMA_SZ; domain->dma.virt = dma_alloc_coherent(&efc->pci->dev, domain->dma.size, - &domain->dma.phys, GFP_DMA); + &domain->dma.phys, GFP_KERNEL); if (!domain->dma.virt) { efc_log_err(efc, "Failed to allocate DMA memory\n"); return -EIO; diff --git a/drivers/scsi/elx/libefc/efc_els.c b/drivers/scsi/elx/libefc/efc_els.c index 24db0accb256..7bb4f9aad2c8 100644 --- a/drivers/scsi/elx/libefc/efc_els.c +++ b/drivers/scsi/elx/libefc/efc_els.c @@ -71,7 +71,7 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen) /* now allocate DMA for request and response */ els->io.req.size = reqlen; els->io.req.virt = dma_alloc_coherent(&efc->pci->dev, els->io.req.size, - &els->io.req.phys, GFP_DMA); + &els->io.req.phys, GFP_KERNEL); if (!els->io.req.virt) { mempool_free(els, efc->els_io_pool); spin_unlock_irqrestore(&node->els_ios_lock, flags); @@ -80,7 +80,7 @@ efc_els_io_alloc_size(struct efc_node *node, u32 reqlen, u32 rsplen) els->io.rsp.size = rsplen; els->io.rsp.virt = dma_alloc_coherent(&efc->pci->dev, els->io.rsp.size, - &els->io.rsp.phys, GFP_DMA); + &els->io.rsp.phys, GFP_KERNEL); if (!els->io.rsp.virt) { dma_free_coherent(&efc->pci->dev, els->io.req.size, els->io.req.virt, els->io.req.phys); diff --git a/drivers/scsi/elx/libefc_sli/sli4.c b/drivers/scsi/elx/libefc_sli/sli4.c index 907d67aeac23..3ea57bd6fb0a 100644 --- a/drivers/scsi/elx/libefc_sli/sli4.c +++ b/drivers/scsi/elx/libefc_sli/sli4.c @@ -445,7 +445,7 @@ sli_cmd_rq_create_v2(struct sli4 *sli4, u32 num_rqs, dma->size = payload_size; dma->virt = dma_alloc_coherent(&sli4->pci->dev, dma->size, - &dma->phys, GFP_DMA); + &dma->phys, GFP_KERNEL); if (!dma->virt) return -EIO; @@ -508,7 +508,7 @@ __sli_queue_init(struct sli4 *sli4, struct sli4_queue *q, u32 qtype, q->dma.size = size * n_entries; q->dma.virt = dma_alloc_coherent(&sli4->pci->dev, q->dma.size, - &q->dma.phys, GFP_DMA); + &q->dma.phys, GFP_KERNEL); if (!q->dma.virt) { memset(&q->dma, 0, sizeof(struct efc_dma)); efc_log_err(sli4, "%s allocation failed\n", SLI4_QNAME[qtype]); @@ -849,7 +849,7 @@ static int sli_cmd_cq_set_create(struct sli4 *sli4, dma->size = payload_size; dma->virt = dma_alloc_coherent(&sli4->pci->dev, dma->size, - &dma->phys, GFP_DMA); + &dma->phys, GFP_KERNEL); if (!dma->virt) return -EIO; @@ -4413,7 +4413,7 @@ sli_get_ctrl_attributes(struct sli4 *sli4) psize = sizeof(struct sli4_rsp_cmn_get_cntl_addl_attributes); data.size = psize; data.virt = dma_alloc_coherent(&sli4->pci->dev, data.size, - &data.phys, GFP_DMA); + &data.phys, GFP_KERNEL); if (!data.virt) { memset(&data, 0, sizeof(struct efc_dma)); efc_log_err(sli4, "Failed to allocate memory for GET_CNTL_ADDL_ATTR\n"); @@ -4653,7 +4653,7 @@ sli_setup(struct sli4 *sli4, void *os, struct pci_dev *pdev, */ sli4->bmbx.size = SLI4_BMBX_SIZE + sizeof(struct sli4_mcqe); sli4->bmbx.virt = dma_alloc_coherent(&pdev->dev, sli4->bmbx.size, - &sli4->bmbx.phys, GFP_DMA); + &sli4->bmbx.phys, GFP_KERNEL); if (!sli4->bmbx.virt) { memset(&sli4->bmbx, 0, sizeof(struct efc_dma)); efc_log_err(sli4, "bootstrap mailbox allocation failed\n"); @@ -4674,7 +4674,7 @@ sli_setup(struct sli4 *sli4, void *os, struct pci_dev *pdev, sli4->vpd_data.virt = dma_alloc_coherent(&pdev->dev, sli4->vpd_data.size, &sli4->vpd_data.phys, - GFP_DMA); + GFP_KERNEL); if (!sli4->vpd_data.virt) { memset(&sli4->vpd_data, 0, sizeof(struct efc_dma)); /* Note that failure isn't fatal in this specific case */ @@ -5070,7 +5070,7 @@ sli_cmd_post_hdr_templates(struct sli4 *sli4, void *buf, struct efc_dma *dma, payload_dma->size = payload_size; payload_dma->virt = dma_alloc_coherent(&sli4->pci->dev, payload_dma->size, - &payload_dma->phys, GFP_DMA); + &payload_dma->phys, GFP_KERNEL); if (!payload_dma->virt) { memset(payload_dma, 0, sizeof(struct efc_dma)); efc_log_err(sli4, "mbox payload memory allocation fail\n"); -- cgit v1.2.3 From 0e4620856b89335426a17904933a92346ee4599d Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 15 Dec 2021 22:37:34 +0800 Subject: scsi: hisi_sas: Start delivery hisi_sas_task_exec() directly Currently we start delivery of commands to the DQ after returning from hisi_sas_task_exec() with success. Let's just start delivery directly in that function without having to check if some local variable is set. Link: https://lore.kernel.org/r/1639579061-179473-2-git-send-email-john.garry@huawei.com Reviewed-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 889c36fa9309..0137ce7c544e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -397,8 +397,7 @@ err_out_dif_dma_unmap: static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq **dq_pointer, - bool is_tmf, struct hisi_sas_tmf_task *tmf, - int *pass) + bool is_tmf, struct hisi_sas_tmf_task *tmf) { struct domain_device *device = task->dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); @@ -536,9 +535,12 @@ static int hisi_sas_task_prep(struct sas_task *task, task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); - ++(*pass); WRITE_ONCE(slot->ready, 1); + spin_lock(&dq->lock); + hisi_hba->hw->start_delivery(dq); + spin_unlock(&dq->lock); + return 0; err_out_dif_dma_unmap: @@ -556,7 +558,6 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, bool is_tmf, struct hisi_sas_tmf_task *tmf) { u32 rc; - u32 pass = 0; struct hisi_hba *hisi_hba; struct device *dev; struct domain_device *device = task->dev; @@ -589,16 +590,10 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, } /* protect task_prep and start_delivery sequence */ - rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf, &pass); + rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf); if (rc) dev_err(dev, "task exec: failed[%d]!\n", rc); - if (likely(pass)) { - spin_lock(&dq->lock); - hisi_hba->hw->start_delivery(dq); - spin_unlock(&dq->lock); - } - return rc; } -- cgit v1.2.3 From 934385a4fd5926650b20131bf3a435199a3d0af2 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 15 Dec 2021 22:37:35 +0800 Subject: scsi: hisi_sas: Make internal abort have no task proto For an internal abort, the task does not have a protocol, so set to none. This will make it easier to differentiate internal abort tasks in future. Link: https://lore.kernel.org/r/1639579061-179473-3-git-send-email-john.garry@huawei.com Reviewed-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 0137ce7c544e..b2299db01a80 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2125,7 +2125,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, return -ENOMEM; task->dev = device; - task->task_proto = device->tproto; + task->task_proto = SAS_PROTOCOL_NONE; task->task_done = hisi_sas_task_done; task->slow_task->timer.function = hisi_sas_tmf_timedout; task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT; -- cgit v1.2.3 From 08c61b5d902b70180b517e9f2616ad70b7a98dcf Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 15 Dec 2021 22:37:36 +0800 Subject: scsi: hisi_sas: Pass abort structure for internal abort To help factor out code in future, it's useful to know if we're executing an internal abort, so pass a pointer to the structure. The idea is that a NULL pointer means not an internal abort. Link: https://lore.kernel.org/r/1639579061-179473-4-git-send-email-john.garry@huawei.com Reviewed-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 5 +++++ drivers/scsi/hisi_sas/hisi_sas_main.c | 21 ++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index ed9419643235..07b473de9136 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -133,6 +133,11 @@ struct hisi_sas_rst { bool done; }; +struct hisi_sas_internal_abort { + unsigned int flag; + unsigned int tag; +}; + #define HISI_SAS_RST_WORK_INIT(r, c) \ { .hisi_hba = hisi_hba, \ .completion = &c, \ diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b2299db01a80..9bad59e77eae 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -265,11 +265,11 @@ static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, } static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, - struct hisi_sas_slot *slot, - int device_id, int abort_flag, int tag_to_abort) + struct hisi_sas_internal_abort *abort, + struct hisi_sas_slot *slot, int device_id) { hisi_hba->hw->prep_abort(hisi_hba, slot, - device_id, abort_flag, tag_to_abort); + device_id, abort->flag, abort->tag); } static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, @@ -2008,8 +2008,9 @@ static int hisi_sas_query_task(struct sas_task *task) static int hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, - struct sas_task *task, int abort_flag, - int task_tag, struct hisi_sas_dq *dq) + struct hisi_sas_internal_abort *abort, + struct sas_task *task, + struct hisi_sas_dq *dq) { struct domain_device *device = task->dev; struct hisi_sas_device *sas_dev = device->lldd_dev; @@ -2066,8 +2067,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, memset(hisi_sas_status_buf_addr_mem(slot), 0, sizeof(struct hisi_sas_err_record)); - hisi_sas_task_prep_abort(hisi_hba, slot, device_id, - abort_flag, task_tag); + hisi_sas_task_prep_abort(hisi_hba, abort, slot, device_id); spin_lock_irqsave(&task->task_state_lock, flags); task->task_state_flags |= SAS_TASK_AT_INITIATOR; @@ -2105,9 +2105,12 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, { struct sas_task *task; struct hisi_sas_device *sas_dev = device->lldd_dev; + struct hisi_sas_internal_abort abort = { + .flag = abort_flag, + .tag = tag, + }; struct device *dev = hisi_hba->dev; int res; - /* * The interface is not realized means this HW don't support internal * abort, or don't need to do internal abort. Then here, we return @@ -2132,7 +2135,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, add_timer(&task->slow_task->timer); res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, - task, abort_flag, tag, dq); + &abort, task, dq); if (res) { del_timer_sync(&task->slow_task->timer); dev_err(dev, "internal task abort: executing internal task failed: %d\n", -- cgit v1.2.3 From dc313f6b125b095d3d2683d94d5f69c8dc9bdc36 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 15 Dec 2021 22:37:37 +0800 Subject: scsi: hisi_sas: Factor out task prep and delivery code The task prep code is the same between the normal path (in hisi_sas_task_prep()) and the internal abort path, so factor is out into a common function. Link: https://lore.kernel.org/r/1639579061-179473-5-git-send-email-john.garry@huawei.com Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 281 +++++++++++++++------------------- 1 file changed, 124 insertions(+), 157 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 9bad59e77eae..8df1fd680eac 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -395,94 +395,20 @@ err_out_dif_dma_unmap: return rc; } -static int hisi_sas_task_prep(struct sas_task *task, - struct hisi_sas_dq **dq_pointer, - bool is_tmf, struct hisi_sas_tmf_task *tmf) +static +void hisi_sas_task_deliver(struct hisi_hba *hisi_hba, + struct hisi_sas_slot *slot, + struct hisi_sas_dq *dq, + struct hisi_sas_device *sas_dev, + struct hisi_sas_internal_abort *abort, + struct hisi_sas_tmf_task *tmf) { - struct domain_device *device = task->dev; - struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); - struct hisi_sas_device *sas_dev = device->lldd_dev; - struct hisi_sas_port *port; - struct hisi_sas_slot *slot; - struct hisi_sas_cmd_hdr *cmd_hdr_base; - struct asd_sas_port *sas_port = device->port; - struct device *dev = hisi_hba->dev; - int dlvry_queue_slot, dlvry_queue, rc, slot_idx; - int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; - struct scsi_cmnd *scmd = NULL; - struct hisi_sas_dq *dq; + struct hisi_sas_cmd_hdr *cmd_hdr_base; + int dlvry_queue_slot, dlvry_queue; + struct sas_task *task = slot->task; unsigned long flags; int wr_q_index; - if (DEV_IS_GONE(sas_dev)) { - if (sas_dev) - dev_info(dev, "task prep: device %d not ready\n", - sas_dev->device_id); - else - dev_info(dev, "task prep: device %016llx not ready\n", - SAS_ADDR(device->sas_addr)); - - return -ECOMM; - } - - if (task->uldd_task) { - struct ata_queued_cmd *qc; - - if (dev_is_sata(device)) { - qc = task->uldd_task; - scmd = qc->scsicmd; - } else { - scmd = task->uldd_task; - } - } - - if (scmd) { - unsigned int dq_index; - u32 blk_tag; - - blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); - dq_index = blk_mq_unique_tag_to_hwq(blk_tag); - *dq_pointer = dq = &hisi_hba->dq[dq_index]; - } else { - struct Scsi_Host *shost = hisi_hba->shost; - struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; - int queue = qmap->mq_map[raw_smp_processor_id()]; - - *dq_pointer = dq = &hisi_hba->dq[queue]; - } - - port = to_hisi_sas_port(sas_port); - if (port && !port->port_attached) { - dev_info(dev, "task prep: %s port%d not attach device\n", - (dev_is_sata(device)) ? - "SATA/STP" : "SAS", - device->port->id); - - return -ECOMM; - } - - rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, - &n_elem_req); - if (rc < 0) - goto prep_out; - - if (!sas_protocol_ata(task->task_proto)) { - rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task); - if (rc < 0) - goto err_out_dma_unmap; - } - - if (hisi_hba->hw->slot_index_alloc) - rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); - else - rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); - - if (rc < 0) - goto err_out_dif_dma_unmap; - - slot_idx = rc; - slot = &hisi_hba->slot_info[slot_idx]; - spin_lock(&dq->lock); wr_q_index = dq->wr_point; dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; @@ -496,16 +422,13 @@ static int hisi_sas_task_prep(struct sas_task *task, dlvry_queue_slot = wr_q_index; slot->device_id = sas_dev->device_id; - slot->n_elem = n_elem; - slot->n_elem_dif = n_elem_dif; slot->dlvry_queue = dlvry_queue; slot->dlvry_queue_slot = dlvry_queue_slot; cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; - slot->task = task; - slot->port = port; + slot->tmf = tmf; - slot->is_internal = is_tmf; + slot->is_internal = tmf; task->lldd_task = slot; memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); @@ -525,8 +448,14 @@ static int hisi_sas_task_prep(struct sas_task *task, case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: hisi_sas_task_prep_ata(hisi_hba, slot); break; + case SAS_PROTOCOL_NONE: + if (abort) { + hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id); + break; + } + fallthrough; default: - dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n", + dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n", task->task_proto); break; } @@ -540,29 +469,22 @@ static int hisi_sas_task_prep(struct sas_task *task, spin_lock(&dq->lock); hisi_hba->hw->start_delivery(dq); spin_unlock(&dq->lock); - - return 0; - -err_out_dif_dma_unmap: - if (!sas_protocol_ata(task->task_proto)) - hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif); -err_out_dma_unmap: - hisi_sas_dma_unmap(hisi_hba, task, n_elem, - n_elem_req); -prep_out: - dev_err(dev, "task prep: failed[%d]!\n", rc); - return rc; } static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, - bool is_tmf, struct hisi_sas_tmf_task *tmf) + struct hisi_sas_tmf_task *tmf) { - u32 rc; - struct hisi_hba *hisi_hba; - struct device *dev; + int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; struct domain_device *device = task->dev; struct asd_sas_port *sas_port = device->port; + struct hisi_sas_device *sas_dev = device->lldd_dev; + struct scsi_cmnd *scmd = NULL; struct hisi_sas_dq *dq = NULL; + struct hisi_sas_port *port; + struct hisi_hba *hisi_hba; + struct hisi_sas_slot *slot; + struct device *dev; + int rc; if (!sas_port) { struct task_status_struct *ts = &task->task_status; @@ -589,11 +511,94 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, up(&hisi_hba->sem); } + if (DEV_IS_GONE(sas_dev)) { + if (sas_dev) + dev_info(dev, "task prep: device %d not ready\n", + sas_dev->device_id); + else + dev_info(dev, "task prep: device %016llx not ready\n", + SAS_ADDR(device->sas_addr)); + + return -ECOMM; + } + + if (task->uldd_task) { + struct ata_queued_cmd *qc; + + if (dev_is_sata(device)) { + qc = task->uldd_task; + scmd = qc->scsicmd; + } else { + scmd = task->uldd_task; + } + } + + if (scmd) { + unsigned int dq_index; + u32 blk_tag; + + blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd)); + dq_index = blk_mq_unique_tag_to_hwq(blk_tag); + dq = &hisi_hba->dq[dq_index]; + } else { + struct Scsi_Host *shost = hisi_hba->shost; + struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; + int queue = qmap->mq_map[raw_smp_processor_id()]; + + dq = &hisi_hba->dq[queue]; + } + + port = to_hisi_sas_port(sas_port); + if (port && !port->port_attached) { + dev_info(dev, "task prep: %s port%d not attach device\n", + (dev_is_sata(device)) ? + "SATA/STP" : "SAS", + device->port->id); + + return -ECOMM; + } + + rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, + &n_elem_req); + if (rc < 0) + goto prep_out; + + if (!sas_protocol_ata(task->task_proto)) { + rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task); + if (rc < 0) + goto err_out_dma_unmap; + } + + if (hisi_hba->hw->slot_index_alloc) + rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); + else + rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); + + if (rc < 0) + goto err_out_dif_dma_unmap; + + slot = &hisi_hba->slot_info[rc]; + slot->n_elem = n_elem; + slot->n_elem_dif = n_elem_dif; + slot->task = task; + slot->port = port; + + slot->tmf = tmf; + slot->is_internal = tmf; + /* protect task_prep and start_delivery sequence */ - rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf); - if (rc) - dev_err(dev, "task exec: failed[%d]!\n", rc); + hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL, tmf); + return 0; + +err_out_dif_dma_unmap: + if (!sas_protocol_ata(task->task_proto)) + hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif); +err_out_dma_unmap: + hisi_sas_dma_unmap(hisi_hba, task, n_elem, + n_elem_req); +prep_out: + dev_err(dev, "task exec: failed[%d]!\n", rc); return rc; } @@ -1092,7 +1097,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) { - return hisi_sas_task_exec(task, gfp_flags, 0, NULL); + return hisi_sas_task_exec(task, gfp_flags, NULL); } static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, @@ -1246,8 +1251,7 @@ static int hisi_sas_exec_internal_tmf_task(struct domain_device *device, task->slow_task->timer.expires = jiffies + TASK_TIMEOUT; add_timer(&task->slow_task->timer); - res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf); - + res = hisi_sas_task_exec(task, GFP_KERNEL, tmf); if (res) { del_timer_sync(&task->slow_task->timer); dev_err(dev, "abort tmf: executing internal task failed: %d\n", @@ -2016,12 +2020,9 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, struct hisi_sas_device *sas_dev = device->lldd_dev; struct device *dev = hisi_hba->dev; struct hisi_sas_port *port; - struct hisi_sas_slot *slot; struct asd_sas_port *sas_port = device->port; - struct hisi_sas_cmd_hdr *cmd_hdr_base; - int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; - unsigned long flags; - int wr_q_index; + struct hisi_sas_slot *slot; + int slot_idx; if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) return -EINVAL; @@ -2032,58 +2033,24 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, port = to_hisi_sas_port(sas_port); /* simply get a slot and send abort command */ - rc = hisi_sas_slot_index_alloc(hisi_hba, NULL); - if (rc < 0) + slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL); + if (slot_idx < 0) goto err_out; - slot_idx = rc; slot = &hisi_hba->slot_info[slot_idx]; - - spin_lock(&dq->lock); - wr_q_index = dq->wr_point; - dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; - list_add_tail(&slot->delivery, &dq->list); - spin_unlock(&dq->lock); - spin_lock(&sas_dev->lock); - list_add_tail(&slot->entry, &sas_dev->list); - spin_unlock(&sas_dev->lock); - - dlvry_queue = dq->id; - dlvry_queue_slot = wr_q_index; - - slot->device_id = sas_dev->device_id; - slot->n_elem = n_elem; - slot->dlvry_queue = dlvry_queue; - slot->dlvry_queue_slot = dlvry_queue_slot; - cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; - slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; + slot->n_elem = 0; slot->task = task; slot->port = port; slot->is_internal = true; - task->lldd_task = slot; - memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); - memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ); - memset(hisi_sas_status_buf_addr_mem(slot), 0, - sizeof(struct hisi_sas_err_record)); - - hisi_sas_task_prep_abort(hisi_hba, abort, slot, device_id); - - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock_irqrestore(&task->task_state_lock, flags); - WRITE_ONCE(slot->ready, 1); - /* send abort command to the chip */ - spin_lock(&dq->lock); - hisi_hba->hw->start_delivery(dq); - spin_unlock(&dq->lock); + hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort, NULL); return 0; err_out: - dev_err(dev, "internal abort task prep: failed[%d]!\n", rc); + dev_err(dev, "internal abort task prep: failed[%d]!\n", slot_idx); - return rc; + return slot_idx; } /** -- cgit v1.2.3 From 20c634932ae8978435645b466c99b3fc1a80545a Mon Sep 17 00:00:00 2001 From: Qi Liu Date: Wed, 15 Dec 2021 22:37:38 +0800 Subject: scsi: hisi_sas: Prevent parallel controller reset and control phy command A user may issue a control phy command from sysfs at any time, even if the controller is resetting. If a phy is disabled by hardreset/linkreset command before calling get_phys_state() in the reset path, the saved phy state may be incorrect. To avoid incorrectly recording the phy state, use hisi_hba.sem to ensure that the controller reset may not run at the same time as when the phy control function is running. Link: https://lore.kernel.org/r/1639579061-179473-6-git-send-email-john.garry@huawei.com Signed-off-by: Qi Liu Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 8df1fd680eac..977911580d8f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1148,6 +1148,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, u8 sts = phy->phy_attached; int ret = 0; + down(&hisi_hba->sem); phy->reset_completion = &completion; switch (func) { @@ -1191,6 +1192,7 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, out: phy->reset_completion = NULL; + up(&hisi_hba->sem); return ret; } -- cgit v1.2.3 From 16775db613c2bdea09705dcb876942c0641a1098 Mon Sep 17 00:00:00 2001 From: Qi Liu Date: Wed, 15 Dec 2021 22:37:39 +0800 Subject: scsi: hisi_sas: Prevent parallel FLR and controller reset If we issue a controller reset command during executing a FLR a hung task may be found: Call trace: __switch_to+0x158/0x1cc __schedule+0x2e8/0x85c schedule+0x7c/0x110 schedule_timeout+0x190/0x1cc __down+0x7c/0xd4 down+0x5c/0x7c hisi_sas_task_exec+0x510/0x680 [hisi_sas_main] hisi_sas_queue_command+0x24/0x30 [hisi_sas_main] smp_execute_task_sg+0xf4/0x23c [libsas] sas_smp_phy_control+0x110/0x1e0 [libsas] transport_sas_phy_reset+0xc8/0x190 [libsas] phy_reset_work+0x2c/0x40 [libsas] process_one_work+0x1dc/0x48c worker_thread+0x15c/0x464 kthread+0x160/0x170 ret_from_fork+0x10/0x18 This is a race condition which occurs when the FLR completes first. Here the host HISI_SAS_RESETTING_BIT flag out gets of sync as HISI_SAS_RESETTING_BIT is not always cleared with the hisi_hba.sem held, so now only set/unset HISI_SAS_RESETTING_BIT under hisi_hba.sem . Link: https://lore.kernel.org/r/1639579061-179473-7-git-send-email-john.garry@huawei.com Signed-off-by: Qi Liu Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 +++++--- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 977911580d8f..0e14f90dbb1e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1574,7 +1574,6 @@ void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba) { struct Scsi_Host *shost = hisi_hba->shost; - down(&hisi_hba->sem); hisi_hba->phy_state = hisi_hba->hw->get_phys_state(hisi_hba); scsi_block_requests(shost); @@ -1599,9 +1598,9 @@ void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba) if (hisi_hba->reject_stp_links_msk) hisi_sas_terminate_stp_reject(hisi_hba); hisi_sas_reset_init_all_devices(hisi_hba); - up(&hisi_hba->sem); scsi_unblock_requests(shost); clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); + up(&hisi_hba->sem); hisi_sas_rescan_topology(hisi_hba, hisi_hba->phy_state); } @@ -1612,8 +1611,11 @@ static int hisi_sas_controller_prereset(struct hisi_hba *hisi_hba) if (!hisi_hba->hw->soft_reset) return -1; - if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) + down(&hisi_hba->sem); + if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { + up(&hisi_hba->sem); return -1; + } if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) hisi_hba->hw->debugfs_snapshot_regs(hisi_hba); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 0ef6c21bf081..11a44d9dd9b2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4848,6 +4848,7 @@ static void hisi_sas_reset_prepare_v3_hw(struct pci_dev *pdev) int rc; dev_info(dev, "FLR prepare\n"); + down(&hisi_hba->sem); set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); hisi_sas_controller_reset_prepare(hisi_hba); -- cgit v1.2.3 From 37310bad7fa645b21653fd7f13cb6b376d80c919 Mon Sep 17 00:00:00 2001 From: Qi Liu Date: Wed, 15 Dec 2021 22:37:40 +0800 Subject: scsi: hisi_sas: Fix phyup timeout on FPGA The OOB interrupt and phyup interrupt handlers may run out-of-order in high CPU usage scenarios. Since the hisi_sas_phy.timer is added in hisi_sas_phy_oob_ready() and disarmed in phy_up_v3_hw(), this out-of-order execution will cause hisi_sas_phy.timer timeout to trigger. To solve, protect hisi_sas_phy.timer and .attached with a lock, and ensure that the timer won't be added after phyup handler completes. Link: https://lore.kernel.org/r/1639579061-179473-8-git-send-email-john.garry@huawei.com Signed-off-by: Qi Liu Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 18 +++++++++++++----- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 ++++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 0e14f90dbb1e..66e63a336770 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -909,10 +909,14 @@ void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no) { struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct device *dev = hisi_hba->dev; + unsigned long flags; dev_dbg(dev, "phy%d OOB ready\n", phy_no); - if (phy->phy_attached) + spin_lock_irqsave(&phy->lock, flags); + if (phy->phy_attached) { + spin_unlock_irqrestore(&phy->lock, flags); return; + } if (!timer_pending(&phy->timer)) { if (phy->wait_phyup_cnt < HISI_SAS_WAIT_PHYUP_RETRIES) { @@ -920,13 +924,17 @@ void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no) phy->timer.expires = jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT; add_timer(&phy->timer); - } else { - dev_warn(dev, "phy%d failed to come up %d times, giving up\n", - phy_no, phy->wait_phyup_cnt); - phy->wait_phyup_cnt = 0; + spin_unlock_irqrestore(&phy->lock, flags); + return; } + + dev_warn(dev, "phy%d failed to come up %d times, giving up\n", + phy_no, phy->wait_phyup_cnt); + phy->wait_phyup_cnt = 0; } + spin_unlock_irqrestore(&phy->lock, flags); } + EXPORT_SYMBOL_GPL(hisi_sas_phy_oob_ready); static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 11a44d9dd9b2..0239e2b4b84f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1484,7 +1484,6 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) struct asd_sas_phy *sas_phy = &phy->sas_phy; struct device *dev = hisi_hba->dev; - del_timer(&phy->timer); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA); @@ -1561,9 +1560,16 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) } phy->port_id = port_id; - phy->phy_attached = 1; + hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); + res = IRQ_HANDLED; + + spin_lock(&phy->lock); + /* Delete timer and set phy_attached atomically */ + del_timer(&phy->timer); + phy->phy_attached = 1; + spin_unlock(&phy->lock); end: if (phy->reset_completion) complete(phy->reset_completion); -- cgit v1.2.3 From 4be6181fea1dbfd21a8d73f69d87a6cae2d3023d Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 15 Dec 2021 22:37:41 +0800 Subject: scsi: libsas: Decode SAM status and host byte codes Value 0 is used for SAM status and libsas exec_status bytes codes in sas_end_task() - use defined macros instead. In addition, change to proper enum types. Also replace SAM_STAT_CHECK_CONDITION with SAS_SAM_STAT_CHECK_CONDITION, the former being a proper member of enum exec_status. Link: https://lore.kernel.org/r/1639579061-179473-9-git-send-email-john.garry@huawei.com Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_scsi_host.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index d337fdf1b9ca..fb19e739a39c 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -37,7 +37,8 @@ static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task) { struct task_status_struct *ts = &task->task_status; - int hs = 0, stat = 0; + enum scsi_host_status hs = DID_OK; + enum exec_status stat = SAS_SAM_STAT_GOOD; if (ts->resp == SAS_TASK_UNDELIVERED) { /* transport error */ @@ -82,10 +83,10 @@ static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task) case SAS_ABORTED_TASK: hs = DID_ABORT; break; - case SAM_STAT_CHECK_CONDITION: + case SAS_SAM_STAT_CHECK_CONDITION: memcpy(sc->sense_buffer, ts->buf, min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); - stat = SAM_STAT_CHECK_CONDITION; + stat = SAS_SAM_STAT_CHECK_CONDITION; break; default: stat = ts->stat; -- cgit v1.2.3 From fbefe22811c3140a686e407e114789ebf328a9a2 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 20 Dec 2021 19:21:24 +0800 Subject: scsi: libsas: Don't always drain event workqueue for HA resume For the hisi_sas driver, if a directly attached disk is removed during suspend, a hang will occur in the resume process: The background is that in commit 16fd4a7c5917 ("scsi: hisi_sas: Add device link between SCSI devices and hisi_hba"), it is ensured that the HBA device cannot be runtime suspended when any SCSI device associated is active. Other drivers which use libsas don't worry about this as none support runtime suspend. The mentioned hang occurs when an disk is removed during suspend. In the removal process - from PHYE_RESUME_TIMEOUT event processing - we call into scsi_remove_device(), which is being processed in the HA event workqueue. Here we wait for all suppliers of the SCSI device to resume, which includes the HBA device (from the above commit). However the HBA device cannot resume, as it is waiting for the PHYE_RESUME_TIMEOUT to be processed (from calling sas_resume_ha() -> sas_drain_work()). This is the deadlock. There does not appear to be any need for the sas_drain_work() to be called at all in sas_resume_ha() as it is not syncing against anything, so allow LLDDs to avoid this by providing a variant of sas_resume_ha() which does "sync", i.e. doesn't drain the event workqueue. Link: https://lore.kernel.org/r/1639999298-244569-2-git-send-email-chenxiang66@hisilicon.com Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 +++++++++- drivers/scsi/libsas/sas_init.c | 17 +++++++++++++++-- include/scsi/libsas.h | 1 + 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 0239e2b4b84f..63059fb6d9ec 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4950,7 +4950,15 @@ static int _resume_v3_hw(struct device *device) return rc; } phys_init_v3_hw(hisi_hba); - sas_resume_ha(sha); + + /* + * If a directly-attached disk is removed during suspend, a deadlock + * may occur, as the PHYE_RESUME_TIMEOUT processing will require the + * hisi_hba->device to be active, which can only happen when resume + * completes. So don't wait for the HA event workqueue to drain upon + * resume. + */ + sas_resume_ha_no_sync(sha); clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); return 0; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index b640e09af6a4..43509d139241 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -387,7 +387,7 @@ static int phys_suspended(struct sas_ha_struct *ha) return rc; } -void sas_resume_ha(struct sas_ha_struct *ha) +static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) { const unsigned long tmo = msecs_to_jiffies(25000); int i; @@ -417,10 +417,23 @@ void sas_resume_ha(struct sas_ha_struct *ha) * flush out disks that did not return */ scsi_unblock_requests(ha->core.shost); - sas_drain_work(ha); + if (drain) + sas_drain_work(ha); +} + +void sas_resume_ha(struct sas_ha_struct *ha) +{ + _sas_resume_ha(ha, true); } EXPORT_SYMBOL(sas_resume_ha); +/* A no-sync variant, which does not call sas_drain_ha(). */ +void sas_resume_ha_no_sync(struct sas_ha_struct *ha) +{ + _sas_resume_ha(ha, false); +} +EXPORT_SYMBOL(sas_resume_ha_no_sync); + void sas_suspend_ha(struct sas_ha_struct *ha) { int i; diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 79e4903bd414..a795a2d9e5b1 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -660,6 +660,7 @@ extern int sas_register_ha(struct sas_ha_struct *); extern int sas_unregister_ha(struct sas_ha_struct *); extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha); extern void sas_resume_ha(struct sas_ha_struct *sas_ha); +extern void sas_resume_ha_no_sync(struct sas_ha_struct *sas_ha); extern void sas_suspend_ha(struct sas_ha_struct *sas_ha); int sas_set_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates); -- cgit v1.2.3 From 6cc739087784160eff296c7fbd7a95b209f44ba5 Mon Sep 17 00:00:00 2001 From: John Garry Date: Mon, 20 Dec 2021 19:21:25 +0800 Subject: scsi: Revert "scsi: hisi_sas: Filter out new PHY up events during suspend" This reverts commit b14a37e011d829404c29a5ae17849d7efb034893. In that commit, we had to filter out phy-up events during suspend, as it work cause a deadlock between processing the phyup event and the resume HA function try to drain the HA event workqueue to complete the resume process. Now that we no longer try to drain the HA event queue during the HA resume processor, the deadlock would not occur, so remove the special handling for it. Link: https://lore.kernel.org/r/1639999298-244569-3-git-send-email-chenxiang66@hisilicon.com Signed-off-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 66e63a336770..ad64ccd41420 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -611,12 +611,6 @@ static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no, if (!phy->phy_attached) return; - if (test_bit(HISI_SAS_PM_BIT, &hisi_hba->flags) && - !sas_phy->suspended) { - dev_warn(hisi_hba->dev, "phy%d during suspend filtered out\n", phy_no); - return; - } - sas_notify_phy_event(sas_phy, PHYE_OOB_DONE, gfp_flags); if (sas_phy->phy) { -- cgit v1.2.3 From 6e1fcab00a23f7fe9f4fe9704905a790efa1eeab Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 20 Dec 2021 19:21:26 +0800 Subject: scsi: block: pm: Always set request queue runtime active in blk_post_runtime_resume() John Garry reported a deadlock that occurs when trying to access a runtime-suspended SATA device. For obscure reasons, the rescan procedure causes the link to be hard-reset, which disconnects the device. The rescan tries to carry out a runtime resume when accessing the device. scsi_rescan_device() holds the SCSI device lock and won't release it until it can put commands onto the device's block queue. This can't happen until the queue is successfully runtime-resumed or the device is unregistered. But the runtime resume fails because the device is disconnected, and __scsi_remove_device() can't do the unregistration because it can't get the device lock. The best way to resolve this deadlock appears to be to allow the block queue to start running again even after an unsuccessful runtime resume. The idea is that the driver or the SCSI error handler will need to be able to use the queue to resolve the runtime resume failure. This patch removes the err argument to blk_post_runtime_resume() and makes the routine act as though the resume was successful always. This fixes the deadlock. Link: https://lore.kernel.org/r/1639999298-244569-4-git-send-email-chenxiang66@hisilicon.com Fixes: e27829dc92e5 ("scsi: serialize ->rescan against ->remove") Reported-and-tested-by: John Garry Reviewed-by: Bart Van Assche Signed-off-by: Alan Stern Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- block/blk-pm.c | 22 +++++++--------------- drivers/scsi/scsi_pm.c | 2 +- include/linux/blk-pm.h | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/block/blk-pm.c b/block/blk-pm.c index 17bd020268d4..2dad62cc1572 100644 --- a/block/blk-pm.c +++ b/block/blk-pm.c @@ -163,27 +163,19 @@ EXPORT_SYMBOL(blk_pre_runtime_resume); /** * blk_post_runtime_resume - Post runtime resume processing * @q: the queue of the device - * @err: return value of the device's runtime_resume function * * Description: - * Update the queue's runtime status according to the return value of the - * device's runtime_resume function. If the resume was successful, call - * blk_set_runtime_active() to do the real work of restarting the queue. + * For historical reasons, this routine merely calls blk_set_runtime_active() + * to do the real work of restarting the queue. It does this regardless of + * whether the device's runtime-resume succeeded; even if it failed the + * driver or error handler will need to communicate with the device. * * This function should be called near the end of the device's * runtime_resume callback. */ -void blk_post_runtime_resume(struct request_queue *q, int err) +void blk_post_runtime_resume(struct request_queue *q) { - if (!q->dev) - return; - if (!err) { - blk_set_runtime_active(q); - } else { - spin_lock_irq(&q->queue_lock); - q->rpm_status = RPM_SUSPENDED; - spin_unlock_irq(&q->queue_lock); - } + blk_set_runtime_active(q); } EXPORT_SYMBOL(blk_post_runtime_resume); @@ -201,7 +193,7 @@ EXPORT_SYMBOL(blk_post_runtime_resume); * runtime PM status and re-enable peeking requests from the queue. It * should be called before first request is added to the queue. * - * This function is also called by blk_post_runtime_resume() for successful + * This function is also called by blk_post_runtime_resume() for * runtime resumes. It does everything necessary to restart the queue. */ void blk_set_runtime_active(struct request_queue *q) diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 0e841e8761c5..d581613d87c7 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -180,7 +180,7 @@ static int sdev_runtime_resume(struct device *dev) blk_pre_runtime_resume(sdev->request_queue); if (pm && pm->runtime_resume) err = pm->runtime_resume(dev); - blk_post_runtime_resume(sdev->request_queue, err); + blk_post_runtime_resume(sdev->request_queue); return err; } diff --git a/include/linux/blk-pm.h b/include/linux/blk-pm.h index b80c65aba249..2580e05a8ab6 100644 --- a/include/linux/blk-pm.h +++ b/include/linux/blk-pm.h @@ -14,7 +14,7 @@ extern void blk_pm_runtime_init(struct request_queue *q, struct device *dev); extern int blk_pre_runtime_suspend(struct request_queue *q); extern void blk_post_runtime_suspend(struct request_queue *q, int err); extern void blk_pre_runtime_resume(struct request_queue *q); -extern void blk_post_runtime_resume(struct request_queue *q, int err); +extern void blk_post_runtime_resume(struct request_queue *q); extern void blk_set_runtime_active(struct request_queue *q); #else static inline void blk_pm_runtime_init(struct request_queue *q, -- cgit v1.2.3 From 42159d3c8d879e8d5fc225733f0cedc8baf19002 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:27 +0800 Subject: scsi: libsas: Add spin_lock/unlock() to protect asd_sas_port->phy_list Most places that use asd_sas_port->phy_list in libsas are protected by spinlock asd_sas_port->phy_list_lock. However, there are still a few places which miss the lock. Add it in those places. Link: https://lore.kernel.org/r/1639999298-244569-5-git-send-email-chenxiang66@hisilicon.com Reviewed-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_event.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index f703115e7a25..af605620ea13 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -104,11 +104,15 @@ void sas_enable_revalidation(struct sas_ha_struct *ha) if (!test_and_clear_bit(ev, &d->pending)) continue; - if (list_empty(&port->phy_list)) + spin_lock(&port->phy_list_lock); + if (list_empty(&port->phy_list)) { + spin_unlock(&port->phy_list_lock); continue; + } sas_phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); + spin_unlock(&port->phy_list_lock); sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD, GFP_KERNEL); } -- cgit v1.2.3 From 29e2bac87421c613782ccb510c76c5efbecac0cf Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:28 +0800 Subject: scsi: hisi_sas: Fix some issues related to asd_sas_port->phy_list Most places that use asd_sas_port->phy_list are protected by spinlock asd_sas_port->phy_list_lock, however there are still some places which miss grabbing the lock. Add it in function hisi_sas_refresh_port_id() when accessing asd_sas_port->phy_list. This carries a risk that list mutates while at the same time dropping the lock in function hisi_sas_send_ata_reset_each_phy(). Read asd_sas_port->phy_mask instead of accessing asd_sas_port->phy_list to avoid this risk. Link: https://lore.kernel.org/r/1639999298-244569-6-git-send-email-chenxiang66@hisilicon.com Acked-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index ad64ccd41420..051092e294f7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1428,11 +1428,13 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) sas_port = device->port; port = to_hisi_sas_port(sas_port); + spin_lock(&sas_port->phy_list_lock); list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) if (state & BIT(sas_phy->id)) { phy = sas_phy->lldd_phy; break; } + spin_unlock(&sas_port->phy_list_lock); if (phy) { port->id = phy->port_id; @@ -1509,22 +1511,25 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, struct ata_link *link; u8 fis[20] = {0}; u32 state; + int i; state = hisi_hba->hw->get_phys_state(hisi_hba); - list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) { + for (i = 0; i < hisi_hba->n_phy; i++) { if (!(state & BIT(sas_phy->id))) continue; + if (!(sas_port->phy_mask & BIT(i))) + continue; ata_for_each_link(link, ap, EDGE) { int pmp = sata_srst_pmp(link); - tmf_task.phy_id = sas_phy->id; + tmf_task.phy_id = i; hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf_task); if (rc != TMF_RESP_FUNC_COMPLETE) { dev_err(dev, "phy%d ata reset failed rc=%d\n", - sas_phy->id, rc); + i, rc); break; } } -- cgit v1.2.3 From 133b688b2d03f7ae2a6c9d344f92c1949ec05a51 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:29 +0800 Subject: scsi: mvsas: Add spin_lock/unlock() to protect asd_sas_port->phy_list phy_list_lock is not held when using asd_sas_port->phy_list in the mvsas driver. Add spin_lock/unlock in those places. Link: https://lore.kernel.org/r/1639999298-244569-7-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_sas.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 31d1ea5a5dd2..1e52bc7febfa 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -67,8 +67,10 @@ static struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev) while (sha->sas_port[i]) { if (sha->sas_port[i] == dev->port) { + spin_lock(&sha->sas_port[i]->phy_list_lock); phy = container_of(sha->sas_port[i]->phy_list.next, struct asd_sas_phy, port_phy_el); + spin_unlock(&sha->sas_port[i]->phy_list_lock); j = 0; while (sha->sas_phy[j]) { if (sha->sas_phy[j] == phy) @@ -96,6 +98,8 @@ static int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) while (sha->sas_port[i]) { if (sha->sas_port[i] == dev->port) { struct asd_sas_phy *phy; + + spin_lock(&sha->sas_port[i]->phy_list_lock); list_for_each_entry(phy, &sha->sas_port[i]->phy_list, port_phy_el) { j = 0; @@ -109,6 +113,7 @@ static int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) num++; n++; } + spin_unlock(&sha->sas_port[i]->phy_list_lock); break; } i++; -- cgit v1.2.3 From e31e18128eb9dbcda8c169cb33421ae4813afa71 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:30 +0800 Subject: scsi: libsas: Insert PORTE_BROADCAST_RCVD event for resuming host If a new disk is inserted through an expander when the host was suspended, it will not necessarily be detected as the topology is not re-scanned during resume. To detect possible changes in topology during suspension, insert a PORTE_BROADCAST_RCVD event per port when resuming to trigger a revalidation. Link: https://lore.kernel.org/r/1639999298-244569-8-git-send-email-chenxiang66@hisilicon.com Reviewed-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_init.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 43509d139241..974c4a305ece 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -387,6 +387,30 @@ static int phys_suspended(struct sas_ha_struct *ha) return rc; } +static void sas_resume_insert_broadcast_ha(struct sas_ha_struct *ha) +{ + int i; + + for (i = 0; i < ha->num_phys; i++) { + struct asd_sas_port *port = ha->sas_port[i]; + struct domain_device *dev = port->port_dev; + + if (dev && dev_is_expander(dev->dev_type)) { + struct asd_sas_phy *first_phy; + + spin_lock(&port->phy_list_lock); + first_phy = list_first_entry_or_null( + &port->phy_list, struct asd_sas_phy, + port_phy_el); + spin_unlock(&port->phy_list_lock); + + if (first_phy) + sas_notify_port_event(first_phy, + PORTE_BROADCAST_RCVD, GFP_KERNEL); + } + } +} + static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) { const unsigned long tmo = msecs_to_jiffies(25000); @@ -419,6 +443,11 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) scsi_unblock_requests(ha->core.shost); if (drain) sas_drain_work(ha); + + /* send event PORTE_BROADCAST_RCVD to identify some new inserted + * disks for expander + */ + sas_resume_insert_broadcast_ha(ha); } void sas_resume_ha(struct sas_ha_struct *ha) -- cgit v1.2.3 From 97f4100939844a6381ba61b99d6d2b1f2fccb79f Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:31 +0800 Subject: scsi: hisi_sas: Add more logs for runtime suspend/resume Add some logs at the beginning and end of suspend/resume. Link: https://lore.kernel.org/r/1639999298-244569-9-git-send-email-chenxiang66@hisilicon.com Acked-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 63059fb6d9ec..6d7fde38fe02 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4904,6 +4904,8 @@ static int _suspend_v3_hw(struct device *device) if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) return -1; + dev_warn(dev, "entering suspend state\n"); + scsi_block_requests(shost); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); flush_workqueue(hisi_hba->wq); @@ -4919,11 +4921,11 @@ static int _suspend_v3_hw(struct device *device) hisi_sas_init_mem(hisi_hba); - dev_warn(dev, "entering suspend state\n"); - hisi_sas_release_tasks(hisi_hba); sas_suspend_ha(sha); + + dev_warn(dev, "end of suspending controller\n"); return 0; } @@ -4961,6 +4963,8 @@ static int _resume_v3_hw(struct device *device) sas_resume_ha_no_sync(sha); clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); + dev_warn(dev, "end of resuming controller\n"); + return 0; } -- cgit v1.2.3 From 0da7ca4c4fd95d70d473dc07488ad94ba3ee9b82 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:32 +0800 Subject: scsi: libsas: Resume host while sending SMP I/Os When sending SMP I/Os to the host we need to ensure that the host is not suspended and can process the commands. This is a better approach than replying on the host to resume itself to handle such commands. Use pm_runtime_get_sync() and pm_runtime_put_sync() calls for the host when executing SMP I/Os. Link: https://lore.kernel.org/r/1639999298-244569-10-git-send-email-chenxiang66@hisilicon.com Reviewed-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_expander.c | 3 +++ drivers/scsi/libsas/sas_internal.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index c2150a818423..6abce9dfc17b 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -58,7 +58,9 @@ static int smp_execute_task_sg(struct domain_device *dev, struct sas_task *task = NULL; struct sas_internal *i = to_sas_internal(dev->port->ha->core.shost->transportt); + struct sas_ha_struct *ha = dev->port->ha; + pm_runtime_get_sync(ha->dev); mutex_lock(&dev->ex_dev.cmd_mutex); for (retry = 0; retry < 3; retry++) { if (test_bit(SAS_DEV_GONE, &dev->state)) { @@ -131,6 +133,7 @@ static int smp_execute_task_sg(struct domain_device *dev, } } mutex_unlock(&dev->ex_dev.cmd_mutex); + pm_runtime_put_sync(ha->dev); BUG_ON(retry == 3 && task != NULL); sas_free_task(task); diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index d7a1fb5c10c6..ad9764a976c3 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef pr_fmt #undef pr_fmt -- cgit v1.2.3 From 4ea775abbb5c50c26edbf043d5a2ae7fde407f4a Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:33 +0800 Subject: scsi: libsas: Add flag SAS_HA_RESUMING Add a flag SAS_HA_RESUMING and use it to indicate the state of resuming the host controller. Link: https://lore.kernel.org/r/1639999298-244569-11-git-send-email-chenxiang66@hisilicon.com Reviewed-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_init.c | 2 ++ include/scsi/libsas.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 974c4a305ece..069e40fc8411 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -362,6 +362,7 @@ void sas_prep_resume_ha(struct sas_ha_struct *ha) int i; set_bit(SAS_HA_REGISTERED, &ha->state); + set_bit(SAS_HA_RESUMING, &ha->state); /* clear out any stale link events/data from the suspension path */ for (i = 0; i < ha->num_phys; i++) { @@ -443,6 +444,7 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) scsi_unblock_requests(ha->core.shost); if (drain) sas_drain_work(ha); + clear_bit(SAS_HA_RESUMING, &ha->state); /* send event PORTE_BROADCAST_RCVD to identify some new inserted * disks for expander diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index a795a2d9e5b1..698f2032807b 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -356,6 +356,7 @@ enum sas_ha_state { SAS_HA_DRAINING, SAS_HA_ATA_EH_ACTIVE, SAS_HA_FROZEN, + SAS_HA_RESUMING, }; struct sas_ha_struct { -- cgit v1.2.3 From 1bc35475c6bf6d078b3800e516978f37c1ecda36 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:34 +0800 Subject: scsi: libsas: Refactor sas_queue_deferred_work() In the second part of function __sas_drain_work(), deferred work is queued. This functionality is required other places so factor it out into the function sas_queue_deferred_work(). Link: https://lore.kernel.org/r/1639999298-244569-12-git-send-email-chenxiang66@hisilicon.com Reviewed-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_event.c | 25 ++++++++++++++----------- drivers/scsi/libsas/sas_internal.h | 1 + 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index af605620ea13..01e544ca518a 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -41,12 +41,23 @@ static int sas_queue_event(int event, struct sas_work *work, return rc; } - -void __sas_drain_work(struct sas_ha_struct *ha) +void sas_queue_deferred_work(struct sas_ha_struct *ha) { struct sas_work *sw, *_sw; int ret; + spin_lock_irq(&ha->lock); + list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { + list_del_init(&sw->drain_node); + ret = sas_queue_work(ha, sw); + if (ret != 1) + sas_free_event(to_asd_sas_event(&sw->work)); + } + spin_unlock_irq(&ha->lock); +} + +void __sas_drain_work(struct sas_ha_struct *ha) +{ set_bit(SAS_HA_DRAINING, &ha->state); /* flush submitters */ spin_lock_irq(&ha->lock); @@ -55,16 +66,8 @@ void __sas_drain_work(struct sas_ha_struct *ha) drain_workqueue(ha->event_q); drain_workqueue(ha->disco_q); - spin_lock_irq(&ha->lock); clear_bit(SAS_HA_DRAINING, &ha->state); - list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { - list_del_init(&sw->drain_node); - ret = sas_queue_work(ha, sw); - if (ret != 1) - sas_free_event(to_asd_sas_event(&sw->work)); - - } - spin_unlock_irq(&ha->lock); + sas_queue_deferred_work(ha); } int sas_drain_work(struct sas_ha_struct *ha) diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index ad9764a976c3..acd515c01861 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -57,6 +57,7 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha); void sas_disable_revalidation(struct sas_ha_struct *ha); void sas_enable_revalidation(struct sas_ha_struct *ha); +void sas_queue_deferred_work(struct sas_ha_struct *ha); void __sas_drain_work(struct sas_ha_struct *ha); void sas_deform_port(struct asd_sas_phy *phy, int gone); -- cgit v1.2.3 From bf19aea4607cb5f4a652ab70d8d8035a72a6b8da Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:35 +0800 Subject: scsi: libsas: Defer works of new phys during suspend During the processing of event PORT_BYTES_DMAED, the driver queues work DISCE_DISCOVER_DOMAIN and then flushes workqueue ha->disco_q. If a new phyup event occurs during resuming the controller, the work PORTE_BYTES_DMAED of new phy occurs before suspended phy's. The work DISCE_DISCOVER_DOMAIN of new phy requires an active SAS controller (it needs to resume SAS controller by function scsi_sysfs_add_sdev() and some other functions such as function add_device_link()). However, the activation of the SAS controller requires completion of work PORTE_BYTES_DMAED of suspended phys while it is blocked by new phy's work on ha->event_q. So there is a deadlock and it is released only after resume timeout. To solve the issue, defer works of new phys during suspend and queue those defer works after SAS controller becomes active. Link: https://lore.kernel.org/r/1639999298-244569-13-git-send-email-chenxiang66@hisilicon.com Reviewed-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_event.c | 24 ++++++++++++++++++++++++ drivers/scsi/libsas/sas_init.c | 1 + 2 files changed, 25 insertions(+) diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 01e544ca518a..626ef96b9348 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -139,6 +139,24 @@ static void sas_phy_event_worker(struct work_struct *work) sas_free_event(ev); } +/* defer works of new phys during suspend */ +static bool sas_defer_event(struct asd_sas_phy *phy, struct asd_sas_event *ev) +{ + struct sas_ha_struct *ha = phy->ha; + unsigned long flags; + bool deferred = false; + + spin_lock_irqsave(&ha->lock, flags); + if (test_bit(SAS_HA_RESUMING, &ha->state) && !phy->suspended) { + struct sas_work *sw = &ev->work; + + list_add_tail(&sw->drain_node, &ha->defer_q); + deferred = true; + } + spin_unlock_irqrestore(&ha->lock, flags); + return deferred; +} + int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, gfp_t gfp_flags) { @@ -154,6 +172,9 @@ int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event); + if (sas_defer_event(phy, ev)) + return 0; + ret = sas_queue_event(event, &ev->work, ha); if (ret != 1) sas_free_event(ev); @@ -177,6 +198,9 @@ int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event, INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event); + if (sas_defer_event(phy, ev)) + return 0; + ret = sas_queue_event(event, &ev->work, ha); if (ret != 1) sas_free_event(ev); diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 069e40fc8411..dc35f0f8eae3 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -446,6 +446,7 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) sas_drain_work(ha); clear_bit(SAS_HA_RESUMING, &ha->state); + sas_queue_deferred_work(ha); /* send event PORTE_BROADCAST_RCVD to identify some new inserted * disks for expander */ -- cgit v1.2.3 From ae9b69e85eb7ecb32ddce7c04a10a3c69ad60e52 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:36 +0800 Subject: scsi: hisi_sas: Keep controller active between ISR of phyup and the event being processed It is possible that controller may become suspended between processing a phyup interrupt and the event being processed by libsas. As such, we can't ensure the controller is active when processing the phyup event - this may cause the phyup event to be lost or other issues. To avoid any possible issues, add pm_runtime_get_noresume() in phyup interrupt handler and pm_runtime_put_sync() in the work handler exit to ensure that we stay always active. Since we only want to call pm_runtime_get_noresume() for v3 hw, signal this will a new event, HISI_PHYE_PHY_UP_PM. Link: https://lore.kernel.org/r/1639999298-244569-14-git-send-email-chenxiang66@hisilicon.com Acked-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 22 ++++++++++++++++++++-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 4 +++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 07b473de9136..15a58c955516 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -158,6 +158,7 @@ enum hisi_sas_bit_err_type { enum hisi_sas_phy_event { HISI_PHYE_PHY_UP = 0U, HISI_PHYE_LINK_RESET, + HISI_PHYE_PHY_UP_PM, HISI_PHYES_NUM, }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 051092e294f7..f46f679fe825 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -846,10 +846,11 @@ int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time) } EXPORT_SYMBOL_GPL(hisi_sas_scan_finished); -static void hisi_sas_phyup_work(struct work_struct *work) +static void hisi_sas_phyup_work_common(struct work_struct *work, + enum hisi_sas_phy_event event) { struct hisi_sas_phy *phy = - container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP]); + container_of(work, typeof(*phy), works[event]); struct hisi_hba *hisi_hba = phy->hisi_hba; struct asd_sas_phy *sas_phy = &phy->sas_phy; int phy_no = sas_phy->id; @@ -860,6 +861,11 @@ static void hisi_sas_phyup_work(struct work_struct *work) hisi_sas_bytes_dmaed(hisi_hba, phy_no, GFP_KERNEL); } +static void hisi_sas_phyup_work(struct work_struct *work) +{ + hisi_sas_phyup_work_common(work, HISI_PHYE_PHY_UP); +} + static void hisi_sas_linkreset_work(struct work_struct *work) { struct hisi_sas_phy *phy = @@ -869,9 +875,21 @@ static void hisi_sas_linkreset_work(struct work_struct *work) hisi_sas_control_phy(sas_phy, PHY_FUNC_LINK_RESET, NULL); } +static void hisi_sas_phyup_pm_work(struct work_struct *work) +{ + struct hisi_sas_phy *phy = + container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP_PM]); + struct hisi_hba *hisi_hba = phy->hisi_hba; + struct device *dev = hisi_hba->dev; + + hisi_sas_phyup_work_common(work, HISI_PHYE_PHY_UP_PM); + pm_runtime_put_sync(dev); +} + static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = { [HISI_PHYE_PHY_UP] = hisi_sas_phyup_work, [HISI_PHYE_LINK_RESET] = hisi_sas_linkreset_work, + [HISI_PHYE_PHY_UP_PM] = hisi_sas_phyup_pm_work, }; bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 6d7fde38fe02..94eb48c93ab1 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1561,7 +1561,9 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) phy->port_id = port_id; - hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); + /* Call pm_runtime_put_sync() with pairs in hisi_sas_phyup_pm_work() */ + pm_runtime_get_noresume(dev); + hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP_PM); res = IRQ_HANDLED; -- cgit v1.2.3 From 307d9f49cce966c2ba969f58bd6227bc0092afaa Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:37 +0800 Subject: scsi: libsas: Keep host active while processing events Processing events such as PORTE_BROADCAST_RCVD may cause dependency issues for runtime power management support. Such a problem would be that handling a PORTE_BROADCAST_RCVD event requires that the host is resumed to send SMP commands. However, in resuming the host, the phyup events generated from re-enabling the phys are processed in the same workqueue as the original PORTE_BROADCAST_RCVD event. As such, the host will never finish resuming (as it waits for the phyup event processing), and then the PORTE_BROADCAST_RCVD event can't be processed as the SMP commands are blocked, and so we have a deadlock. Solve this problem by ensuring that libsas keeps the host active until completely finished phy or port events, such as PORTE_BYTES_DMAED. As such, we don't have to worry about resuming the host for processing individual SMP commands in this example. Link: https://lore.kernel.org/r/1639999298-244569-15-git-send-email-chenxiang66@hisilicon.com Reviewed-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/libsas/sas_event.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 626ef96b9348..3613b9b315bc 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -50,8 +50,10 @@ void sas_queue_deferred_work(struct sas_ha_struct *ha) list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { list_del_init(&sw->drain_node); ret = sas_queue_work(ha, sw); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(to_asd_sas_event(&sw->work)); + } } spin_unlock_irq(&ha->lock); } @@ -126,16 +128,22 @@ void sas_enable_revalidation(struct sas_ha_struct *ha) static void sas_port_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha; sas_port_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); } static void sas_phy_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha; sas_phy_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); } @@ -170,14 +178,19 @@ int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, if (!ev) return -ENOMEM; + /* Call pm_runtime_put() with pairs in sas_port_event_worker() */ + pm_runtime_get_noresume(ha->dev); + INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event); if (sas_defer_event(phy, ev)) return 0; ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(ev); + } return ret; } @@ -196,14 +209,19 @@ int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event, if (!ev) return -ENOMEM; + /* Call pm_runtime_put() with pairs in sas_phy_event_worker() */ + pm_runtime_get_noresume(ha->dev); + INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event); if (sas_defer_event(phy, ev)) return 0; ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(ev); + } return ret; } -- cgit v1.2.3 From b4cc09492263e07bad4fc4bf34fed3246fa95057 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Mon, 20 Dec 2021 19:21:38 +0800 Subject: scsi: hisi_sas: Use autosuspend for the host controller The controller may frequently enter and exit suspend for each I/O which we need to deal with. This is inefficient and may cause too much suspend and resume activity for the controller. To avoid this, use a default 5s autosuspend for the controller to stop frequently suspending and resuming. This value may still be modified via sysfs interfaces. Link: https://lore.kernel.org/r/1639999298-244569-16-git-send-email-chenxiang66@hisilicon.com Acked-by: John Garry Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 94eb48c93ab1..a45ef9a5e12e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4783,6 +4783,8 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) scsi_scan_host(shost); + pm_runtime_set_autosuspend_delay(dev, 5000); + pm_runtime_use_autosuspend(dev); /* * For the situation that there are ATA disks connected with SAS * controller, it additionally creates ata_port which will affect the -- cgit v1.2.3 From bc7806b39589f4960d7f583c2381edf2300be48c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Dec 2021 10:03:11 +0100 Subject: scsi: ch: Don't use GFP_DMA The allocated buffers are used as a command payload, for which the block layer and/or DMA API do the proper bounce buffering if needed. Link: https://lore.kernel.org/r/20211222090311.916624-1-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/ch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 27012908b586..a313949ba199 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -239,7 +239,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data) u_char *buffer; int result; - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if(!buffer) return -ENOMEM; @@ -297,7 +297,7 @@ ch_readconfig(scsi_changer *ch) int result,id,lun,i; u_int elem; - buffer = kzalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kzalloc(512, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -783,7 +783,7 @@ static long ch_ioctl(struct file *file, return -EINVAL; elem = ch->firsts[cge.cge_type] + cge.cge_unit; - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) return -ENOMEM; mutex_lock(&ch->lock); -- cgit v1.2.3 From d94d94969a4ba07a43d62429c60372320519c391 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Dec 2021 10:08:42 +0100 Subject: scsi: sr: Don't use GFP_DMA The allocated buffers are used as a command payload, for which the block layer and/or DMA API do the proper bounce buffering if needed. Link: https://lore.kernel.org/r/20211222090842.920724-1-hch@lst.de Reported-by: Baoquan He Reviewed-by: Baoquan He Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/sr.c | 2 +- drivers/scsi/sr_vendor.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 8e4af111c078..f5a2eed54345 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -856,7 +856,7 @@ static void get_capabilities(struct scsi_cd *cd) /* allocate transfer buffer */ - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) { sr_printk(KERN_ERR, cd, "out of memory.\n"); return; diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c index 1f988a1b9166..a61635326ae0 100644 --- a/drivers/scsi/sr_vendor.c +++ b/drivers/scsi/sr_vendor.c @@ -131,7 +131,7 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength) if (cd->vendor == VENDOR_TOSHIBA) density = (blocklength > 2048) ? 0x81 : 0x83; - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -179,7 +179,7 @@ int sr_cd_check(struct cdrom_device_info *cdi) if (cd->cdi.mask & CDC_MULTI_SESSION) return 0; - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) return -ENOMEM; -- cgit v1.2.3 From c981e9e0f823a8300569c04e59f78c5faa52ada5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Dec 2021 10:16:30 +0100 Subject: scsi: initio: Don't use GFP_DMA in initio_probe_one() The driver doesn't express DMA addressing limitation under 32-bits anywhere else, so remove the spurious GFP_DMA allocation. Link: https://lore.kernel.org/r/20211222091630.922788-1-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/initio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 9cdee38f5ba3..5f96ac47d7fd 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2847,7 +2847,8 @@ static int initio_probe_one(struct pci_dev *pdev, for (; num_scb >= MAX_TARGETS + 3; num_scb--) { i = num_scb * sizeof(struct scsi_ctrl_blk); - if ((scb = kzalloc(i, GFP_DMA)) != NULL) + scb = kzalloc(i, GFP_KERNEL); + if (scb) break; } -- cgit v1.2.3 From 27363ba89f3472c39737e0bc34f75c5728e1cffb Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Dec 2021 10:18:01 +0100 Subject: scsi: myrb: Don't use GFP_DMA in myrb_pdev_slave_alloc() The driver doesn't express DMA addressing limitation under 32-bits anywhere else, so remove the spurious GFP_DMA allocation. Link: https://lore.kernel.org/r/20211222091801.924745-1-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/myrb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c index 2a4506a5083e..71585528e8db 100644 --- a/drivers/scsi/myrb.c +++ b/drivers/scsi/myrb.c @@ -1674,7 +1674,7 @@ static int myrb_pdev_slave_alloc(struct scsi_device *sdev) if (sdev->id > MYRB_MAX_TARGETS) return -ENXIO; - pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL|GFP_DMA); + pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL); if (!pdev_info) return -ENOMEM; -- cgit v1.2.3 From 0298b7daf8091f895d20a1b512cba6ab4af5aca9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Dec 2021 10:19:35 +0100 Subject: scsi: myrs: Don't use GFP_DMA The myrs devices supports 64-bit addressing, so remove the spurious GFP_DMA allocations. Link: https://lore.kernel.org/r/20211222091935.925624-1-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/myrs.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index 6ea323e9a2e3..253ceca54a84 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -538,13 +538,11 @@ static bool myrs_enable_mmio_mbox(struct myrs_hba *cs, cs->fwstat_buf = NULL; goto out_free; } - cs->ctlr_info = kzalloc(sizeof(struct myrs_ctlr_info), - GFP_KERNEL | GFP_DMA); + cs->ctlr_info = kzalloc(sizeof(struct myrs_ctlr_info), GFP_KERNEL); if (!cs->ctlr_info) goto out_free; - cs->event_buf = kzalloc(sizeof(struct myrs_event), - GFP_KERNEL | GFP_DMA); + cs->event_buf = kzalloc(sizeof(struct myrs_event), GFP_KERNEL); if (!cs->event_buf) goto out_free; @@ -1805,7 +1803,7 @@ static int myrs_slave_alloc(struct scsi_device *sdev) ldev_num = myrs_translate_ldev(cs, sdev); - ldev_info = kzalloc(sizeof(*ldev_info), GFP_KERNEL|GFP_DMA); + ldev_info = kzalloc(sizeof(*ldev_info), GFP_KERNEL); if (!ldev_info) return -ENOMEM; @@ -1867,7 +1865,7 @@ static int myrs_slave_alloc(struct scsi_device *sdev) } else { struct myrs_pdev_info *pdev_info; - pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL|GFP_DMA); + pdev_info = kzalloc(sizeof(*pdev_info), GFP_KERNEL); if (!pdev_info) return -ENOMEM; -- cgit v1.2.3 From 1964777e107a7125fb0753a27cdede213d05248c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Dec 2021 10:20:48 +0100 Subject: scsi: snic: Don't use GFP_DMA in snic_queue_report_tgt_req() The driver doesn't express DMA addressing limitation under 32-bits anywhere else, so remove the spurious GFP_DMA allocation. Link: https://lore.kernel.org/r/20211222092048.925829-1-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/snic/snic_disc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index e9ccfb97773f..27e98df83b31 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -100,7 +100,7 @@ snic_queue_report_tgt_req(struct snic *snic) SNIC_BUG_ON(ntgts == 0); buf_len = ntgts * sizeof(struct snic_tgt_id) + SNIC_SG_DESC_ALIGN; - buf = kzalloc(buf_len, GFP_KERNEL|GFP_DMA); + buf = kzalloc(buf_len, GFP_KERNEL); if (!buf) { snic_req_free(snic, rqi); SNIC_HOST_ERR(snic->shost, "Resp Buf Alloc Failed.\n"); -- cgit v1.2.3 From 657b44d651eb284443d62895d9d47897729ef35a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 22 Dec 2021 10:22:47 +0100 Subject: scsi: pmcraid: Don't use GFP_DMA in pmcraid_alloc_sglist() The driver doesn't express DMA addressing limitation under 32-bits anywhere else, so remove the spurious GFP_DMA allocation. Link: https://lore.kernel.org/r/20211222092247.928711-1-hch@lst.de Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/pmcraid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 2fe7a0019fff..928532180d32 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3221,8 +3221,8 @@ static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) return NULL; sglist->order = order; - sgl_alloc_order(buflen, order, false, - GFP_KERNEL | GFP_DMA | __GFP_ZERO, &sglist->num_sg); + sgl_alloc_order(buflen, order, false, GFP_KERNEL | __GFP_ZERO, + &sglist->num_sg); return sglist; } -- cgit v1.2.3 From 9cf0666f34b1991d73db8b19dc53387724aaefae Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:35 +0530 Subject: scsi: mpi3mr: Add debug APIs based on logging_level bits Add debug print functions which will print messages based on logging_level bits enabled. Link: https://lore.kernel.org/r/20211220141159.16117-2-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_debug.h | 133 ++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h index c085bb048d41..cef61c5d59d3 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_debug.h +++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h @@ -14,27 +14,20 @@ /* * debug levels */ -#define MPI3_DEBUG 0x00000001 -#define MPI3_DEBUG_MSG_FRAME 0x00000002 -#define MPI3_DEBUG_SG 0x00000004 -#define MPI3_DEBUG_EVENTS 0x00000008 -#define MPI3_DEBUG_EVENT_WORK_TASK 0x00000010 -#define MPI3_DEBUG_INIT 0x00000020 -#define MPI3_DEBUG_EXIT 0x00000040 -#define MPI3_DEBUG_FAIL 0x00000080 -#define MPI3_DEBUG_TM 0x00000100 -#define MPI3_DEBUG_REPLY 0x00000200 -#define MPI3_DEBUG_HANDSHAKE 0x00000400 -#define MPI3_DEBUG_CONFIG 0x00000800 -#define MPI3_DEBUG_DL 0x00001000 -#define MPI3_DEBUG_RESET 0x00002000 -#define MPI3_DEBUG_SCSI 0x00004000 -#define MPI3_DEBUG_IOCTL 0x00008000 -#define MPI3_DEBUG_CSMISAS 0x00010000 -#define MPI3_DEBUG_SAS 0x00020000 -#define MPI3_DEBUG_TRANSPORT 0x00040000 -#define MPI3_DEBUG_TASK_SET_FULL 0x00080000 -#define MPI3_DEBUG_TRIGGER_DIAG 0x00200000 + +#define MPI3_DEBUG_EVENT 0x00000001 +#define MPI3_DEBUG_EVENT_WORK_TASK 0x00000002 +#define MPI3_DEBUG_INIT 0x00000004 +#define MPI3_DEBUG_EXIT 0x00000008 +#define MPI3_DEBUG_TM 0x00000010 +#define MPI3_DEBUG_RESET 0x00000020 +#define MPI3_DEBUG_SCSI_ERROR 0x00000040 +#define MPI3_DEBUG_REPLY 0x00000080 +#define MPI3_DEBUG_IOCTL_ERROR 0x00008000 +#define MPI3_DEBUG_IOCTL_INFO 0x00010000 +#define MPI3_DEBUG_SCSI_INFO 0x00020000 +#define MPI3_DEBUG 0x01000000 +#define MPI3_DEBUG_SG 0x02000000 /* @@ -50,11 +43,103 @@ #define ioc_info(ioc, fmt, ...) \ pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__) +#define dprint(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_event_th(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_EVENT) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_event_bh(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_init(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_INIT) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_exit(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_EXIT) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_tm(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_TM) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_reply(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_REPLY) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_reset(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_RESET) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_scsi_info(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_SCSI_INFO) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_scsi_err(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_SCSI_ERROR) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) + +#define dprint_scsi_command(ioc, SCMD, LOG_LEVEL) \ + do { \ + if (ioc->logging_level & LOG_LEVEL) \ + scsi_print_command(SCMD); \ + } while (0) + + +#define dprint_ioctl_info(ioc, fmt, ...) \ + do { \ + if (ioc->logging_level & MPI3_DEBUG_IOCTL_INFO) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ + } while (0) -#define dbgprint(IOC, FMT, ...) \ +#define dprint_ioctl_err(ioc, fmt, ...) \ do { \ - if (IOC->logging_level & MPI3_DEBUG) \ - pr_info("%s: " FMT, (IOC)->name, ##__VA_ARGS__); \ + if (ioc->logging_level & MPI3_DEBUG_IOCTL_ERROR) \ + pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \ } while (0) #endif /* MPT3SAS_DEBUG_H_INCLUDED */ + +/** + * dprint_dump_req - print message frame contents + * @req: pointer to message frame + * @sz: number of dwords + */ +static inline void +dprint_dump_req(void *req, int sz) +{ + int i; + __le32 *mfp = (__le32 *)req; + + pr_info("request:\n\t"); + for (i = 0; i < sz; i++) { + if (i && ((i % 8) == 0)) + pr_info("\n\t"); + pr_info("%08x ", le32_to_cpu(mfp[i])); + } + pr_info("\n"); +} -- cgit v1.2.3 From a83ec831b24a8142e0871544b19ee5671607588e Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:36 +0530 Subject: scsi: mpi3mr: Replace spin_lock() with spin_lock_irqsave() Use spin_lock_irqsave() instead of spin_lock() while acquiring reply_free_queue_lock & sbq_lock locks. Link: https://lore.kernel.org/r/20211220141159.16117-3-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index aa5d877df6f8..61dcacd098f1 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -124,8 +124,9 @@ static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc, u64 reply_dma) { u32 old_idx = 0; + unsigned long flags; - spin_lock(&mrioc->reply_free_queue_lock); + spin_lock_irqsave(&mrioc->reply_free_queue_lock, flags); old_idx = mrioc->reply_free_queue_host_index; mrioc->reply_free_queue_host_index = ( (mrioc->reply_free_queue_host_index == @@ -134,15 +135,16 @@ static void mpi3mr_repost_reply_buf(struct mpi3mr_ioc *mrioc, mrioc->reply_free_q[old_idx] = cpu_to_le64(reply_dma); writel(mrioc->reply_free_queue_host_index, &mrioc->sysif_regs->reply_free_host_index); - spin_unlock(&mrioc->reply_free_queue_lock); + spin_unlock_irqrestore(&mrioc->reply_free_queue_lock, flags); } void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, u64 sense_buf_dma) { u32 old_idx = 0; + unsigned long flags; - spin_lock(&mrioc->sbq_lock); + spin_lock_irqsave(&mrioc->sbq_lock, flags); old_idx = mrioc->sbq_host_index; mrioc->sbq_host_index = ((mrioc->sbq_host_index == (mrioc->sense_buf_q_sz - 1)) ? 0 : @@ -150,7 +152,7 @@ void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, mrioc->sense_buf_q[old_idx] = cpu_to_le64(sense_buf_dma); writel(mrioc->sbq_host_index, &mrioc->sysif_regs->sense_buffer_free_host_index); - spin_unlock(&mrioc->sbq_lock); + spin_unlock_irqrestore(&mrioc->sbq_lock, flags); } static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc, -- cgit v1.2.3 From fbaa9aa48bb43a021847195704c10908ded3c2ba Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:37 +0530 Subject: scsi: mpi3mr: Don't reset IOC if cmnds flush with reset status Don't issue the soft reset if internal commands are flushed out with reset status. Soft reset needs to be issued only if commands are really timed out. Link: https://lore.kernel.org/r/20211220141159.16117-4-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 10 ++++++---- drivers/scsi/mpi3mr/mpi3mr_os.c | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 61dcacd098f1..4ce79d7dad66 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1947,8 +1947,9 @@ static int mpi3mr_sync_timestamp(struct mpi3mr_ioc *mrioc) if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { ioc_err(mrioc, "Issue IOUCTL time_stamp: command timed out\n"); mrioc->init_cmds.is_waiting = 0; - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_TSU_TIMEOUT, 1); + if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) + mpi3mr_soft_reset_handler(mrioc, + MPI3MR_RESET_FROM_TSU_TIMEOUT, 1); retval = -1; goto out_unlock; } @@ -2827,8 +2828,9 @@ int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1); + if (!(mrioc->init_cmds.state & MPI3MR_CMD_RESET)) + mpi3mr_soft_reset_handler(mrioc, + MPI3MR_RESET_FROM_EVTACK_TIMEOUT, 1); retval = -1; goto out_unlock; } diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index fe10f257b5a4..ce7550358599 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -2659,8 +2659,9 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, ioc_err(mrioc, "%s :Issue TM: command timed out\n", __func__); drv_cmd->is_waiting = 0; retval = -1; - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_TM_TIMEOUT, 1); + if (!(drv_cmd->state & MPI3MR_CMD_RESET)) + mpi3mr_soft_reset_handler(mrioc, + MPI3MR_RESET_FROM_TM_TIMEOUT, 1); goto out_unlock; } -- cgit v1.2.3 From d00ff7c31195e2f5098b2c034f547a83c30b8adb Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:38 +0530 Subject: scsi: mpi3mr: Update MPI3 headers - part1 Update MPI3 headers. Link: https://lore.kernel.org/r/20211220141159.16117-5-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h | 603 +++++++++++++++++++++++++++++------ drivers/scsi/mpi3mr/mpi3mr_os.c | 2 +- 2 files changed, 499 insertions(+), 106 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h index d43bbecef651..5e1f6ced0e71 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h @@ -8,7 +8,7 @@ #define MPI3_CONFIG_PAGETYPE_IO_UNIT (0x00) #define MPI3_CONFIG_PAGETYPE_MANUFACTURING (0x01) #define MPI3_CONFIG_PAGETYPE_IOC (0x02) -#define MPI3_CONFIG_PAGETYPE_UEFI_BSD (0x03) +#define MPI3_CONFIG_PAGETYPE_DRIVER (0x03) #define MPI3_CONFIG_PAGETYPE_SECURITY (0x04) #define MPI3_CONFIG_PAGETYPE_ENCLOSURE (0x11) #define MPI3_CONFIG_PAGETYPE_DEVICE (0x12) @@ -181,8 +181,17 @@ struct mpi3_config_page_header { #define MPI3_SAS_HWRATE_MIN_RATE_6_0 (0x0a) #define MPI3_SAS_HWRATE_MIN_RATE_12_0 (0x0b) #define MPI3_SAS_HWRATE_MIN_RATE_22_5 (0x0c) -#define MPI3_SLOT_INVALID (0xffff) -#define MPI3_SLOT_INDEX_INVALID (0xffff) +#define MPI3_SLOT_INVALID (0xffff) +#define MPI3_SLOT_INDEX_INVALID (0xffff) +#define MPI3_LINK_CHANGE_COUNT_INVALID (0xffff) +#define MPI3_RATE_CHANGE_COUNT_INVALID (0xffff) +#define MPI3_TEMP_SENSOR_LOCATION_INTERNAL (0x0) +#define MPI3_TEMP_SENSOR_LOCATION_INLET (0x1) +#define MPI3_TEMP_SENSOR_LOCATION_OUTLET (0x2) +#define MPI3_TEMP_SENSOR_LOCATION_DRAM (0x3) +#define MPI3_MFGPAGE_VENDORID_BROADCOM (0x1000) +#define MPI3_MFGPAGE_DEVID_SAS4116 (0x00a5) +#define MPI3_MFGPAGE_DEVID_SAS4016 (0x00a7) struct mpi3_man_page0 { struct mpi3_config_page_header header; u8 chip_revision[8]; @@ -195,7 +204,7 @@ struct mpi3_man_page0 { __le32 reserved98; u8 oem; u8 sub_oem; - __le16 reserved9e; + __le16 flags; u8 board_mfg_day; u8 board_mfg_month; __le16 board_mfg_year; @@ -208,6 +217,8 @@ struct mpi3_man_page0 { }; #define MPI3_MAN0_PAGEVERSION (0x00) +#define MPI3_MAN0_FLAGS_SWITCH_PRESENT (0x0002) +#define MPI3_MAN0_FLAGS_EXPANDER_PRESENT (0x0001) #define MPI3_MAN1_VPD_SIZE (512) struct mpi3_man_page1 { struct mpi3_config_page_header header; @@ -236,7 +247,7 @@ struct mpi3_man_page5 { #define MPI3_MAN5_PAGEVERSION (0x00) struct mpi3_man6_gpio_entry { u8 function_code; - u8 reserved01; + u8 function_flags; __le16 flags; u8 param1; u8 param2; @@ -253,7 +264,6 @@ struct mpi3_man6_gpio_entry { #define MPI3_MAN6_GPIO_FUNCTION_PORT_STATUS_YELLOW (0x06) #define MPI3_MAN6_GPIO_FUNCTION_CABLE_MANAGEMENT (0x07) #define MPI3_MAN6_GPIO_FUNCTION_BKPLANE_MGMT_TYPE (0x08) -#define MPI3_MAN6_GPIO_FUNCTION_ISTWI_MUX_RESET (0x09) #define MPI3_MAN6_GPIO_FUNCTION_ISTWI_RESET (0x0a) #define MPI3_MAN6_GPIO_FUNCTION_BACKEND_PCIE_RESET (0x0b) #define MPI3_MAN6_GPIO_FUNCTION_GLOBAL_FAULT (0x0c) @@ -263,6 +273,10 @@ struct mpi3_man6_gpio_entry { #define MPI3_MAN6_GPIO_FUNCTION_CTRL_TYPE (0x10) #define MPI3_MAN6_GPIO_FUNCTION_LICENSE (0x11) #define MPI3_MAN6_GPIO_FUNCTION_REFCLK_CONTROL (0x12) +#define MPI3_MAN6_GPIO_FUNCTION_BACKEND_PCIE_RESET_CLAMP (0x13) +#define MPI3_MAN6_GPIO_ISTWI_RESET_FUNCTIONFLAGS_DEVSELECT_MASK (0x01) +#define MPI3_MAN6_GPIO_ISTWI_RESET_FUNCTIONFLAGS_DEVSELECT_ISTWI (0x00) +#define MPI3_MAN6_GPIO_ISTWI_RESET_FUNCTIONFLAGS_DEVSELECT_RECEPTACLEID (0x01) #define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_MASK (0xf0) #define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_GENERIC (0x00) #define MPI3_MAN6_GPIO_EXTINT_PARAM1_FLAGS_SOURCE_CABLE_MGMT (0x10) @@ -275,8 +289,6 @@ struct mpi3_man6_gpio_entry { #define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_MODULE_PRESENT (0x00) #define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_ACTIVE_CABLE_ENABLE (0x01) #define MPI3_MAN6_GPIO_CABLE_MGMT_PARAM1_INTERFACE_CABLE_MGMT_ENABLE (0x02) -#define MPI3_MAN6_GPIO_ISTWI_MUX_RESET_PARAM2_SPEC_MUX (0x00) -#define MPI3_MAN6_GPIO_ISTWI_MUX_RESET_PARAM2_ALL_MUXES (0x01) #define MPI3_MAN6_GPIO_LICENSE_PARAM1_TYPE_IBUTTON (0x00) #define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_MASK (0x0100) #define MPI3_MAN6_GPIO_FLAGS_SLEW_RATE_FAST_EDGE (0x0100) @@ -353,6 +365,7 @@ struct mpi3_man8_phy_info { __le32 reserved0c; }; +#define MPI3_MAN8_PHY_INFO_RECEPTACLE_ID_HOST_PHY (0xff) #ifndef MPI3_MAN8_PHY_INFO_MAX #define MPI3_MAN8_PHY_INFO_MAX (1) #endif @@ -373,20 +386,22 @@ struct mpi3_man9_rsrc_entry { }; enum mpi3_man9_resources { - MPI3_MAN9_RSRC_OUTSTANDING_REQS = 0, - MPI3_MAN9_RSRC_TARGET_CMDS = 1, - MPI3_MAN9_RSRC_SAS_TARGETS = 2, - MPI3_MAN9_RSRC_PCIE_TARGETS = 3, - MPI3_MAN9_RSRC_INITIATORS = 4, - MPI3_MAN9_RSRC_VDS = 5, - MPI3_MAN9_RSRC_ENCLOSURES = 6, - MPI3_MAN9_RSRC_ENCLOSURE_PHYS = 7, - MPI3_MAN9_RSRC_EXPANDERS = 8, - MPI3_MAN9_RSRC_PCIE_SWITCHES = 9, - MPI3_MAN9_RSRC_PDS = 10, - MPI3_MAN9_RSRC_HOST_PDS = 11, - MPI3_MAN9_RSRC_ADV_HOST_PDS = 12, - MPI3_MAN9_RSRC_RAID_PDS = 13, + MPI3_MAN9_RSRC_OUTSTANDING_REQS = 0, + MPI3_MAN9_RSRC_TARGET_CMDS = 1, + MPI3_MAN9_RSRC_RESERVED02 = 2, + MPI3_MAN9_RSRC_NVME = 3, + MPI3_MAN9_RSRC_INITIATORS = 4, + MPI3_MAN9_RSRC_VDS = 5, + MPI3_MAN9_RSRC_ENCLOSURES = 6, + MPI3_MAN9_RSRC_ENCLOSURE_PHYS = 7, + MPI3_MAN9_RSRC_EXPANDERS = 8, + MPI3_MAN9_RSRC_PCIE_SWITCHES = 9, + MPI3_MAN9_RSRC_RESERVED10 = 10, + MPI3_MAN9_RSRC_HOST_PD_DRIVES = 11, + MPI3_MAN9_RSRC_ADV_HOST_PD_DRIVES = 12, + MPI3_MAN9_RSRC_RAID_PD_DRIVES = 13, + MPI3_MAN9_RSRC_DRV_DIAG_BUF = 14, + MPI3_MAN9_RSRC_NAMESPACE_COUNT = 15, MPI3_MAN9_RSRC_NUM_RESOURCES }; @@ -402,6 +417,7 @@ enum mpi3_man9_resources { #define MPI3_MAN9_MIN_ENCLOSURES (0) #define MPI3_MAN9_MAX_ENCLOSURES (65535) #define MPI3_MAN9_MIN_ENCLOSURE_PHYS (0) +#define MPI3_MAN9_MIN_NAMESPACE_COUNT (1) #define MPI3_MAN9_MIN_EXPANDERS (0) #define MPI3_MAN9_MAX_EXPANDERS (65535) #define MPI3_MAN9_MIN_PCIE_SWITCHES (0) @@ -422,9 +438,14 @@ struct mpi3_man_page9 { struct mpi3_man10_istwi_ctrlr_entry { __le16 slave_address; __le16 flags; - __le32 reserved04; + u8 scl_low_override; + u8 scl_high_override; + __le16 reserved06; }; +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_MASK (0x000c) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_100K (0x0000) +#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_400K (0x0004) #define MPI3_MAN10_ISTWI_CTRLR_FLAGS_SLAVE_ENABLED (0x0002) #define MPI3_MAN10_ISTWI_CTRLR_FLAGS_MASTER_ENABLED (0x0001) #ifndef MPI3_MAN10_ISTWI_CTRLR_MAX @@ -451,10 +472,13 @@ struct mpi3_man11_temp_sensor_device_format { u8 temp_channel[4]; }; -#define MPI3_MAN11_TEMP_SENSOR_TYPE_MAX6654 (0x00) -#define MPI3_MAN11_TEMP_SENSOR_TYPE_EMC1442 (0x01) -#define MPI3_MAN11_TEMP_SENSOR_TYPE_ADT7476 (0x02) -#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_ENABLED (0x01) +#define MPI3_MAN11_TEMP_SENSOR_TYPE_MAX6654 (0x00) +#define MPI3_MAN11_TEMP_SENSOR_TYPE_EMC1442 (0x01) +#define MPI3_MAN11_TEMP_SENSOR_TYPE_ADT7476 (0x02) +#define MPI3_MAN11_TEMP_SENSOR_TYPE_SE97B (0x03) +#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_LOCATION_MASK (0xe0) +#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_LOCATION_SHIFT (5) +#define MPI3_MAN11_TEMP_SENSOR_CHANNEL_ENABLED (0x01) struct mpi3_man11_seeprom_device_format { u8 size; u8 page_write_size; @@ -495,31 +519,40 @@ struct mpi3_man11_bkplane_spec_ubm_format { #define MPI3_MAN11_BKPLANE_UBM_FLAGS_MAX_FRU_SHIFT (4) #define MPI3_MAN11_BKPLANE_UBM_FLAGS_POLL_INTERVAL_MASK (0x000f) #define MPI3_MAN11_BKPLANE_UBM_FLAGS_POLL_INTERVAL_SHIFT (0) -struct mpi3_man11_bkplane_spec_vpp_format { +struct mpi3_man11_bkplane_spec_non_ubm_format { __le16 flags; - __le16 reserved02; + u8 reserved02; + u8 type; }; -#define MPI3_MAN11_BKPLANE_VPP_FLAGS_REFCLK_POLICY_ALWAYS_ENABLED (0x0040) -#define MPI3_MAN11_BKPLANE_VPP_FLAGS_PRESENCE_DETECT_MASK (0x0030) -#define MPI3_MAN11_BKPLANE_VPP_FLAGS_PRESENCE_DETECT_GPIO (0x0000) -#define MPI3_MAN11_BKPLANE_VPP_FLAGS_PRESENCE_DETECT_REG (0x0010) -#define MPI3_MAN11_BKPLANE_VPP_FLAGS_POLL_INTERVAL_MASK (0x000f) -#define MPI3_MAN11_BKPLANE_VPP_FLAGS_POLL_INTERVAL_SHIFT (0) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_GROUP_MASK (0xf000) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_GROUP_SHIFT (12) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_REFCLK_POLICY_ALWAYS_ENABLED (0x0200) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_PRESENCE_DETECT_MASK (0x0030) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_PRESENCE_DETECT_GPIO (0x0000) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_PRESENCE_DETECT_REG (0x0010) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_POLL_INTERVAL_MASK (0x000f) +#define MPI3_MAN11_BKPLANE_NON_UBM_FLAGS_POLL_INTERVAL_SHIFT (0) +#define MPI3_MAN11_BKPLANE_NON_UBM_TYPE_VPP (0x00) union mpi3_man11_bkplane_spec_format { - struct mpi3_man11_bkplane_spec_ubm_format ubm; - struct mpi3_man11_bkplane_spec_vpp_format vpp; + struct mpi3_man11_bkplane_spec_ubm_format ubm; + struct mpi3_man11_bkplane_spec_non_ubm_format non_ubm; }; struct mpi3_man11_bkplane_mgmt_device_format { u8 type; u8 receptacle_id; - __le16 reserved02; + u8 reset_info; + u8 reserved03; union mpi3_man11_bkplane_spec_format backplane_mgmt_specific; }; #define MPI3_MAN11_BKPLANE_MGMT_TYPE_UBM (0x00) -#define MPI3_MAN11_BKPLANE_MGMT_TYPE_VPP (0x01) +#define MPI3_MAN11_BKPLANE_MGMT_TYPE_NON_UBM (0x01) +#define MPI3_MAN11_BACKPLANE_RESETINFO_ASSERT_TIME_MASK (0xf0) +#define MPI3_MAN11_BACKPLANE_RESETINFO_ASSERT_TIME_SHIFT (4) +#define MPI3_MAN11_BACKPLANE_RESETINFO_READY_TIME_MASK (0x0f) +#define MPI3_MAN11_BACKPLANE_RESETINFO_READY_TIME_SHIFT (0) struct mpi3_man11_gas_gauge_device_format { u8 type; u8 reserved01[3]; @@ -527,6 +560,11 @@ struct mpi3_man11_gas_gauge_device_format { }; #define MPI3_MAN11_GAS_GAUGE_TYPE_STANDARD (0x00) +struct mpi3_man11_mgmt_ctrlr_device_format { + __le32 reserved00; + __le32 reserved04; +}; + union mpi3_man11_device_specific_format { struct mpi3_man11_mux_device_format mux; struct mpi3_man11_temp_sensor_device_format temp_sensor; @@ -535,6 +573,7 @@ union mpi3_man11_device_specific_format { struct mpi3_man11_cable_mgmt_device_format cable_mgmt; struct mpi3_man11_bkplane_mgmt_device_format bkplane_mgmt; struct mpi3_man11_gas_gauge_device_format gas_gauge; + struct mpi3_man11_mgmt_ctrlr_device_format mgmt_controller; __le32 words[2]; }; @@ -556,10 +595,8 @@ struct mpi3_man11_istwi_device_format { #define MPI3_MAN11_ISTWI_DEVTYPE_CABLE_MGMT (0x04) #define MPI3_MAN11_ISTWI_DEVTYPE_BACKPLANE_MGMT (0x05) #define MPI3_MAN11_ISTWI_DEVTYPE_GAS_GAUGE (0x06) +#define MPI3_MAN11_ISTWI_DEVTYPE_MGMT_CONTROLLER (0x07) #define MPI3_MAN11_ISTWI_FLAGS_MUX_PRESENT (0x01) -#define MPI3_MAN11_ISTWI_FLAGS_BUS_SPEED_MASK (0x06) -#define MPI3_MAN11_ISTWI_FLAGS_BUS_SPEED_100KHZ (0x00) -#define MPI3_MAN11_ISTWI_FLAGS_BUS_SPEED_400KHZ (0x02) #ifndef MPI3_MAN11_ISTWI_DEVICE_MAX #define MPI3_MAN11_ISTWI_DEVICE_MAX (1) #endif @@ -692,8 +729,8 @@ struct mpi3_man_page14 { #define MPI3_MAN14_FLAGS_AUTH_SESSION_REQ (0x01) #define MPI3_MAN14_FLAGS_AUTH_API_MASK (0x0e) #define MPI3_MAN14_FLAGS_AUTH_API_NONE (0x00) -#define MPI3_MAN14_FLAGS_AUTH_API_CEREBUS (0x02) -#define MPI3_MAN14_FLAGS_AUTH_API_DMTF_PMCI (0x04) +#define MPI3_MAN14_FLAGS_AUTH_API_CERBERUS (0x02) +#define MPI3_MAN14_FLAGS_AUTH_API_SPDM (0x04) #ifndef MPI3_MAN15_VERSION_RECORD_MAX #define MPI3_MAN15_VERSION_RECORD_MAX 1 #endif @@ -808,7 +845,7 @@ struct mpi3_io_unit_page1 { struct mpi3_config_page_header header; __le32 flags; u8 dmd_io_delay; - u8 dmd_report_pc_ie; + u8 dmd_report_pcie; u8 dmd_report_sata; u8 dmd_report_sas; }; @@ -844,26 +881,30 @@ struct mpi3_io_unit_page2 { #define MPI3_IOUNIT2_GPIO_SETTING_ON (0x0001) struct mpi3_io_unit3_sensor { __le16 flags; - __le16 reserved02; - __le16 threshold[4]; + u8 threshold_margin; + u8 reserved03; + __le16 threshold[3]; + __le16 reserved0a; __le32 reserved0c; __le32 reserved10; __le32 reserved14; }; -#define MPI3_IOUNIT3_SENSOR_FLAGS_T3_ENABLE (0x0008) -#define MPI3_IOUNIT3_SENSOR_FLAGS_T2_ENABLE (0x0004) -#define MPI3_IOUNIT3_SENSOR_FLAGS_T1_ENABLE (0x0002) -#define MPI3_IOUNIT3_SENSOR_FLAGS_T0_ENABLE (0x0001) +#define MPI3_IOUNIT3_SENSOR_FLAGS_FATAL_EVENT_ENABLED (0x0010) +#define MPI3_IOUNIT3_SENSOR_FLAGS_FATAL_ACTION_ENABLED (0x0008) +#define MPI3_IOUNIT3_SENSOR_FLAGS_CRITICAL_EVENT_ENABLED (0x0004) +#define MPI3_IOUNIT3_SENSOR_FLAGS_CRITICAL_ACTION_ENABLED (0x0002) +#define MPI3_IOUNIT3_SENSOR_FLAGS_WARNING_EVENT_ENABLED (0x0001) #ifndef MPI3_IO_UNIT3_SENSOR_MAX -#define MPI3_IO_UNIT3_SENSOR_MAX (1) +#define MPI3_IO_UNIT3_SENSOR_MAX (1) #endif struct mpi3_io_unit_page3 { struct mpi3_config_page_header header; __le32 reserved08; u8 num_sensors; - u8 polling_interval; - __le16 reserved0e; + u8 nominal_poll_interval; + u8 warning_poll_interval; + u8 reserved0f; struct mpi3_io_unit3_sensor sensor[MPI3_IO_UNIT3_SENSOR_MAX]; }; @@ -873,13 +914,19 @@ struct mpi3_io_unit4_sensor { __le16 reserved02; u8 flags; u8 reserved05[3]; - __le32 reserved08; + __le16 istwi_index; + u8 channel; + u8 reserved0b; __le32 reserved0c; }; +#define MPI3_IOUNIT4_SENSOR_FLAGS_LOC_MASK (0xe0) +#define MPI3_IOUNIT4_SENSOR_FLAGS_LOC_SHIFT (5) #define MPI3_IOUNIT4_SENSOR_FLAGS_TEMP_VALID (0x01) +#define MPI3_IOUNIT4_SENSOR_ISTWI_INDEX_INTERNAL (0xffff) +#define MPI3_IOUNIT4_SENSOR_CHANNEL_RESERVED (0xff) #ifndef MPI3_IO_UNIT4_SENSOR_MAX -#define MPI3_IO_UNIT4_SENSOR_MAX (1) +#define MPI3_IO_UNIT4_SENSOR_MAX (1) #endif struct mpi3_io_unit_page4 { struct mpi3_config_page_header header; @@ -906,8 +953,9 @@ struct mpi3_io_unit_page5 { struct mpi3_io_unit5_spinup_group spinup_group_parameters[4]; __le32 reserved18; __le32 reserved1c; - __le32 reserved20; - u8 reserved24; + __le16 device_shutdown; + __le16 reserved22; + u8 pcie_device_wait_time; u8 sata_device_wait_time; u8 spinup_encl_drive_count; u8 spinup_encl_delay; @@ -919,6 +967,22 @@ struct mpi3_io_unit_page5 { }; #define MPI3_IOUNIT5_PAGEVERSION (0x00) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_NO_ACTION (0x00) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_ATTACHED (0x01) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_EXPANDER_ATTACHED (0x02) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SWITCH_ATTACHED (0x02) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_EXPANDER (0x03) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_SWITCH (0x03) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_MASK (0x0300) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_SHIFT (8) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_HDD_MASK (0x00c0) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_HDD_SHIFT (6) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_NVME_SSD_MASK (0x0030) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_NVME_SSD_SHIFT (4) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_SSD_MASK (0x000c) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_SSD_SHIFT (2) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_MASK (0x0003) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAA_SSD_SHIFT (0) #define MPI3_IOUNIT5_FLAGS_POWER_CAPABLE_SPINUP (0x02) #define MPI3_IOUNIT5_FLAGS_AUTO_PORT_ENABLE (0x01) #define MPI3_IOUNIT5_PHY_SPINUP_GROUP_MASK (0x03) @@ -1012,7 +1076,52 @@ struct mpi3_ioc_page2 { }; #define MPI3_IOC2_PAGEVERSION (0x00) -struct mpi3_uefibsd_page0 { +#define MPI3_DRIVER_FLAGS_ADMINRAIDPD_BLOCKED (0x0010) +#define MPI3_DRIVER_FLAGS_OOBRAIDPD_BLOCKED (0x0008) +#define MPI3_DRIVER_FLAGS_OOBRAIDVD_BLOCKED (0x0004) +#define MPI3_DRIVER_FLAGS_OOBADVHOSTPD_BLOCKED (0x0002) +#define MPI3_DRIVER_FLAGS_OOBHOSTPD_BLOCKED (0x0001) +struct mpi3_allowed_cmd_scsi { + __le16 service_action; + u8 operation_code; + u8 command_flags; +}; + +struct mpi3_allowed_cmd_ata { + u8 subcommand; + u8 reserved01; + u8 command; + u8 command_flags; +}; + +struct mpi3_allowed_cmd_nvme { + u8 reserved00; + u8 nvme_cmd_flags; + u8 op_code; + u8 command_flags; +}; + +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_SUBQ_TYPE_MASK (0x80) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_SUBQ_TYPE_IO (0x00) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_SUBQ_TYPE_ADMIN (0x80) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_CMDSET_MASK (0x3f) +#define MPI3_DRIVER_ALLOWEDCMD_NVMECMDFLAGS_CMDSET_NVM (0x00) +union mpi3_allowed_cmd { + struct mpi3_allowed_cmd_scsi scsi; + struct mpi3_allowed_cmd_ata ata; + struct mpi3_allowed_cmd_nvme nvme; +}; + +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_ADMINRAIDPD_BLOCKED (0x20) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBRAIDPD_BLOCKED (0x10) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBRAIDVD_BLOCKED (0x08) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBADVHOSTPD_BLOCKED (0x04) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_OOBHOSTPD_BLOCKED (0x02) +#define MPI3_DRIVER_ALLOWEDCMD_CMDFLAGS_CHECKSUBCMD_ENABLED (0x01) +#ifndef MPI3_ALLOWED_CMDS_MAX +#define MPI3_ALLOWED_CMDS_MAX (1) +#endif +struct mpi3_driver_page0 { struct mpi3_config_page_header header; __le32 bsd_options; u8 ssu_timeout; @@ -1026,13 +1135,122 @@ struct mpi3_uefibsd_page0 { __le32 reserved18; }; -#define MPI3_UEFIBSD_PAGEVERSION (0x00) -#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_MASK (0x00000003) -#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_IOC_AND_DEVS (0x00000000) -#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_IOC_ONLY (0x00000001) -#define MPI3_UEFIBSD_BSDOPTS_REGISTRATION_NONE (0x00000002) -#define MPI3_UEFIBSD_BSDOPTS_DIS_HII_CONFIG_UTIL (0x00000004) -#define MPI3_UEFIBSD_BSDOPTS_EN_ADV_ADAPTER_CONFIG (0x00000008) +#define MPI3_DRIVER0_PAGEVERSION (0x00) +#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_MASK (0x00000003) +#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_AND_DEVS (0x00000000) +#define MPI3_DRIVER0_BSDOPTS_REGISTRATION_IOC_ONLY (0x00000001) +#define MPI3_DRIVER0_BSDOPTS_DIS_HII_CONFIG_UTIL (0x00000004) +#define MPI3_DRIVER0_BSDOPTS_EN_ADV_ADAPTER_CONFIG (0x00000008) +struct mpi3_driver_page1 { + struct mpi3_config_page_header header; + __le32 flags; + __le32 reserved0c; + __le16 host_diag_trace_max_size; + __le16 host_diag_trace_min_size; + __le16 host_diag_trace_decrement_size; + __le16 reserved16; + __le16 host_diag_fw_max_size; + __le16 host_diag_fw_min_size; + __le16 host_diag_fw_decrement_size; + __le16 reserved1e; + __le16 host_diag_driver_max_size; + __le16 host_diag_driver_min_size; + __le16 host_diag_driver_decrement_size; + __le16 reserved26; +}; + +#define MPI3_DRIVER1_PAGEVERSION (0x00) +#ifndef MPI3_DRIVER2_TRIGGER_MAX +#define MPI3_DRIVER2_TRIGGER_MAX (1) +#endif +struct mpi3_driver2_trigger_event { + u8 type; + u8 flags; + u8 reserved02; + u8 event; + __le32 reserved04[3]; +}; + +struct mpi3_driver2_trigger_scsi_sense { + u8 type; + u8 flags; + __le16 reserved02; + u8 ascq; + u8 asc; + u8 sense_key; + u8 reserved07; + __le32 reserved08[2]; +}; + +#define MPI3_DRIVER2_TRIGGER_SCSI_SENSE_ASCQ_MATCH_ALL (0xff) +#define MPI3_DRIVER2_TRIGGER_SCSI_SENSE_ASC_MATCH_ALL (0xff) +#define MPI3_DRIVER2_TRIGGER_SCSI_SENSE_SENSE_KEY_MATCH_ALL (0xff) +struct mpi3_driver2_trigger_reply { + u8 type; + u8 flags; + __le16 ioc_status; + __le32 ioc_log_info; + __le32 ioc_log_info_mask; + __le32 reserved0c; +}; + +#define MPI3_DRIVER2_TRIGGER_REPLY_IOCSTATUS_MATCH_ALL (0xffff) +union mpi3_driver2_trigger_element { + struct mpi3_driver2_trigger_event event; + struct mpi3_driver2_trigger_scsi_sense scsi_sense; + struct mpi3_driver2_trigger_reply reply; +}; + +#define MPI3_DRIVER2_TRIGGER_TYPE_EVENT (0x00) +#define MPI3_DRIVER2_TRIGGER_TYPE_SCSI_SENSE (0x01) +#define MPI3_DRIVER2_TRIGGER_TYPE_REPLY (0x02) +#define MPI3_DRIVER2_TRIGGER_FLAGS_DIAG_TRACE_RELEASE (0x02) +#define MPI3_DRIVER2_TRIGGER_FLAGS_DIAG_FW_RELEASE (0x01) +struct mpi3_driver_page2 { + struct mpi3_config_page_header header; + __le64 master_trigger; + __le32 reserved10[3]; + u8 num_triggers; + u8 reserved1d[3]; + union mpi3_driver2_trigger_element trigger[MPI3_DRIVER2_TRIGGER_MAX]; +}; + +#define MPI3_DRIVER2_PAGEVERSION (0x00) +#define MPI3_DRIVER2_MASTERTRIGGER_DIAG_TRACE_RELEASE (0x8000000000000000ULL) +#define MPI3_DRIVER2_MASTERTRIGGER_DIAG_FW_RELEASE (0x4000000000000000ULL) +#define MPI3_DRIVER2_MASTERTRIGGER_SNAPDUMP (0x2000000000000000ULL) +#define MPI3_DRIVER2_MASTERTRIGGER_DEVICE_REMOVAL_ENABLED (0x0000000000000004ULL) +#define MPI3_DRIVER2_MASTERTRIGGER_TASK_MANAGEMENT_ENABLED (0x0000000000000002ULL) +struct mpi3_driver_page10 { + struct mpi3_config_page_header header; + __le16 flags; + __le16 reserved0a; + u8 num_allowed_commands; + u8 reserved0d[3]; + union mpi3_allowed_cmd allowed_command[MPI3_ALLOWED_CMDS_MAX]; +}; + +#define MPI3_DRIVER10_PAGEVERSION (0x00) +struct mpi3_driver_page20 { + struct mpi3_config_page_header header; + __le16 flags; + __le16 reserved0a; + u8 num_allowed_commands; + u8 reserved0d[3]; + union mpi3_allowed_cmd allowed_command[MPI3_ALLOWED_CMDS_MAX]; +}; + +#define MPI3_DRIVER20_PAGEVERSION (0x00) +struct mpi3_driver_page30 { + struct mpi3_config_page_header header; + __le16 flags; + __le16 reserved0a; + u8 num_allowed_commands; + u8 reserved0d[3]; + union mpi3_allowed_cmd allowed_command[MPI3_ALLOWED_CMDS_MAX]; +}; + +#define MPI3_DRIVER30_PAGEVERSION (0x00) union mpi3_security_mac { __le32 dword[16]; __le16 word[32]; @@ -1102,7 +1320,7 @@ struct mpi3_security1_key_record { #define MPI3_SECURITY1_KEY_RECORD_CONSUMER_NOT_VALID (0x00) #define MPI3_SECURITY1_KEY_RECORD_CONSUMER_SAFESTORE (0x01) #define MPI3_SECURITY1_KEY_RECORD_CONSUMER_CERT_CHAIN (0x02) -#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_AUTH_DEV_KEY (0x03) +#define MPI3_SECURITY1_KEY_RECORD_CONSUMER_DEVICE_KEY (0x03) #define MPI3_SECURITY1_KEY_RECORD_CONSUMER_CACHE_OFFLOAD (0x04) struct mpi3_security_page1 { struct mpi3_config_page_header header; @@ -1137,16 +1355,30 @@ struct mpi3_sas_io_unit_page0 { struct mpi3_config_page_header header; __le32 reserved08; u8 num_phys; - u8 reserved0d[3]; + u8 init_status; + __le16 reserved0e; struct mpi3_sas_io_unit0_phy_data phy_data[MPI3_SAS_IO_UNIT0_PHY_MAX]; }; -#define MPI3_SASIOUNIT0_PAGEVERSION (0x00) -#define MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS (0x08) -#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) -#define MPI3_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) -#define MPI3_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) -#define MPI3_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) +#define MPI3_SASIOUNIT0_PAGEVERSION (0x00) +#define MPI3_SASIOUNIT0_INITSTATUS_NO_ERRORS (0x00) +#define MPI3_SASIOUNIT0_INITSTATUS_NEEDS_INITIALIZATION (0x01) +#define MPI3_SASIOUNIT0_INITSTATUS_NO_TARGETS_ALLOCATED (0x02) +#define MPI3_SASIOUNIT0_INITSTATUS_BAD_NUM_PHYS (0x04) +#define MPI3_SASIOUNIT0_INITSTATUS_UNSUPPORTED_CONFIG (0x05) +#define MPI3_SASIOUNIT0_INITSTATUS_HOST_PHYS_ENABLED (0x06) +#define MPI3_SASIOUNIT0_INITSTATUS_PRODUCT_SPECIFIC_MIN (0xf0) +#define MPI3_SASIOUNIT0_INITSTATUS_PRODUCT_SPECIFIC_MAX (0xff) +#define MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS (0x08) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_MASK (0x03) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_IOUNIT1 (0x00) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_DYNAMIC (0x01) +#define MPI3_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG_BACKPLANE (0x02) +#define MPI3_SASIOUNIT0_PHYFLAGS_INIT_PERSIST_CONNECT (0x40) +#define MPI3_SASIOUNIT0_PHYFLAGS_TARG_PERSIST_CONNECT (0x20) +#define MPI3_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) +#define MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY (0x02) +#define MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY (0x01) struct mpi3_sas_io_unit1_phy_data { u8 io_unit_port; u8 port_flags; @@ -1343,6 +1575,26 @@ struct mpi3_sas_expander_page1 { #define MPI3_SASEXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) #define MPI3_SASEXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) #define MPI3_SASEXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) +#ifndef MPI3_SASEXPANDER2_MAX_NUM_PHYS +#define MPI3_SASEXPANDER2_MAX_NUM_PHYS (1) +#endif +struct mpi3_sasexpander2_phy_element { + u8 link_change_count; + u8 reserved01; + __le16 rate_change_count; + __le32 reserved04; +}; + +struct mpi3_sas_expander_page2 { + struct mpi3_config_page_header header; + u8 num_phys; + u8 reserved09; + __le16 dev_handle; + __le32 reserved0c; + struct mpi3_sasexpander2_phy_element phy[MPI3_SASEXPANDER2_MAX_NUM_PHYS]; +}; + +#define MPI3_SASEXPANDER2_PAGEVERSION (0x00) struct mpi3_sas_port_page0 { struct mpi3_config_page_header header; u8 port_number; @@ -1510,6 +1762,14 @@ struct mpi3_sas_phy_page4 { #define MPI3_PCIE_NEG_LINK_RATE_8_0 (0x04) #define MPI3_PCIE_NEG_LINK_RATE_16_0 (0x05) #define MPI3_PCIE_NEG_LINK_RATE_32_0 (0x06) +#define MPI3_PCIE_ASPM_ENABLE_NONE (0x0) +#define MPI3_PCIE_ASPM_ENABLE_L0S (0x1) +#define MPI3_PCIE_ASPM_ENABLE_L1 (0x2) +#define MPI3_PCIE_ASPM_ENABLE_L0S_L1 (0x3) +#define MPI3_PCIE_ASPM_SUPPORT_NONE (0x0) +#define MPI3_PCIE_ASPM_SUPPORT_L0S (0x1) +#define MPI3_PCIE_ASPM_SUPPORT_L1 (0x2) +#define MPI3_PCIE_ASPM_SUPPORT_L0S_L1 (0x3) struct mpi3_pcie_io_unit0_phy_data { u8 link; u8 link_flags; @@ -1540,7 +1800,8 @@ struct mpi3_pcie_io_unit_page0 { __le32 reserved08; u8 num_phys; u8 init_status; - __le16 reserved0e; + u8 aspm; + u8 reserved0f; struct mpi3_pcie_io_unit0_phy_data phy_data[MPI3_PCIE_IO_UNIT0_PHY_MAX]; }; @@ -1556,6 +1817,14 @@ struct mpi3_pcie_io_unit_page0 { #define MPI3_PCIEIOUNIT0_INITSTATUS_BAD_CLOCKING_MODE (0x08) #define MPI3_PCIEIOUNIT0_INITSTATUS_PROD_SPEC_START (0xf0) #define MPI3_PCIEIOUNIT0_INITSTATUS_PROD_SPEC_END (0xff) +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_STATES_MASK (0xc0) +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_STATES_SHIFT (6) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_STATES_MASK (0x30) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_STATES_SHIFT (4) +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_SUPPORT_MASK (0x0c) +#define MPI3_PCIEIOUNIT0_ASPM_SWITCH_SUPPORT_SHIFT (2) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_SUPPORT_MASK (0x03) +#define MPI3_PCIEIOUNIT0_ASPM_DIRECT_SUPPORT_SHIFT (0) struct mpi3_pcie_io_unit1_phy_data { u8 link; u8 link_flags; @@ -1569,16 +1838,16 @@ struct mpi3_pcie_io_unit1_phy_data { #define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_DIS_SEPARATE_REFCLK (0x00) #define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_EN_SRIS (0x01) #define MPI3_PCIEIOUNIT1_LINKFLAGS_PCIE_CLK_MODE_EN_SRNS (0x02) -#define MPI3_PCIEIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) -#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_MASK (0xf0) -#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_SHIFT (4) -#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_2_5 (0x20) -#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_5_0 (0x30) -#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_8_0 (0x40) -#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_16_0 (0x50) -#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_32_0 (0x60) +#define MPI3_PCIEIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_MASK (0xf0) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_SHIFT (4) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_2_5 (0x20) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_5_0 (0x30) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_8_0 (0x40) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_16_0 (0x50) +#define MPI3_PCIEIOUNIT1_MMLR_MAX_RATE_32_0 (0x60) #ifndef MPI3_PCIE_IO_UNIT1_PHY_MAX -#define MPI3_PCIE_IO_UNIT1_PHY_MAX (1) +#define MPI3_PCIE_IO_UNIT1_PHY_MAX (1) #endif struct mpi3_pcie_io_unit_page1 { struct mpi3_config_page_header header; @@ -1586,21 +1855,66 @@ struct mpi3_pcie_io_unit_page1 { __le32 reserved0c; u8 num_phys; u8 reserved11; - __le16 reserved12; + u8 aspm; + u8 reserved13; struct mpi3_pcie_io_unit1_phy_data phy_data[MPI3_PCIE_IO_UNIT1_PHY_MAX]; }; -#define MPI3_PCIEIOUNIT1_PAGEVERSION (0x00) +#define MPI3_PCIEIOUNIT1_PAGEVERSION (0x00) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_OVERRIDE_DISABLE (0x80) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_DISABLE (0x40) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_MASK (0x30) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SHIFT (4) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SRIS_SRNS_DISABLED (0x00) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SRIS_ENABLED (0x10) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_CLOCK_OVERRIDE_MODE_SRNS_ENABLED (0x20) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MASK (0x0f) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_2_5 (0x02) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_5_0 (0x03) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_8_0 (0x04) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_16_0 (0x05) +#define MPI3_PCIEIOUNIT1_CONTROL_FLAGS_LINK_RATE_OVERRIDE_MAX_32_0 (0x06) +#define MPI3_PCIEIOUNIT1_ASPM_SWITCH_MASK (0x0c) +#define MPI3_PCIEIOUNIT1_ASPM_SWITCH_SHIFT (2) +#define MPI3_PCIEIOUNIT1_ASPM_DIRECT_MASK (0x03) +#define MPI3_PCIEIOUNIT1_ASPM_DIRECT_SHIFT (0) struct mpi3_pcie_io_unit_page2 { struct mpi3_config_page_header header; - __le16 nv_me_max_queue_depth; - __le16 reserved0a; - u8 nv_me_abort_to; + __le16 nvme_max_q_dx1; + __le16 nvme_max_q_dx2; + u8 nvme_abort_to; u8 reserved0d; - __le16 reserved0e; + __le16 nvme_max_q_dx4; }; #define MPI3_PCIEIOUNIT2_PAGEVERSION (0x00) +#define MPI3_PCIEIOUNIT3_ERROR_RECEIVER_ERROR (0) +#define MPI3_PCIEIOUNIT3_ERROR_RECOVERY (1) +#define MPI3_PCIEIOUNIT3_ERROR_CORRECTABLE_ERROR_MSG (2) +#define MPI3_PCIEIOUNIT3_ERROR_BAD_DLLP (3) +#define MPI3_PCIEIOUNIT3_ERROR_BAD_TLP (4) +#define MPI3_PCIEIOUNIT3_NUM_ERROR_INDEX (5) +struct mpi3_pcie_io_unit3_error { + __le16 threshold_count; + __le16 reserved02; +}; + +struct mpi3_pcie_io_unit_page3 { + struct mpi3_config_page_header header; + u8 threshold_window; + u8 threshold_action; + u8 escalation_count; + u8 escalation_action; + u8 num_errors; + u8 reserved0d[3]; + struct mpi3_pcie_io_unit3_error error[MPI3_PCIEIOUNIT3_NUM_ERROR_INDEX]; +}; + +#define MPI3_PCIEIOUNIT3_PAGEVERSION (0x00) +#define MPI3_PCIEIOUNIT3_ACTION_NO_ACTION (0x00) +#define MPI3_PCIEIOUNIT3_ACTION_HOT_RESET (0x01) +#define MPI3_PCIEIOUNIT3_ACTION_REDUCE_LINK_RATE_ONLY (0x02) +#define MPI3_PCIEIOUNIT3_ACTION_REDUCE_LINK_RATE_NO_ACCESS (0x03) struct mpi3_pcie_switch_page0 { struct mpi3_config_page_header header; u8 io_unit_port; @@ -1609,7 +1923,7 @@ struct mpi3_pcie_switch_page0 { __le16 dev_handle; __le16 parent_dev_handle; u8 num_ports; - u8 pc_ie_level; + u8 pcie_level; __le16 reserved12; __le32 reserved14; __le32 reserved18; @@ -1623,7 +1937,8 @@ struct mpi3_pcie_switch_page0 { struct mpi3_pcie_switch_page1 { struct mpi3_config_page_header header; u8 io_unit_port; - u8 reserved09[3]; + u8 flags; + __le16 reserved0a; u8 num_ports; u8 port_num; __le16 attached_dev_handle; @@ -1636,15 +1951,43 @@ struct mpi3_pcie_switch_page1 { }; #define MPI3_PCIESWITCH1_PAGEVERSION (0x00) +#define MPI3_PCIESWITCH1_FLAGS_ASPMSTATE_MASK (0x0c) +#define MPI3_PCIESWITCH1_FLAGS_ASPMSTATE_SHIFT (2) +#define MPI3_PCIESWITCH1_FLAGS_ASPMSUPPORT_MASK (0x03) +#define MPI3_PCIESWITCH1_FLAGS_ASPMSUPPORT_SHIFT (0) +#ifndef MPI3_PCIESWITCH2_MAX_NUM_PORTS +#define MPI3_PCIESWITCH2_MAX_NUM_PORTS (1) +#endif +struct mpi3_pcieswitch2_port_element { + __le16 link_change_count; + __le16 rate_change_count; + __le32 reserved04; +}; + +struct mpi3_pcie_switch_page2 { + struct mpi3_config_page_header header; + u8 num_ports; + u8 reserved09; + __le16 dev_handle; + __le32 reserved0c; + struct mpi3_pcieswitch2_port_element port[MPI3_PCIESWITCH2_MAX_NUM_PORTS]; +}; + +#define MPI3_PCIESWITCH2_PAGEVERSION (0x00) struct mpi3_pcie_link_page0 { struct mpi3_config_page_header header; u8 link; u8 reserved09[3]; - __le32 correctable_error_count; - __le16 n_fatal_error_count; - __le16 reserved12; - __le16 fatal_error_count; - __le16 reserved16; + __le32 reserved0c; + __le32 receiver_error_count; + __le32 recovery_count; + __le32 corr_error_msg_count; + __le32 non_fatal_error_msg_count; + __le32 fatal_error_msg_count; + __le32 non_fatal_error_count; + __le32 fatal_error_count; + __le32 bad_dllp_count; + __le32 bad_tlp_count; }; #define MPI3_PCIELINK0_PAGEVERSION (0x00) @@ -1654,11 +1997,12 @@ struct mpi3_enclosure_page0 { __le16 flags; __le16 enclosure_handle; __le16 num_slots; - __le16 start_slot; + __le16 reserved16; u8 io_unit_port; u8 enclosure_level; __le16 sep_dev_handle; - __le32 reserved1c; + u8 chassis_slot; + u8 reserved1d[3]; }; #define MPI3_ENCLOSURE0_PAGEVERSION (0x00) @@ -1666,6 +2010,7 @@ struct mpi3_enclosure_page0 { #define MPI3_ENCLS0_FLAGS_ENCL_TYPE_VIRTUAL (0x0000) #define MPI3_ENCLS0_FLAGS_ENCL_TYPE_SAS (0x4000) #define MPI3_ENCLS0_FLAGS_ENCL_TYPE_PCIE (0x8000) +#define MPI3_ENCLS0_FLAGS_CHASSIS_SLOT_VALID (0x0020) #define MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK (0x0010) #define MPI3_ENCLS0_FLAGS_ENCL_DEV_NOT_FOUND (0x0000) #define MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT (0x0010) @@ -1686,6 +2031,7 @@ struct mpi3_device0_sas_sata_format { u8 zone_group; }; +#define MPI3_DEVICE0_SASSATA_FLAGS_WRITE_SAME_UNMAP_NCQ (0x0400) #define MPI3_DEVICE0_SASSATA_FLAGS_SLUMBER_CAP (0x0200) #define MPI3_DEVICE0_SASSATA_FLAGS_PARTIAL_CAP (0x0100) #define MPI3_DEVICE0_SASSATA_FLAGS_ASYNC_NOTIFY (0x0080) @@ -1707,10 +2053,11 @@ struct mpi3_device0_pcie_format { __le32 maximum_data_transfer_size; __le32 capabilities; __le16 noiob; - u8 nv_me_abort_to; + u8 nvme_abort_to; u8 page_size; __le16 shutdown_latency; - __le16 reserved16; + u8 recovery_info; + u8 reserved17; }; #define MPI3_DEVICE0_PCIE_LINK_RATE_32_0_SUPP (0x10) @@ -1718,16 +2065,38 @@ struct mpi3_device0_pcie_format { #define MPI3_DEVICE0_PCIE_LINK_RATE_8_0_SUPP (0x04) #define MPI3_DEVICE0_PCIE_LINK_RATE_5_0_SUPP (0x02) #define MPI3_DEVICE0_PCIE_LINK_RATE_2_5_SUPP (0x01) -#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK (0x0003) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK (0x0007) #define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NO_DEVICE (0x0000) #define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE (0x0001) #define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SWITCH_DEVICE (0x0002) #define MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE (0x0003) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_ASPM_MASK (0x0030) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_ASPM_SHIFT (4) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_MASK (0x00c0) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_SHIFT (6) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_0 (0x0000) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_1 (0x0040) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_2 (0x0080) +#define MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_3 (0x00c0) +#define MPI3_DEVICE0_PCIE_CAP_SGL_EXTRA_LENGTH_SUPPORTED (0x00000020) #define MPI3_DEVICE0_PCIE_CAP_METADATA_SEPARATED (0x00000010) #define MPI3_DEVICE0_PCIE_CAP_SGL_DWORD_ALIGN_REQUIRED (0x00000008) -#define MPI3_DEVICE0_PCIE_CAP_NVME_SGL_ENABLED (0x00000004) +#define MPI3_DEVICE0_PCIE_CAP_SGL_FORMAT_SGL (0x00000004) +#define MPI3_DEVICE0_PCIE_CAP_SGL_FORMAT_PRP (0x00000000) #define MPI3_DEVICE0_PCIE_CAP_BIT_BUCKET_SGL_SUPP (0x00000002) #define MPI3_DEVICE0_PCIE_CAP_SGL_SUPP (0x00000001) +#define MPI3_DEVICE0_PCIE_CAP_ASPM_MASK (0x000000c0) +#define MPI3_DEVICE0_PCIE_CAP_ASPM_SHIFT (6) +#define MPI3_DEVICE0_PCIE_RECOVER_METHOD_MASK (0xe0) +#define MPI3_DEVICE0_PCIE_RECOVER_METHOD_NS_MGMT (0x00) +#define MPI3_DEVICE0_PCIE_RECOVER_METHOD_FORMAT (0x20) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_MASK (0x1f) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_NO_NS (0x00) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_NO_NSID_1 (0x01) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_TOO_MANY_NS (0x02) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_PROTECTION (0x03) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_METADATA_SZ (0x04) +#define MPI3_DEVICE0_PCIE_RECOVER_REASON_LBA_DATA_SZ (0x05) struct mpi3_device0_vd_format { u8 vd_state; u8 raid_level; @@ -1783,6 +2152,8 @@ struct mpi3_device_page0 { }; #define MPI3_DEVICE0_PAGEVERSION (0x00) +#define MPI3_DEVICE0_PARENT_INVALID (0xffff) +#define MPI3_DEVICE0_ENCLOSURE_HANDLE_NO_ENCLOSURE (0x0000) #define MPI3_DEVICE0_WWID_INVALID (0xffffffffffffffff) #define MPI3_DEVICE0_PERSISTENTID_INVALID (0xffff) #define MPI3_DEVICE0_IOUNITPORT_INVALID (0xff) @@ -1792,9 +2163,13 @@ struct mpi3_device_page0 { #define MPI3_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x03) #define MPI3_DEVICE0_ASTATUS_UNAUTHORIZED (0x04) #define MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY (0x05) +#define MPI3_DEVICE0_ASTATUS_PREPARE (0x06) +#define MPI3_DEVICE0_ASTATUS_SAFE_MODE (0x07) +#define MPI3_DEVICE0_ASTATUS_GENERIC_MAX (0x0f) #define MPI3_DEVICE0_ASTATUS_SAS_UNKNOWN (0x10) #define MPI3_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x11) #define MPI3_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x12) +#define MPI3_DEVICE0_ASTATUS_SAS_MAX (0x1f) #define MPI3_DEVICE0_ASTATUS_SIF_UNKNOWN (0x20) #define MPI3_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x21) #define MPI3_DEVICE0_ASTATUS_SIF_DIAG (0x22) @@ -1810,6 +2185,8 @@ struct mpi3_device_page0 { #define MPI3_DEVICE0_ASTATUS_PCIE_MEM_SPACE_ACCESS (0x31) #define MPI3_DEVICE0_ASTATUS_PCIE_UNSUPPORTED (0x32) #define MPI3_DEVICE0_ASTATUS_PCIE_MSIX_REQUIRED (0x33) +#define MPI3_DEVICE0_ASTATUS_PCIE_ECRC_REQUIRED (0x34) +#define MPI3_DEVICE0_ASTATUS_PCIE_MAX (0x3f) #define MPI3_DEVICE0_ASTATUS_NVME_UNKNOWN (0x40) #define MPI3_DEVICE0_ASTATUS_NVME_READY_TIMEOUT (0x41) #define MPI3_DEVICE0_ASTATUS_NVME_DEVCFG_UNSUPPORTED (0x42) @@ -1820,7 +2197,17 @@ struct mpi3_device_page0 { #define MPI3_DEVICE0_ASTATUS_NVME_GET_FEATURE_STAT_FAILED (0x47) #define MPI3_DEVICE0_ASTATUS_NVME_IDLE_TIMEOUT (0x48) #define MPI3_DEVICE0_ASTATUS_NVME_CTRL_FAILURE_STATUS (0x49) -#define MPI3_DEVICE0_ASTATUS_VD_UNKNOWN (0x50) +#define MPI3_DEVICE0_ASTATUS_NVME_INSUFFICIENT_POWER (0x4a) +#define MPI3_DEVICE0_ASTATUS_NVME_DOORBELL_STRIDE (0x4b) +#define MPI3_DEVICE0_ASTATUS_NVME_MEM_PAGE_MIN_SIZE (0x4c) +#define MPI3_DEVICE0_ASTATUS_NVME_MEMORY_ALLOCATION (0x4d) +#define MPI3_DEVICE0_ASTATUS_NVME_COMPLETION_TIME (0x4e) +#define MPI3_DEVICE0_ASTATUS_NVME_BAR (0x4f) +#define MPI3_DEVICE0_ASTATUS_NVME_NS_DESCRIPTOR (0x50) +#define MPI3_DEVICE0_ASTATUS_NVME_INCOMPATIBLE_SETTINGS (0x51) +#define MPI3_DEVICE0_ASTATUS_NVME_MAX (0x5f) +#define MPI3_DEVICE0_ASTATUS_VD_UNKNOWN (0x80) +#define MPI3_DEVICE0_ASTATUS_VD_MAX (0x8f) #define MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE (0x0080) #define MPI3_DEVICE0_FLAGS_HIDDEN (0x0008) #define MPI3_DEVICE0_FLAGS_ATT_METHOD_MASK (0x0006) @@ -1870,11 +2257,17 @@ struct mpi3_device_page1 { struct mpi3_config_page_header header; __le16 dev_handle; __le16 reserved0a; - __le32 reserved0c[12]; + __le16 link_change_count; + __le16 rate_change_count; + __le16 tm_count; + __le16 reserved12; + __le32 reserved14[10]; u8 reserved3c[3]; u8 device_form; union mpi3_device1_dev_spec_format device_specific; }; #define MPI3_DEVICE1_PAGEVERSION (0x00) +#define MPI3_DEVICE1_COUNTER_MAX (0xfffe) +#define MPI3_DEVICE1_COUNTER_INVALID (0xffff) #endif diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index ce7550358599..e887d31d3007 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -860,7 +860,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, tgtdev->dev_spec.pcie_inf.reset_to = pcieinf->controller_reset_to; tgtdev->dev_spec.pcie_inf.abort_to = - pcieinf->nv_me_abort_to; + pcieinf->nvme_abort_to; } if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024)) tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024); -- cgit v1.2.3 From ec5ebd2c14a9123c0a8e2ae29202adf0ac242565 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:39 +0530 Subject: scsi: mpi3mr: Update MPI3 headers - part2 Continued updating MPI3 headers. Link: https://lore.kernel.org/r/20211220141159.16117-6-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi/mpi30_image.h | 59 +++++++++++++- drivers/scsi/mpi3mr/mpi/mpi30_init.h | 15 +++- drivers/scsi/mpi3mr/mpi/mpi30_ioc.h | 128 +++++++++++++++++++++++------- drivers/scsi/mpi3mr/mpi/mpi30_pci.h | 44 ++++++++++ drivers/scsi/mpi3mr/mpi/mpi30_sas.h | 14 ++++ drivers/scsi/mpi3mr/mpi/mpi30_transport.h | 31 +++++--- drivers/scsi/mpi3mr/mpi3mr.h | 5 +- drivers/scsi/mpi3mr/mpi3mr_fw.c | 26 +++--- 8 files changed, 261 insertions(+), 61 deletions(-) create mode 100644 drivers/scsi/mpi3mr/mpi/mpi30_pci.h diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_image.h b/drivers/scsi/mpi3mr/mpi/mpi30_image.h index 169e4f9b7b7c..c29b87de8e18 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_image.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_image.h @@ -61,6 +61,8 @@ struct mpi3_component_image_header { #define MPI3_IMAGE_HEADER_SIGNATURE1_SPD (0x20445053) #define MPI3_IMAGE_HEADER_SIGNATURE1_GAS_GAUGE (0x20534147) #define MPI3_IMAGE_HEADER_SIGNATURE1_PBLP (0x504c4250) +#define MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST (0x464e414d) +#define MPI3_IMAGE_HEADER_SIGNATURE1_OEM (0x204d454f) #define MPI3_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546) #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_MASK (0x00000030) #define MPI3_IMAGE_HEADER_FLAGS_DEVICE_KEY_BASIS_CDI (0x00000000) @@ -94,6 +96,61 @@ struct mpi3_component_image_header { #define MPI3_IMAGE_HEADER_HASH_EXCLUSION_OFFSET (0x5c) #define MPI3_IMAGE_HEADER_NEXT_IMAGE_HEADER_OFFSET_OFFSET (0x7c) #define MPI3_IMAGE_HEADER_SIZE (0x100) +#ifndef MPI3_CI_MANIFEST_MPI_MAX +#define MPI3_CI_MANIFEST_MPI_MAX (1) +#endif +struct mpi3_ci_manifest_mpi_comp_image_ref { + __le32 signature1; + __le32 reserved04[3]; + struct mpi3_comp_image_version component_image_version; + __le32 component_image_version_string_offset; + __le32 crc; +}; + +struct mpi3_ci_manifest_mpi { + u8 manifest_type; + u8 reserved01[3]; + __le32 reserved04[3]; + u8 num_image_references; + u8 release_level; + __le16 reserved12; + __le16 reserved14; + __le16 flags; + __le32 reserved18[2]; + __le16 vendor_id; + __le16 device_id; + __le16 subsystem_vendor_id; + __le16 subsystem_id; + __le32 reserved28[2]; + union mpi3_version_union package_security_version; + __le32 reserved34; + struct mpi3_comp_image_version package_version; + __le32 package_version_string_offset; + __le32 package_build_date_string_offset; + __le32 package_build_time_string_offset; + __le32 reserved4c; + __le32 diag_authorization_identifier[16]; + struct mpi3_ci_manifest_mpi_comp_image_ref component_image_ref[MPI3_CI_MANIFEST_MPI_MAX]; +}; + +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_DEV (0x00) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_PREALPHA (0x10) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_ALPHA (0x20) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_BETA (0x30) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_RC (0x40) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_GCA (0x50) +#define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_POINT (0x60) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTHORIZATION (0x01) +#define MPI3_CI_MANIFEST_MPI_SUBSYSTEMID_IGNORED (0xffff) +#define MPI3_CI_MANIFEST_MPI_PKG_VER_STR_OFF_UNSPECIFIED (0x00000000) +#define MPI3_CI_MANIFEST_MPI_PKG_BUILD_DATE_STR_OFF_UNSPECIFIED (0x00000000) +#define MPI3_CI_MANIFEST_MPI_PKG_BUILD_TIME_STR_OFF_UNSPECIFIED (0x00000000) +union mpi3_ci_manifest { + struct mpi3_ci_manifest_mpi mpi; + __le32 dword[1]; +}; + +#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) struct mpi3_extended_image_header { u8 image_type; u8 reserved01[3]; @@ -161,6 +218,7 @@ struct mpi3_encrypted_hash_entry { #define MPI3_HASH_ALGORITHM_SIZE_UNUSED (0x00) #define MPI3_HASH_ALGORITHM_SIZE_SHA256 (0x01) #define MPI3_HASH_ALGORITHM_SIZE_SHA512 (0x02) +#define MPI3_HASH_ALGORITHM_SIZE_SHA384 (0x03) #define MPI3_ENCRYPTION_ALGORITHM_UNUSED (0x00) #define MPI3_ENCRYPTION_ALGORITHM_RSA256 (0x01) #define MPI3_ENCRYPTION_ALGORITHM_RSA512 (0x02) @@ -178,7 +236,6 @@ struct mpi3_encrypted_key_with_hash_entry { u8 reserved03; __le32 reserved04; __le32 public_key[MPI3_PUBLIC_KEY_MAX]; - __le32 encrypted_hash[MPI3_ENCRYPTED_HASH_MAX]; }; #ifndef MPI3_ENCRYPTED_HASH_ENTRY_MAX diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_init.h b/drivers/scsi/mpi3mr/mpi/mpi30_init.h index e02b6d3cfba2..7a208dc81d49 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_init.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_init.h @@ -13,7 +13,7 @@ struct mpi3_scsi_io_cdb_eedp32 { __le32 transfer_length; }; -union mpi3_scso_io_cdb_union { +union mpi3_scsi_io_cdb_union { u8 cdb32[32]; struct mpi3_scsi_io_cdb_eedp32 eedp32; struct mpi3_sge_common sge; @@ -32,11 +32,12 @@ struct mpi3_scsi_io_request { __le32 skip_count; __le32 data_length; u8 lun[8]; - union mpi3_scso_io_cdb_union cdb; + union mpi3_scsi_io_cdb_union cdb; union mpi3_sge_union sgl[4]; }; #define MPI3_SCSIIO_MSGFLAGS_METASGL_VALID (0x80) +#define MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE (0x40) #define MPI3_SCSIIO_FLAGS_LARGE_CDB (0x60000000) #define MPI3_SCSIIO_FLAGS_CDB_16_OR_LESS (0x00000000) #define MPI3_SCSIIO_FLAGS_CDB_GREATER_THAN_16 (0x20000000) @@ -155,5 +156,13 @@ struct mpi3_scsi_task_mgmt_reply { __le32 reserved18; }; -#define MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC (0x80) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE (0x00) +#define MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME (0x02) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED (0x04) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED (0x05) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED (0x08) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN (0x09) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG (0x0a) +#define MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC (0x80) +#define MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED (0x81) #endif diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index 1af99a5382d5..bc56273778d3 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -29,10 +29,15 @@ struct mpi3_ioc_init_request { __le64 driver_information_address; }; -#define MPI3_WHOINIT_NOT_INITIALIZED (0x00) -#define MPI3_WHOINIT_ROM_BIOS (0x02) -#define MPI3_WHOINIT_HOST_DRIVER (0x03) -#define MPI3_WHOINIT_MANUFACTURER (0x04) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_MASK (0x03) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_NOT_USED (0x00) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SEPARATED (0x01) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_INLINE (0x02) +#define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_BOTH (0x03) +#define MPI3_WHOINIT_NOT_INITIALIZED (0x00) +#define MPI3_WHOINIT_ROM_BIOS (0x02) +#define MPI3_WHOINIT_HOST_DRIVER (0x03) +#define MPI3_WHOINIT_MANUFACTURER (0x04) struct mpi3_driver_info_layout { __le32 information_length; u8 driver_signature[12]; @@ -77,17 +82,17 @@ struct mpi3_ioc_facts_data { u8 sge_modifier_shift; u8 protocol_flags; __le16 max_sas_initiators; - __le16 max_sas_targets; + __le16 reserved2a; __le16 max_sas_expanders; __le16 max_enclosures; __le16 min_dev_handle; __le16 max_dev_handle; - __le16 max_pc_ie_switches; + __le16 max_pcie_switches; __le16 max_nvme; - __le16 max_pds; + __le16 reserved38; __le16 max_vds; __le16 max_host_pds; - __le16 max_advanced_host_pds; + __le16 max_adv_host_pds; __le16 max_raid_pds; __le16 max_posted_cmd_buffers; __le32 flags; @@ -97,26 +102,41 @@ struct mpi3_ioc_facts_data { __le16 reserved4e; __le32 diag_trace_size; __le32 diag_fw_size; + __le32 diag_driver_size; + u8 max_host_pd_ns_count; + u8 max_adv_host_pd_ns_count; + u8 max_raidpd_ns_count; + u8 reserved5f; }; -#define MPI3_IOCFACTS_CAPABILITY_ADVANCED_HOST_PD (0x00000010) +#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_MASK (0x80000000) +#define MPI3_IOCFACTS_CAPABILITY_SUPERVISOR_IOC (0x00000000) +#define MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC (0x10000000) +#define MPI3_IOCFACTS_CAPABILITY_COMPLETE_RESET_CAPABLE (0x00000100) +#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_ENABLED (0x00000080) +#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_FW_ENABLED (0x00000040) +#define MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_DRIVER_ENABLED (0x00000020) +#define MPI3_IOCFACTS_CAPABILITY_ADVANCED_HOST_PD_ENABLED (0x00000010) #define MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE (0x00000008) -#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_GRAN_MASK (0x00000001) -#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_IOC_GRAN (0x00000000) -#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_REPLY_Q_GRAN (0x00000001) +#define MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED (0x00000002) +#define MPI3_IOCFACTS_CAPABILITY_COALESCE_CTRL_SUPPORTED (0x00000001) #define MPI3_IOCFACTS_PID_TYPE_MASK (0xf000) #define MPI3_IOCFACTS_PID_TYPE_SHIFT (12) #define MPI3_IOCFACTS_PID_PRODUCT_MASK (0x0f00) #define MPI3_IOCFACTS_PID_PRODUCT_SHIFT (8) #define MPI3_IOCFACTS_PID_FAMILY_MASK (0x00ff) #define MPI3_IOCFACTS_PID_FAMILY_SHIFT (0) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_REKEY (0x2000) +#define MPI3_IOCFACTS_EXCEPT_SAS_DISABLED (0x1000) #define MPI3_IOCFACTS_EXCEPT_SAFE_MODE (0x0800) #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_MASK (0x0700) #define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_NONE (0x0000) -#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_RAID (0x0100) -#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_OOB (0x0200) -#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_RAID (0x0300) -#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_OOB (0x0400) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_MGMT (0x0100) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_MGMT (0x0200) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_DRIVE_EXT_VIA_MGMT (0x0300) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_LOCAL_VIA_OOB (0x0400) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_EXT_VIA_OOB (0x0500) +#define MPI3_IOCFACTS_EXCEPT_SECURITY_KEY_DRIVE_EXT_VIA_OOB (0x0600) #define MPI3_IOCFACTS_EXCEPT_PCIE_DISABLED (0x0080) #define MPI3_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0040) #define MPI3_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0020) @@ -175,6 +195,7 @@ struct mpi3_create_request_queue_request { #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_MASK (0x80) #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED (0x80) #define MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_CONTIGUOUS (0x00) +#define MPI3_CREATE_REQUEST_QUEUE_SIZE_MINIMUM (2) struct mpi3_delete_request_queue_request { __le16 host_tag; u8 ioc_use_only02; @@ -210,6 +231,7 @@ struct mpi3_create_reply_queue_request { #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_MASK (0x01) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_DISABLE (0x00) #define MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE (0x01) +#define MPI3_CREATE_REPLY_QUEUE_SIZE_MINIMUM (2) struct mpi3_delete_reply_queue_request { __le16 host_tag; u8 ioc_use_only02; @@ -255,7 +277,9 @@ struct mpi3_port_enable_request { #define MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR (0x19) #define MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST (0x20) #define MPI3_EVENT_PCIE_ENUMERATION (0x22) +#define MPI3_EVENT_PCIE_ERROR_THRESHOLD (0x23) #define MPI3_EVENT_HARD_RESET_RECEIVED (0x40) +#define MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE (0x50) #define MPI3_EVENT_MIN_PRODUCT_SPECIFIC (0x60) #define MPI3_EVENT_MAX_PRODUCT_SPECIFIC (0x7f) #define MPI3_EVENT_NOTIFY_EVENTMASK_WORDS (4) @@ -311,10 +335,9 @@ struct mpi3_event_data_temp_threshold { __le32 reserved0c; }; -#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD3_EXCEEDED (0x0008) -#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD2_EXCEEDED (0x0004) -#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD1_EXCEEDED (0x0002) -#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_THRESHOLD0_EXCEEDED (0x0001) +#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_FATAL_THRESHOLD_EXCEEDED (0x0004) +#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_CRITICAL_THRESHOLD_EXCEEDED (0x0002) +#define MPI3_EVENT_TEMP_THRESHOLD_STATUS_WARNING_THRESHOLD_EXCEEDED (0x0001) struct mpi3_event_data_cable_management { __le32 active_cable_power_requirement; u8 status; @@ -398,8 +421,10 @@ struct mpi3_event_data_sas_discovery { #define MPI3_SAS_DISC_STATUS_MAX_EXPANDERS_EXCEED (0x40000000) #define MPI3_SAS_DISC_STATUS_MAX_DEVICES_EXCEED (0x20000000) #define MPI3_SAS_DISC_STATUS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI3_SAS_DISC_STATUS_INVALID_CEI (0x00010000) +#define MPI3_SAS_DISC_STATUS_FECEI_MISMATCH (0x00008000) #define MPI3_SAS_DISC_STATUS_MULTIPLE_DEVICES_IN_SLOT (0x00004000) -#define MPI3_SAS_DISC_STATUS_SLOT_COUNT_MISMATCH (0x00002000) +#define MPI3_SAS_DISC_STATUS_NECEI_MISMATCH (0x00002000) #define MPI3_SAS_DISC_STATUS_TOO_MANY_SLOTS (0x00001000) #define MPI3_SAS_DISC_STATUS_EXP_MULTI_SUBTRACTIVE (0x00000800) #define MPI3_SAS_DISC_STATUS_MULTI_PORT_DOMAIN (0x00000400) @@ -581,6 +606,20 @@ struct mpi3_event_data_pcie_topology_change_list { #define MPI3_EVENT_PCIE_TOPO_SS_NOT_RESPONDING (0x02) #define MPI3_EVENT_PCIE_TOPO_SS_RESPONDING (0x03) #define MPI3_EVENT_PCIE_TOPO_SS_DELAY_NOT_RESPONDING (0x04) +struct mpi3_event_data_pcie_error_threshold { + __le64 timestamp; + u8 reason_code; + u8 port; + __le16 switch_dev_handle; + u8 error; + u8 action; + __le16 threshold_count; + __le16 attached_dev_handle; + __le16 reserved12; +}; + +#define MPI3_EVENT_PCI_ERROR_RC_THRESHOLD_EXCEEDED (0x00) +#define MPI3_EVENT_PCI_ERROR_RC_ESCALATION (0x01) struct mpi3_event_data_sas_init_dev_status_change { u8 reason_code; u8 io_unit_port; @@ -604,6 +643,16 @@ struct mpi3_event_data_hard_reset_received { __le16 reserved02; }; +struct mpi3_event_data_diag_buffer_status_change { + u8 type; + u8 reason_code; + __le16 reserved02; + __le32 reserved04; +}; + +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RELEASED (0x01) +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_PAUSED (0x02) +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RESUMED (0x03) #define MPI3_PEL_LOCALE_FLAGS_NON_BLOCKING_BOOT_EVENT (0x0200) #define MPI3_PEL_LOCALE_FLAGS_BLOCKING_BOOT_EVENT (0x0100) #define MPI3_PEL_LOCALE_FLAGS_PCIE (0x0080) @@ -645,21 +694,23 @@ struct mpi3_pel_seq { }; struct mpi3_pel_entry { + __le64 time_stamp; __le32 sequence_number; - __le32 time_stamp[2]; __le16 log_code; __le16 arg_type; __le16 locale; u8 class; - u8 reserved13; + u8 flags; u8 ext_num; u8 num_exts; u8 arg_data_size; - u8 fixed_format_size; + u8 fixed_format_strings_size; __le32 reserved18[2]; __le32 pel_info[24]; }; +#define MPI3_PEL_FLAGS_COMPLETE_RESET_NEEDED (0x02) +#define MPI3_PEL_FLAGS_ACK_NEEDED (0x01) struct mpi3_pel_list { __le32 log_count; __le32 reserved04; @@ -837,7 +888,10 @@ struct mpi3_pel_req_action_acknowledge { __le32 reserved10; }; -#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT (0x01) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_MASK (0x03) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_NO_GUIDANCE (0x00) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_CONTINUE_OP (0x01) +#define MPI3_PELACKNOWLEDGE_MSGFLAGS_SAFE_MODE_EXIT_TRANSITION_TO_FAULT (0x02) struct mpi3_pel_reply { __le16 host_tag; u8 ioc_use_only02; @@ -885,6 +939,7 @@ struct mpi3_ci_download_request { #define MPI3_CI_DOWNLOAD_ACTION_ONLINE_ACTIVATION (0x02) #define MPI3_CI_DOWNLOAD_ACTION_OFFLINE_ACTIVATION (0x03) #define MPI3_CI_DOWNLOAD_ACTION_GET_STATUS (0x04) +#define MPI3_CI_DOWNLOAD_ACTION_CANCEL_OFFLINE_ACTIVATION (0x05) struct mpi3_ci_download_reply { __le16 host_tag; u8 ioc_use_only02; @@ -902,6 +957,7 @@ struct mpi3_ci_download_reply { }; #define MPI3_CI_DOWNLOAD_FLAGS_DOWNLOAD_IN_PROGRESS (0x80) +#define MPI3_CI_DOWNLOAD_FLAGS_OFFLINE_ACTIVATION_REQUIRED (0x20) #define MPI3_CI_DOWNLOAD_FLAGS_KEY_UPDATE_PENDING (0x10) #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_MASK (0x0e) #define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_NOT_NEEDED (0x00) @@ -939,19 +995,28 @@ struct mpi3_ci_upload_request { #define MPI3_CTRL_OP_REMOVE_DEVICE (0x10) #define MPI3_CTRL_OP_CLOSE_PERSISTENT_CONNECTION (0x11) #define MPI3_CTRL_OP_HIDDEN_ACK (0x12) +#define MPI3_CTRL_OP_CLEAR_DEVICE_COUNTERS (0x13) #define MPI3_CTRL_OP_SAS_SEND_PRIMITIVE (0x20) -#define MPI3_CTRL_OP_SAS_CLEAR_ERROR_LOG (0x21) -#define MPI3_CTRL_OP_PCIE_CLEAR_ERROR_LOG (0x22) +#define MPI3_CTRL_OP_SAS_PHY_CONTROL (0x21) +#define MPI3_CTRL_OP_READ_INTERNAL_BUS (0x23) +#define MPI3_CTRL_OP_WRITE_INTERNAL_BUS (0x24) +#define MPI3_CTRL_OP_PCIE_LINK_CONTROL (0x30) #define MPI3_CTRL_OP_LOOKUP_MAPPING_PARAM8_LOOKUP_METHOD_INDEX (0x00) #define MPI3_CTRL_OP_UPDATE_TIMESTAMP_PARAM64_TIMESTAMP_INDEX (0x00) #define MPI3_CTRL_OP_REMOVE_DEVICE_PARAM16_DEVHANDLE_INDEX (0x00) #define MPI3_CTRL_OP_CLOSE_PERSIST_CONN_PARAM16_DEVHANDLE_INDEX (0x00) #define MPI3_CTRL_OP_HIDDEN_ACK_PARAM16_DEVHANDLE_INDEX (0x00) +#define MPI3_CTRL_OP_CLEAR_DEVICE_COUNTERS_PARAM16_DEVHANDLE_INDEX (0x00) #define MPI3_CTRL_OP_SAS_SEND_PRIM_PARAM8_PHY_INDEX (0x00) #define MPI3_CTRL_OP_SAS_SEND_PRIM_PARAM8_PRIMSEQ_INDEX (0x01) #define MPI3_CTRL_OP_SAS_SEND_PRIM_PARAM32_PRIMITIVE_INDEX (0x00) -#define MPI3_CTRL_OP_SAS_CLEAR_ERR_LOG_PARAM8_PHY_INDEX (0x00) -#define MPI3_CTRL_OP_PCIE_CLEAR_ERR_LOG_PARAM8_PHY_INDEX (0x00) +#define MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX (0x00) +#define MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX (0x01) +#define MPI3_CTRL_OP_READ_INTERNAL_BUS_PARAM64_ADDRESS_INDEX (0x00) +#define MPI3_CTRL_OP_WRITE_INTERNAL_BUS_PARAM64_ADDRESS_INDEX (0x00) +#define MPI3_CTRL_OP_WRITE_INTERNAL_BUS_PARAM32_VALUE_INDEX (0x00) +#define MPI3_CTRL_OP_PCIE_LINK_CONTROL_PARAM8_ACTION_INDEX (0x00) +#define MPI3_CTRL_OP_PCIE_LINK_CONTROL_PARAM8_LINK_INDEX (0x01) #define MPI3_CTRL_LOOKUP_METHOD_WWID_ADDRESS (0x01) #define MPI3_CTRL_LOOKUP_METHOD_ENCLOSURE_SLOT (0x02) #define MPI3_CTRL_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) @@ -966,9 +1031,14 @@ struct mpi3_ci_upload_request { #define MPI3_CTRL_LOOKUP_METHOD_PERSISTID_PARAM16_PERSISTENT_ID_INDEX (1) #define MPI3_CTRL_LOOKUP_METHOD_VALUE16_DEVH_INDEX (0) #define MPI3_CTRL_GET_TIMESTAMP_VALUE64_TIMESTAMP_INDEX (0) +#define MPI3_CTRL_READ_INTERNAL_BUS_VALUE32_VALUE_INDEX (0) #define MPI3_CTRL_PRIMFLAGS_SINGLE (0x01) #define MPI3_CTRL_PRIMFLAGS_TRIPLE (0x03) #define MPI3_CTRL_PRIMFLAGS_REDUNDANT (0x06) +#define MPI3_CTRL_ACTION_NOP (0x00) +#define MPI3_CTRL_ACTION_LINK_RESET (0x01) +#define MPI3_CTRL_ACTION_HARD_RESET (0x02) +#define MPI3_CTRL_ACTION_CLEAR_ERROR_LOG (0x05) struct mpi3_iounit_control_request { __le16 host_tag; u8 ioc_use_only02; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h new file mode 100644 index 000000000000..dbfaf4137560 --- /dev/null +++ b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright 2016-2021 Broadcom Inc. All rights reserved. + * + */ +#ifndef MPI30_PCI_H +#define MPI30_PCI_H 1 +#ifndef MPI3_NVME_ENCAP_CMD_MAX +#define MPI3_NVME_ENCAP_CMD_MAX (1) +#endif +struct mpi3_nvme_encapsulated_request { + __le16 host_tag; + u8 ioc_use_only02; + u8 function; + __le16 ioc_use_only04; + u8 ioc_use_only06; + u8 msg_flags; + __le16 change_count; + __le16 dev_handle; + __le16 encapsulated_command_length; + __le16 flags; + __le32 reserved10[4]; + __le32 command[MPI3_NVME_ENCAP_CMD_MAX]; +}; + +#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_MASK (0x0002) +#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_FAIL_ONLY (0x0000) +#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_ALL (0x0002) +#define MPI3_NVME_FLAGS_SUBMISSIONQ_MASK (0x0001) +#define MPI3_NVME_FLAGS_SUBMISSIONQ_IO (0x0000) +#define MPI3_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0001) +struct mpi3_nvme_encapsulated_error_reply { + __le16 host_tag; + u8 ioc_use_only02; + u8 function; + __le16 ioc_use_only04; + u8 ioc_use_only06; + u8 msg_flags; + __le16 ioc_use_only08; + __le16 ioc_status; + __le32 ioc_log_info; + __le32 nvme_completion_entry[4]; +}; +#endif diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h index ba5018702960..298d895e374b 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h @@ -30,4 +30,18 @@ struct mpi3_smp_passthrough_request { struct mpi3_sge_common request_sge; struct mpi3_sge_common response_sge; }; + +struct mpi3_smp_passthrough_reply { + __le16 host_tag; + u8 ioc_use_only02; + u8 function; + __le16 ioc_use_only04; + u8 ioc_use_only06; + u8 msg_flags; + __le16 ioc_use_only08; + __le16 ioc_status; + __le32 ioc_log_info; + __le16 response_data_length; + __le16 reserved12; +}; #endif diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h index 63e4e81d5397..6d550117ec2e 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h @@ -19,8 +19,8 @@ union mpi3_version_union { #define MPI3_VERSION_MAJOR (3) #define MPI3_VERSION_MINOR (0) -#define MPI3_VERSION_UNIT (0) -#define MPI3_VERSION_DEV (18) +#define MPI3_VERSION_UNIT (22) +#define MPI3_VERSION_DEV (0) struct mpi3_sysif_oper_queue_indexes { __le16 producer_index; __le16 reserved02; @@ -74,6 +74,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_IOC_INFO_HIGH_OFFSET (0x00000004) #define MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK (0xff000000) #define MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT (24) +#define MPI3_SYSIF_IOC_INFO_LOW_HCB_DISABLED (0x00000001) #define MPI3_SYSIF_IOC_CONFIG_OFFSET (0x00000014) #define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ (0x00f00000) #define MPI3_SYSIF_IOC_CONFIG_OPER_RPY_ENT_SZ_SHIFT (20) @@ -82,12 +83,13 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_MASK (0x0000c000) #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NO (0x00000000) #define MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL (0x00004000) -#define MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN (0x00002000) +#define MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ (0x00002000) #define MPI3_SYSIF_IOC_CONFIG_DIAG_SAVE (0x00000010) #define MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC (0x00000001) #define MPI3_SYSIF_IOC_STATUS_OFFSET (0x0000001c) #define MPI3_SYSIF_IOC_STATUS_RESET_HISTORY (0x00000010) #define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK (0x0000000c) +#define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_SHIFT (0x00000002) #define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_NONE (0x00000000) #define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS (0x00000004) #define MPI3_SYSIF_IOC_STATUS_SHUTDOWN_COMPLETE (0x00000008) @@ -107,9 +109,9 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_NO_CHANGE (0x00000000) #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_DISABLE (0x40000000) #define MPI3_SYSIF_COALESCE_CONTROL_ENABLE_ENABLE (0xc0000000) -#define MPI3_SYSIF_COALESCE_CONTROL_VALID (0x30000000) -#define MPI3_SYSIF_COALESCE_CONTROL_QUEUE_ID_MASK (0x00ff0000) -#define MPI3_SYSIF_COALESCE_CONTROL_QUEUE_ID_SHIFT (16) +#define MPI3_SYSIF_COALESCE_CONTROL_VALID (0x20000000) +#define MPI3_SYSIF_COALESCE_CONTROL_MSIX_IDX_MASK (0x01ff0000) +#define MPI3_SYSIF_COALESCE_CONTROL_MSIX_IDX_SHIFT (16) #define MPI3_SYSIF_COALESCE_CONTROL_TIMEOUT_MASK (0x0000ff00) #define MPI3_SYSIF_COALESCE_CONTROL_TIMEOUT_SHIFT (8) #define MPI3_SYSIF_COALESCE_CONTROL_DEPTH_MASK (0x000000ff) @@ -117,9 +119,9 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_ADMIN_REQ_Q_PI_OFFSET (0x00001000) #define MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET (0x00001004) #define MPI3_SYSIF_OPER_REQ_Q_PI_OFFSET (0x00001008) -#define MPI3_SYSIF_OPER_REQ_Q_N_PI_OFFSET(n) (MPI3_SYSIF_OPER_REQ_Q_PI_OFFSET + (((n) - 1) * 8)) +#define MPI3_SYSIF_OPER_REQ_Q_N_PI_OFFSET(N) (MPI3_SYSIF_OPER_REQ_Q_PI_OFFSET + (((N) - 1) * 8)) #define MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET (0x0000100c) -#define MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(n) (MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET + (((n) - 1) * 8)) +#define MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(N) (MPI3_SYSIF_OPER_REPLY_Q_CI_OFFSET + (((N) - 1) * 8)) #define MPI3_SYSIF_WRITE_SEQUENCE_OFFSET (0x00001c04) #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_MASK (0x0000000f) #define MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH (0x0) @@ -133,7 +135,7 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_MASK (0x00000700) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_NO_RESET (0x00000000) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET (0x00000100) -#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_FLASH_RCVRY_RESET (0x00000200) +#define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_HOST_CONTROL_BOOT_RESET (0x00000200) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_COMPLETE_RESET (0x00000300) #define MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT (0x00000700) #define MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS (0x00000080) @@ -153,8 +155,9 @@ struct mpi3_sysif_registers { #define MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET (0x0000f001) #define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS (0x0000f002) #define MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED (0x0000f003) -#define MPI3_SYSIF_FAULT_CODE_SAFE_MODE_EXIT (0x0000f004) -#define MPI3_SYSIF_FAULT_CODE_FACTORY_RESET (0x0000f005) +#define MPI3_SYSIF_FAULT_CODE_SOFT_RESET_NEEDED (0x0000f004) +#define MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED (0x0000f005) +#define MPI3_SYSIF_FAULT_CODE_TEMP_THRESHOLD_EXCEEDED (0x0000f006) #define MPI3_SYSIF_FAULT_INFO0_OFFSET (0x00001c14) #define MPI3_SYSIF_FAULT_INFO1_OFFSET (0x00001c18) #define MPI3_SYSIF_FAULT_INFO2_OFFSET (0x00001c1c) @@ -409,6 +412,8 @@ struct mpi3_default_reply { #define MPI3_IOCSTATUS_INVALID_STATE (0x0008) #define MPI3_IOCSTATUS_INSUFFICIENT_POWER (0x000a) #define MPI3_IOCSTATUS_INVALID_CHANGE_COUNT (0x000b) +#define MPI3_IOCSTATUS_ALLOWED_CMD_BLOCK (0x000c) +#define MPI3_IOCSTATUS_SUPERVISOR_ONLY (0x000d) #define MPI3_IOCSTATUS_FAILURE (0x001f) #define MPI3_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) #define MPI3_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) @@ -448,8 +453,10 @@ struct mpi3_default_reply { #define MPI3_IOCSTATUS_CI_UNSUPPORTED (0x00b0) #define MPI3_IOCSTATUS_CI_UPDATE_SEQUENCE (0x00b1) #define MPI3_IOCSTATUS_CI_VALIDATION_FAILED (0x00b2) -#define MPI3_IOCSTATUS_CI_UPDATE_PENDING (0x00b3) +#define MPI3_IOCSTATUS_CI_KEY_UPDATE_PENDING (0x00b3) +#define MPI3_IOCSTATUS_CI_KEY_UPDATE_NOT_POSSIBLE (0x00b4) #define MPI3_IOCSTATUS_SECURITY_KEY_REQUIRED (0x00c0) +#define MPI3_IOCSTATUS_SECURITY_VIOLATION (0x00c1) #define MPI3_IOCSTATUS_INVALID_QUEUE_ID (0x0f00) #define MPI3_IOCSTATUS_INVALID_QUEUE_SIZE (0x0f01) #define MPI3_IOCSTATUS_INVALID_MSIX_VECTOR (0x0f02) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 9787b53a2b59..cdbd1cb44d97 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -45,6 +45,7 @@ #include "mpi/mpi30_init.h" #include "mpi/mpi30_ioc.h" #include "mpi/mpi30_sas.h" +#include "mpi/mpi30_pci.h" #include "mpi3mr_debug.h" /* Global list and lock for storing multiple adapters managed by the driver */ @@ -121,7 +122,7 @@ extern int prot_mask; /* Definitions for Event replies and sense buffer allocated per controller */ #define MPI3MR_NUM_EVT_REPLIES 64 -#define MPI3MR_SENSEBUF_SZ 256 +#define MPI3MR_SENSE_BUF_SZ 256 #define MPI3MR_SENSEBUF_FACTOR 3 #define MPI3MR_CHAINBUF_FACTOR 3 #define MPI3MR_CHAINBUFDIX_FACTOR 2 @@ -263,7 +264,7 @@ struct mpi3mr_ioc_facts { u16 max_vds; u16 max_hpds; u16 max_advhpds; - u16 max_raidpds; + u16 max_raid_pds; u16 min_devhandle; u16 max_devhandle; u16 max_op_req_q; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 4ce79d7dad66..12d510629513 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -2012,7 +2012,7 @@ static void mpi3mr_watchdog_work(struct work_struct *work) mpi3mr_print_fault_info(mrioc); mrioc->diagsave_timeout = 0; - if (fault == MPI3_SYSIF_FAULT_CODE_FACTORY_RESET) { + if (fault == MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED) { ioc_info(mrioc, "Factory Reset fault occurred marking controller as unrecoverable" ); @@ -2377,14 +2377,13 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, mrioc->facts.reply_sz = le16_to_cpu(facts_data->reply_frame_size) * 4; mrioc->facts.exceptions = le16_to_cpu(facts_data->ioc_exceptions); mrioc->facts.max_perids = le16_to_cpu(facts_data->max_persistent_id); - mrioc->facts.max_pds = le16_to_cpu(facts_data->max_pds); mrioc->facts.max_vds = le16_to_cpu(facts_data->max_vds); mrioc->facts.max_hpds = le16_to_cpu(facts_data->max_host_pds); - mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_advanced_host_pds); - mrioc->facts.max_raidpds = le16_to_cpu(facts_data->max_raid_pds); + mrioc->facts.max_advhpds = le16_to_cpu(facts_data->max_adv_host_pds); + mrioc->facts.max_raid_pds = le16_to_cpu(facts_data->max_raid_pds); mrioc->facts.max_nvme = le16_to_cpu(facts_data->max_nvme); mrioc->facts.max_pcie_switches = - le16_to_cpu(facts_data->max_pc_ie_switches); + le16_to_cpu(facts_data->max_pcie_switches); mrioc->facts.max_sasexpanders = le16_to_cpu(facts_data->max_sas_expanders); mrioc->facts.max_sasinitiators = @@ -2418,10 +2417,9 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, mrioc->facts.ioc_num, mrioc->facts.max_op_req_q, mrioc->facts.max_op_reply_q, mrioc->facts.max_devhandle); ioc_info(mrioc, - "maxreqs(%d), mindh(%d) maxPDs(%d) maxvectors(%d) maxperids(%d)\n", + "maxreqs(%d), mindh(%d) maxvectors(%d) maxperids(%d)\n", mrioc->facts.max_reqs, mrioc->facts.min_devhandle, - mrioc->facts.max_pds, mrioc->facts.max_msix_vectors, - mrioc->facts.max_perids); + mrioc->facts.max_msix_vectors, mrioc->facts.max_perids); ioc_info(mrioc, "SGEModMask 0x%x SGEModVal 0x%x SGEModShift 0x%x ", mrioc->facts.sge_mod_mask, mrioc->facts.sge_mod_value, mrioc->facts.sge_mod_shift); @@ -2520,7 +2518,7 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) goto out_failed; /* sense buffer pool, 4 byte align */ - sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ; + sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; mrioc->sense_buf_pool = dma_pool_create("sense_buf pool", &mrioc->pdev->dev, sz, 4, 0); if (!mrioc->sense_buf_pool) { @@ -2556,10 +2554,10 @@ post_reply_sbuf: "reply_free_q pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", mrioc->reply_free_q, mrioc->reply_free_qsz, 8, (sz / 1024), (unsigned long long)mrioc->reply_free_q_dma); - sz = mrioc->num_sense_bufs * MPI3MR_SENSEBUF_SZ; + sz = mrioc->num_sense_bufs * MPI3MR_SENSE_BUF_SZ; ioc_info(mrioc, "sense_buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), sense_dma(0x%llx)\n", - mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSEBUF_SZ, + mrioc->sense_buf, mrioc->num_sense_bufs, MPI3MR_SENSE_BUF_SZ, (sz / 1024), (unsigned long long)mrioc->sense_buf_dma); sz = mrioc->sense_buf_q_sz * 8; ioc_info(mrioc, @@ -2575,7 +2573,7 @@ post_reply_sbuf: /* initialize Sense Buffer Queue */ for (i = 0, phy_addr = mrioc->sense_buf_dma; - i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSEBUF_SZ) + i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ) mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr); mrioc->sense_buf_q[i] = cpu_to_le64(0); return retval; @@ -2642,7 +2640,7 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) iocinit_req.reply_free_queue_depth = cpu_to_le16(mrioc->reply_free_qsz); iocinit_req.reply_free_queue_address = cpu_to_le64(mrioc->reply_free_q_dma); - iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSEBUF_SZ); + iocinit_req.sense_buffer_length = cpu_to_le16(MPI3MR_SENSE_BUF_SZ); iocinit_req.sense_buffer_free_queue_depth = cpu_to_le16(mrioc->sense_buf_q_sz); iocinit_req.sense_buffer_free_queue_address = @@ -3667,7 +3665,7 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); ioc_config |= MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL; - ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN; + ioc_config |= MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ; writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); -- cgit v1.2.3 From 17d6b9cf89cfdb5a52298bb4abe7f1621f92ba93 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:40 +0530 Subject: scsi: mpi3mr: Add support for PCIe Managed Switch SES device The SAS4 Controller firmware exposes the SES devices in Managed PCIe Switch as a PCIe Device Type SCSI Device (MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE). Driver is enhanced to handle this device type by: - Exposing the device to the upper layers and - Not updating any hardware sectors & virtual boundary settings as these settings are needed only for NVMe devices. Link: https://lore.kernel.org/r/20211220141159.16117-7-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 3 +++ drivers/scsi/mpi3mr/mpi3mr_os.c | 40 +++++++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index cdbd1cb44d97..fe3cfd5c2823 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -147,6 +147,7 @@ extern int prot_mask; MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC #define MPI3MR_DEFAULT_MDTS (128 * 1024) +#define MPI3MR_DEFAULT_PGSZEXP (12) /* Command retry count definitions */ #define MPI3MR_DEV_RMHS_RETRY_COUNT 3 @@ -389,6 +390,7 @@ struct tgt_dev_sas_sata { * @pgsz: Device page size * @abort_to: Timeout for abort TM * @reset_to: Timeout for Target/LUN reset TM + * @dev_info: Device information bits */ struct tgt_dev_pcie { u32 mdts; @@ -396,6 +398,7 @@ struct tgt_dev_pcie { u8 pgsz; u8 abort_to; u8 reset_to; + u16 dev_info; }; /** diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index e887d31d3007..14621dc604ce 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -742,11 +742,18 @@ mpi3mr_update_sdev(struct scsi_device *sdev, void *data) switch (tgtdev->dev_type) { case MPI3_DEVICE_DEVFORM_PCIE: /*The block layer hw sector size = 512*/ - blk_queue_max_hw_sectors(sdev->request_queue, - tgtdev->dev_spec.pcie_inf.mdts / 512); - blk_queue_virt_boundary(sdev->request_queue, - ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1)); - + if ((tgtdev->dev_spec.pcie_inf.dev_info & + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { + blk_queue_max_hw_sectors(sdev->request_queue, + tgtdev->dev_spec.pcie_inf.mdts / 512); + if (tgtdev->dev_spec.pcie_inf.pgsz == 0) + blk_queue_virt_boundary(sdev->request_queue, + ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); + else + blk_queue_virt_boundary(sdev->request_queue, + ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1)); + } break; default: break; @@ -848,6 +855,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, &dev_pg0->device_specific.pcie_format; u16 dev_info = le16_to_cpu(pcieinf->device_info); + tgtdev->dev_spec.pcie_inf.dev_info = dev_info; tgtdev->dev_spec.pcie_inf.capb = le32_to_cpu(pcieinf->capabilities); tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS; @@ -864,8 +872,10 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, } if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024)) tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024); - if ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != - MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) + if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) && + ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) != + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE)) tgtdev->is_hidden = 1; if (!mrioc->shost) break; @@ -3190,10 +3200,18 @@ static int mpi3mr_slave_configure(struct scsi_device *sdev) switch (tgt_dev->dev_type) { case MPI3_DEVICE_DEVFORM_PCIE: /*The block layer hw sector size = 512*/ - blk_queue_max_hw_sectors(sdev->request_queue, - tgt_dev->dev_spec.pcie_inf.mdts / 512); - blk_queue_virt_boundary(sdev->request_queue, - ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1)); + if ((tgt_dev->dev_spec.pcie_inf.dev_info & + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { + blk_queue_max_hw_sectors(sdev->request_queue, + tgt_dev->dev_spec.pcie_inf.mdts / 512); + if (tgt_dev->dev_spec.pcie_inf.pgsz == 0) + blk_queue_virt_boundary(sdev->request_queue, + ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); + else + blk_queue_virt_boundary(sdev->request_queue, + ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1)); + } break; default: break; -- cgit v1.2.3 From ba68779a518d9ebe734c1fca9f5e199826723b5b Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:41 +0530 Subject: scsi: mpi3mr: Do access status validation before adding devices Add validation for various access statuses prior to exposing attached target device to the operating system. Link: https://lore.kernel.org/r/20211220141159.16117-8-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 14621dc604ce..2fe7fcbe21d1 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -831,6 +831,17 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, scsi_tgt_priv_data->dev_type = tgtdev->dev_type; } + switch (dev_pg0->access_status) { + case MPI3_DEVICE0_ASTATUS_NO_ERRORS: + case MPI3_DEVICE0_ASTATUS_PREPARE: + case MPI3_DEVICE0_ASTATUS_NEEDS_INITIALIZATION: + case MPI3_DEVICE0_ASTATUS_DEVICE_MISSING_DELAY: + break; + default: + tgtdev->is_hidden = 1; + break; + } + switch (tgtdev->dev_type) { case MPI3_DEVICE_DEVFORM_SAS_SATA: { -- cgit v1.2.3 From 4f08b9637f639fed9c36fde4e238274c47ca5f53 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:42 +0530 Subject: scsi: mpi3mr: Increase internal cmnds timeout to 60s - Increase internal command timeout to 60 seconds. - Enable 16 device removal handshake processing in parallel in the device removal handshake infrastructure. Link: https://lore.kernel.org/r/20211220141159.16117-9-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 8 ++++---- drivers/scsi/mpi3mr/mpi3mr_os.c | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index fe3cfd5c2823..fdbedf23b112 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -91,7 +91,7 @@ extern int prot_mask; #define MPI3MR_HOSTTAG_IOCTLCMDS 2 #define MPI3MR_HOSTTAG_BLK_TMS 5 -#define MPI3MR_NUM_DEVRMCMD 1 +#define MPI3MR_NUM_DEVRMCMD 16 #define MPI3MR_HOSTTAG_DEVRMCMD_MIN (MPI3MR_HOSTTAG_BLK_TMS + 1) #define MPI3MR_HOSTTAG_DEVRMCMD_MAX (MPI3MR_HOSTTAG_DEVRMCMD_MIN + \ MPI3MR_NUM_DEVRMCMD - 1) @@ -102,10 +102,10 @@ extern int prot_mask; #define MPI3MR_HOST_IOS_KDUMP 128 /* command/controller interaction timeout definitions in seconds */ -#define MPI3MR_INTADMCMD_TIMEOUT 10 +#define MPI3MR_INTADMCMD_TIMEOUT 60 #define MPI3MR_PORTENABLE_TIMEOUT 300 -#define MPI3MR_ABORTTM_TIMEOUT 30 -#define MPI3MR_RESETTM_TIMEOUT 30 +#define MPI3MR_ABORTTM_TIMEOUT 60 +#define MPI3MR_RESETTM_TIMEOUT 60 #define MPI3MR_RESET_HOST_IOWAIT_TIMEOUT 5 #define MPI3MR_TSUPDATE_INTERVAL 900 #define MPI3MR_DEFAULT_SHUTDOWN_TIME 120 diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 2fe7fcbe21d1..e961bb200557 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -877,9 +877,11 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, le32_to_cpu(pcieinf->maximum_data_transfer_size); tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size; tgtdev->dev_spec.pcie_inf.reset_to = - pcieinf->controller_reset_to; + max_t(u8, pcieinf->controller_reset_to, + MPI3MR_INTADMCMD_TIMEOUT); tgtdev->dev_spec.pcie_inf.abort_to = - pcieinf->nvme_abort_to; + max_t(u8, pcieinf->nvme_abort_to, + MPI3MR_INTADMCMD_TIMEOUT); } if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024)) tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024); @@ -3597,6 +3599,7 @@ static struct scsi_host_template mpi3mr_driver_template = { */ .max_sectors = 2048, .cmd_per_lun = MPI3MR_MAX_CMDS_LUN, + .max_segment_size = 0xffffffff, .track_queue_depth = 1, .cmd_size = sizeof(struct scmd_priv), }; -- cgit v1.2.3 From 13fd7b1555b6c1121c0f823bbfa3ee36e178df44 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:43 +0530 Subject: scsi: mpi3mr: Handle unaligned PLL in unmap cmnds The following special handling is needed for UNMAP commands issued to NVMe drives: - On B0 boards, if the parameter list length is greater than 24 and not a 16-byte multiple, then truncate the parameter list length to a 16-byte multiple. - On A0 boards, if the parameter list length is greater than block descriptor data length + 8, then truncate the parameter list length to block descriptor data length + 8 value. Link: https://lore.kernel.org/r/20211220141159.16117-10-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index e961bb200557..2a153df0f803 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -3344,9 +3344,22 @@ static bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc, struct scsi_cmnd *scmd) { unsigned char *buf; - u16 param_len, desc_len; - - param_len = get_unaligned_be16(scmd->cmnd + 7); + u16 param_len, desc_len, trunc_param_len; + + trunc_param_len = param_len = get_unaligned_be16(scmd->cmnd + 7); + + if (mrioc->pdev->revision) { + if ((param_len > 24) && ((param_len - 8) & 0xF)) { + trunc_param_len -= (param_len - 8) & 0xF; + dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR); + dprint_scsi_err(mrioc, + "truncating param_len from (%d) to (%d)\n", + param_len, trunc_param_len); + put_unaligned_be16(trunc_param_len, scmd->cmnd + 7); + dprint_scsi_command(mrioc, scmd, MPI3_DEBUG_SCSI_ERROR); + } + return false; + } if (!param_len) { ioc_warn(mrioc, @@ -3406,12 +3419,12 @@ static bool mpi3mr_check_return_unmap(struct mpi3mr_ioc *mrioc, } if (param_len > (desc_len + 8)) { + trunc_param_len = desc_len + 8; scsi_print_command(scmd); - ioc_warn(mrioc, - "%s: Truncating param_len(%d) to desc_len+8(%d)\n", - __func__, param_len, (desc_len + 8)); - param_len = desc_len + 8; - put_unaligned_be16(param_len, scmd->cmnd + 7); + dprint_scsi_err(mrioc, + "truncating param_len(%d) to desc_len+8(%d)\n", + param_len, trunc_param_len); + put_unaligned_be16(trunc_param_len, scmd->cmnd + 7); scsi_print_command(scmd); } @@ -3466,6 +3479,7 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost, u32 scsiio_flags = 0; struct request *rq = scsi_cmd_to_rq(scmd); int iprio_class; + u8 is_pcie_dev = 0; sdev_priv_data = scmd->device->hostdata; if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) { @@ -3510,8 +3524,10 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost, goto out; } - if ((scmd->cmnd[0] == UNMAP) && - (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE) && + if (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE) + is_pcie_dev = 1; + if ((scmd->cmnd[0] == UNMAP) && is_pcie_dev && + (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && mpi3mr_check_return_unmap(mrioc, scmd)) goto out; -- cgit v1.2.3 From 2ac794baaec97c70faf17b56fba4adefd6b7ba3a Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:44 +0530 Subject: scsi: mpi3mr: Display IOC firmware package version Display IOC firmware package version by reading component image upload data. Link: https://lore.kernel.org/r/20211220141159.16117-11-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 89 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 12d510629513..6b534ed0ecf8 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1971,6 +1971,89 @@ out: return retval; } +/** + * mpi3mr_print_pkg_ver - display controller fw package version + * @mrioc: Adapter reference + * + * Retrieve firmware package version from the component image + * header of the controller flash and display it. + * + * Return: 0 on success and non-zero on failure. + */ +static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc) +{ + struct mpi3_ci_upload_request ci_upload; + int retval = -1; + void *data = NULL; + dma_addr_t data_dma; + struct mpi3_ci_manifest_mpi *manifest; + u32 data_len = sizeof(struct mpi3_ci_manifest_mpi); + u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; + + data = dma_alloc_coherent(&mrioc->pdev->dev, data_len, &data_dma, + GFP_KERNEL); + if (!data) + return -ENOMEM; + + memset(&ci_upload, 0, sizeof(ci_upload)); + mutex_lock(&mrioc->init_cmds.mutex); + if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { + ioc_err(mrioc, "sending get package version failed due to command in use\n"); + mutex_unlock(&mrioc->init_cmds.mutex); + goto out; + } + mrioc->init_cmds.state = MPI3MR_CMD_PENDING; + mrioc->init_cmds.is_waiting = 1; + mrioc->init_cmds.callback = NULL; + ci_upload.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); + ci_upload.function = MPI3_FUNCTION_CI_UPLOAD; + ci_upload.msg_flags = MPI3_CI_UPLOAD_MSGFLAGS_LOCATION_PRIMARY; + ci_upload.signature1 = cpu_to_le32(MPI3_IMAGE_HEADER_SIGNATURE1_MANIFEST); + ci_upload.image_offset = cpu_to_le32(MPI3_IMAGE_HEADER_SIZE); + ci_upload.segment_size = cpu_to_le32(data_len); + + mpi3mr_add_sg_single(&ci_upload.sgl, sgl_flags, data_len, + data_dma); + init_completion(&mrioc->init_cmds.done); + retval = mpi3mr_admin_request_post(mrioc, &ci_upload, + sizeof(ci_upload), 1); + if (retval) { + ioc_err(mrioc, "posting get package version failed\n"); + goto out_unlock; + } + wait_for_completion_timeout(&mrioc->init_cmds.done, + (MPI3MR_INTADMCMD_TIMEOUT * HZ)); + if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + ioc_err(mrioc, "get package version timed out\n"); + retval = -1; + goto out_unlock; + } + if ((mrioc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) + == MPI3_IOCSTATUS_SUCCESS) { + manifest = (struct mpi3_ci_manifest_mpi *) data; + if (manifest->manifest_type == MPI3_CI_MANIFEST_TYPE_MPI) { + ioc_info(mrioc, + "firmware package version(%d.%d.%d.%d.%05d-%05d)\n", + manifest->package_version.gen_major, + manifest->package_version.gen_minor, + manifest->package_version.phase_major, + manifest->package_version.phase_minor, + manifest->package_version.customer_id, + manifest->package_version.build_num); + } + } + retval = 0; +out_unlock: + mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; + mutex_unlock(&mrioc->init_cmds.mutex); + +out: + if (data) + dma_free_coherent(&mrioc->pdev->dev, data_len, data, + data_dma); + return retval; +} + /** * mpi3mr_watchdog_work - watchdog thread to monitor faults * @work: work struct @@ -3362,6 +3445,12 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) writel(mrioc->sbq_host_index, &mrioc->sysif_regs->sense_buffer_free_host_index); + retval = mpi3mr_print_pkg_ver(mrioc); + if (retval) { + ioc_err(mrioc, "failed to get package version\n"); + goto out_failed; + } + if (init_type != MPI3MR_IT_RESET) { retval = mpi3mr_setup_isr(mrioc, 0); if (retval) { -- cgit v1.2.3 From a6856cc4507be044497fcde48aa3d33e900cbc45 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:45 +0530 Subject: scsi: mpi3mr: Fault IOC when internal command gets timeout Save snapdump and fault the controller with the given reason code if it is already not in the fault or not in asynchronous reset. This ensures that soft reset is issued from the watchdog thread. This will also be used to handle initialization time faults/resets/timeout as in those cases immediate soft reset invocation is not required. Link: https://lore.kernel.org/r/20211220141159.16117-12-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 1 + drivers/scsi/mpi3mr/mpi3mr_fw.c | 114 +++++++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index fdbedf23b112..55a07f9c8807 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -916,5 +916,6 @@ void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc); void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc); void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc); void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc); +void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); #endif /*MPI3MR_H_INCLUDED*/ diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 6b534ed0ecf8..b6d4e9d2961a 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1391,13 +1391,9 @@ static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) wait_for_completion_timeout(&mrioc->init_cmds.done, (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { - ioc_err(mrioc, "Issue DelRepQ: command timed out\n"); - mpi3mr_set_diagsave(mrioc); - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + ioc_err(mrioc, "delete reply queue timed out\n"); + mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_DELREPQ_TIMEOUT); - mrioc->unrecoverable = 1; - retval = -1; goto out_unlock; } @@ -1617,12 +1613,9 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) wait_for_completion_timeout(&mrioc->init_cmds.done, (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { - ioc_err(mrioc, "CreateRepQ: command timed out\n"); - mpi3mr_set_diagsave(mrioc); - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + ioc_err(mrioc, "create reply queue timed out\n"); + mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT); - mrioc->unrecoverable = 1; retval = -1; goto out_unlock; } @@ -1724,12 +1717,9 @@ static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx, wait_for_completion_timeout(&mrioc->init_cmds.done, (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { - ioc_err(mrioc, "CreateReqQ: command timed out\n"); - mpi3mr_set_diagsave(mrioc); - if (mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, - MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT)) - mrioc->unrecoverable = 1; + ioc_err(mrioc, "create request queue timed out\n"); + mpi3mr_check_rh_fault_ioc(mrioc, + MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT); retval = -1; goto out_unlock; } @@ -1902,6 +1892,42 @@ out: return retval; } +/** + * mpi3mr_check_rh_fault_ioc - check reset history and fault + * controller + * @mrioc: Adapter instance reference + * @reason_code, reason code for the fault. + * + * This routine will save snapdump and fault the controller with + * the given reason code if it is not already in the fault or + * not asynchronosuly reset. This will be used to handle + * initilaization time faults/resets/timeout as in those cases + * immediate soft reset invocation is not required. + * + * Return: None. + */ +void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) +{ + u32 ioc_status, host_diagnostic, timeout; + + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { + mpi3mr_print_fault_info(mrioc); + return; + } + mpi3mr_set_diagsave(mrioc); + mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + reason_code); + timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; + do { + host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); + if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) + break; + msleep(100); + } while (--timeout); +} + /** * mpi3mr_sync_timestamp - Issue time stamp sync request * @mrioc: Adapter reference @@ -2025,6 +2051,8 @@ static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc) (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { ioc_err(mrioc, "get package version timed out\n"); + mpi3mr_check_rh_fault_ioc(mrioc, + MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT); retval = -1; goto out_unlock; } @@ -2344,12 +2372,9 @@ static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, wait_for_completion_timeout(&mrioc->init_cmds.done, (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { - ioc_err(mrioc, "Issue IOCFacts: command timed out\n"); - mpi3mr_set_diagsave(mrioc); - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + ioc_err(mrioc, "ioc_facts timed out\n"); + mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT); - mrioc->unrecoverable = 1; retval = -1; goto out_unlock; } @@ -2743,12 +2768,9 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) wait_for_completion_timeout(&mrioc->init_cmds.done, (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { - mpi3mr_set_diagsave(mrioc); - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_IOCINIT_TIMEOUT); - mrioc->unrecoverable = 1; - ioc_err(mrioc, "Issue IOCInit: command timed out\n"); + ioc_err(mrioc, "ioc_init timed out\n"); retval = -1; goto out_unlock; } @@ -2839,12 +2861,9 @@ static int mpi3mr_issue_event_notification(struct mpi3mr_ioc *mrioc) wait_for_completion_timeout(&mrioc->init_cmds.done, (MPI3MR_INTADMCMD_TIMEOUT * HZ)); if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { - ioc_err(mrioc, "Issue EvtNotify: command timed out\n"); - mpi3mr_set_diagsave(mrioc); - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + ioc_err(mrioc, "event notification timed out\n"); + mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT); - mrioc->unrecoverable = 1; retval = -1; goto out_unlock; } @@ -3051,29 +3070,28 @@ int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async) ioc_err(mrioc, "Issue PortEnable: Admin Post failed\n"); goto out_unlock; } - if (!async) { - wait_for_completion_timeout(&mrioc->init_cmds.done, - (pe_timeout * HZ)); - if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { - ioc_err(mrioc, "Issue PortEnable: command timed out\n"); - retval = -1; - mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; - mpi3mr_set_diagsave(mrioc); - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, - MPI3MR_RESET_FROM_PE_TIMEOUT); - mrioc->unrecoverable = 1; - goto out_unlock; - } - mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds); + if (async) { + mutex_unlock(&mrioc->init_cmds.mutex); + goto out; } + + wait_for_completion_timeout(&mrioc->init_cmds.done, (pe_timeout * HZ)); + if (!(mrioc->init_cmds.state & MPI3MR_CMD_COMPLETE)) { + ioc_err(mrioc, "port enable timed out\n"); + retval = -1; + mpi3mr_check_rh_fault_ioc(mrioc, MPI3MR_RESET_FROM_PE_TIMEOUT); + goto out_unlock; + } + mpi3mr_port_enable_complete(mrioc, &mrioc->init_cmds); + out_unlock: + mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; mutex_unlock(&mrioc->init_cmds.mutex); out: return retval; } -/* Protocol type to name mapper structure*/ +/* Protocol type to name mapper structure */ static const struct { u8 protocol; char *name; -- cgit v1.2.3 From e3605f65ef69f399aaade423f19f6db6eb3c11cb Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:46 +0530 Subject: scsi: mpi3mr: Code refactor of IOC init - part1 Separate out reply and sense buffer allocation and initialization into two routines and call only initialization routine while issuing the IOC Init request message. Also move out the event enable logic to a separate function. Link: https://lore.kernel.org/r/20211220141159.16117-13-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 107 +++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index b6d4e9d2961a..f7cdb21551f0 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -2555,10 +2555,9 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) { int retval = 0; u32 sz, i; - dma_addr_t phy_addr; if (mrioc->init_cmds.reply) - goto post_reply_sbuf; + return retval; mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL); if (!mrioc->init_cmds.reply) @@ -2651,7 +2650,28 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) if (!mrioc->sense_buf_q) goto out_failed; -post_reply_sbuf: + return retval; + +out_failed: + retval = -1; + return retval; +} + +/** + * mpimr_initialize_reply_sbuf_queues - initialize reply sense + * buffers + * @mrioc: Adapter instance reference + * + * Helper function to initialize reply and sense buffers along + * with some debug prints. + * + * Return: None. + */ +static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc) +{ + u32 sz, i; + dma_addr_t phy_addr; + sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz; ioc_info(mrioc, "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", @@ -2684,11 +2704,6 @@ post_reply_sbuf: i < mrioc->num_sense_bufs; i++, phy_addr += MPI3MR_SENSE_BUF_SZ) mrioc->sense_buf_q[i] = cpu_to_le64(phy_addr); mrioc->sense_buf_q[i] = cpu_to_le64(0); - return retval; - -out_failed: - retval = -1; - return retval; } /** @@ -2715,6 +2730,8 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) retval = -1; goto out; } + mpimr_initialize_reply_sbuf_queues(mrioc); + drv_info->information_length = cpu_to_le32(data_len); strscpy(drv_info->driver_signature, "Broadcom", sizeof(drv_info->driver_signature)); strscpy(drv_info->os_name, utsname()->sysname, sizeof(drv_info->os_name)); @@ -2784,6 +2801,13 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) goto out_unlock; } + mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs; + writel(mrioc->reply_free_queue_host_index, + &mrioc->sysif_regs->reply_free_host_index); + + mrioc->sbq_host_index = mrioc->num_sense_bufs; + writel(mrioc->sbq_host_index, + &mrioc->sysif_regs->sense_buffer_free_host_index); out_unlock: mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; mutex_unlock(&mrioc->init_cmds.mutex); @@ -3291,6 +3315,44 @@ out_failed: return retval; } +/** + * mpi3mr_enable_events - Enable required events + * @mrioc: Adapter instance reference + * + * This routine unmasks the events required by the driver by + * sennding appropriate event mask bitmapt through an event + * notification request. + * + * Return: 0 on success and non-zero on failure. + */ +static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) +{ + int retval = 0; + u32 i; + + for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) + mrioc->event_masks[i] = -1; + + mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); + + retval = mpi3mr_issue_event_notification(mrioc); + if (retval) + ioc_err(mrioc, "failed to issue event notification %d\n", + retval); + return retval; +} + /** * mpi3mr_init_ioc - Initialize the controller * @mrioc: Adapter instance reference @@ -3313,7 +3375,7 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) enum mpi3mr_iocstate ioc_state; u64 base_info; u32 timeout; - u32 ioc_status, ioc_config, i; + u32 ioc_status, ioc_config; struct mpi3_ioc_facts_data facts_data; mrioc->irqpoll_sleep = MPI3MR_IRQ_POLL_SLEEP; @@ -3455,13 +3517,6 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) retval); goto out_failed; } - mrioc->reply_free_queue_host_index = mrioc->num_reply_bufs; - writel(mrioc->reply_free_queue_host_index, - &mrioc->sysif_regs->reply_free_host_index); - - mrioc->sbq_host_index = mrioc->num_sense_bufs; - writel(mrioc->sbq_host_index, - &mrioc->sysif_regs->sense_buffer_free_host_index); retval = mpi3mr_print_pkg_ver(mrioc); if (retval) { @@ -3494,25 +3549,9 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) goto out_failed; } - for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) - mrioc->event_masks[i] = -1; - - mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_ADDED); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); - mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); - - retval = mpi3mr_issue_event_notification(mrioc); + retval = mpi3mr_enable_events(mrioc); if (retval) { - ioc_err(mrioc, "Failed to issue event notification %d\n", + ioc_err(mrioc, "failed to enable events %d\n", retval); goto out_failed; } -- cgit v1.2.3 From 59bd9cfe3fa07234e34cc2406e97481b3398c2d6 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:47 +0530 Subject: scsi: mpi3mr: Code refactor of IOC init - part2 Move the IOC initialization's bring up logic to mpi3mr_bring_ioc_ready() routine. Link: https://lore.kernel.org/r/20211220141159.16117-14-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 167 +++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 78 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index f7cdb21551f0..163e8b98f304 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -10,6 +10,10 @@ #include "mpi3mr.h" #include +static int +mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason); +static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc); + #if defined(writeq) && defined(CONFIG_64BIT) static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) { @@ -992,26 +996,105 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, * Set Enable IOC bit in IOC configuration register and wait for * the controller to become ready. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, appropriate error on failure. */ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) { - u32 ioc_config, timeout; - enum mpi3mr_iocstate current_state; + u32 ioc_config, ioc_status, timeout; + int retval = 0; + enum mpi3mr_iocstate ioc_state; + u64 base_info; + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); + base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information); + ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n", + ioc_status, ioc_config, base_info); + + /*The timeout value is in 2sec unit, changing it to seconds*/ + mrioc->ready_timeout = + ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> + MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; + + ioc_info(mrioc, "ready timeout: %d seconds\n", mrioc->ready_timeout); + + ioc_state = mpi3mr_get_iocstate(mrioc); + ioc_info(mrioc, "controller is in %s state during detection\n", + mpi3mr_iocstate_name(ioc_state)); + + if (ioc_state == MRIOC_STATE_BECOMING_READY || + ioc_state == MRIOC_STATE_RESET_REQUESTED) { + timeout = mrioc->ready_timeout * 10; + do { + msleep(100); + } while (--timeout); + + ioc_state = mpi3mr_get_iocstate(mrioc); + ioc_info(mrioc, + "controller is in %s state after waiting to reset\n", + mpi3mr_iocstate_name(ioc_state)); + } + + if (ioc_state == MRIOC_STATE_READY) { + ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n"); + retval = mpi3mr_issue_and_process_mur(mrioc, + MPI3MR_RESET_FROM_BRINGUP); + ioc_state = mpi3mr_get_iocstate(mrioc); + if (retval) + ioc_err(mrioc, + "message unit reset failed with error %d current state %s\n", + retval, mpi3mr_iocstate_name(ioc_state)); + } + if (ioc_state != MRIOC_STATE_RESET) { + mpi3mr_print_fault_info(mrioc); + ioc_info(mrioc, "issuing soft reset to bring to reset state\n"); + retval = mpi3mr_issue_reset(mrioc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, + MPI3MR_RESET_FROM_BRINGUP); + if (retval) { + ioc_err(mrioc, + "soft reset failed with error %d\n", retval); + goto out_failed; + } + } + ioc_state = mpi3mr_get_iocstate(mrioc); + if (ioc_state != MRIOC_STATE_RESET) { + ioc_err(mrioc, + "cannot bring controller to reset state, current state: %s\n", + mpi3mr_iocstate_name(ioc_state)); + goto out_failed; + } + mpi3mr_clear_reset_history(mrioc); + retval = mpi3mr_setup_admin_qpair(mrioc); + if (retval) { + ioc_err(mrioc, "failed to setup admin queues: error %d\n", + retval); + goto out_failed; + } + + ioc_info(mrioc, "bringing controller to ready state\n"); ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); timeout = mrioc->ready_timeout * 10; do { - current_state = mpi3mr_get_iocstate(mrioc); - if (current_state == MRIOC_STATE_READY) + ioc_state = mpi3mr_get_iocstate(mrioc); + if (ioc_state == MRIOC_STATE_READY) { + ioc_info(mrioc, + "successfully transistioned to %s state\n", + mpi3mr_iocstate_name(ioc_state)); return 0; + } msleep(100); } while (--timeout); - return -1; +out_failed: + ioc_state = mpi3mr_get_iocstate(mrioc); + ioc_err(mrioc, + "failed to bring to ready state, current state: %s\n", + mpi3mr_iocstate_name(ioc_state)); + return retval; } /** @@ -3372,10 +3455,6 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) { int retval = 0; - enum mpi3mr_iocstate ioc_state; - u64 base_info; - u32 timeout; - u32 ioc_status, ioc_config; struct mpi3_ioc_facts_data facts_data; mrioc->irqpoll_sleep = MPI3MR_IRQ_POLL_SLEEP; @@ -3390,74 +3469,6 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) } } - ioc_status = readl(&mrioc->sysif_regs->ioc_status); - ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); - - ioc_info(mrioc, "SOD status %x configuration %x\n", - ioc_status, ioc_config); - - base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information); - ioc_info(mrioc, "SOD base_info %llx\n", base_info); - - /*The timeout value is in 2sec unit, changing it to seconds*/ - mrioc->ready_timeout = - ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> - MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2; - - ioc_info(mrioc, "IOC ready timeout %d\n", mrioc->ready_timeout); - - ioc_state = mpi3mr_get_iocstate(mrioc); - ioc_info(mrioc, "IOC in %s state during detection\n", - mpi3mr_iocstate_name(ioc_state)); - - if (ioc_state == MRIOC_STATE_BECOMING_READY || - ioc_state == MRIOC_STATE_RESET_REQUESTED) { - timeout = mrioc->ready_timeout * 10; - do { - msleep(100); - } while (--timeout); - - ioc_state = mpi3mr_get_iocstate(mrioc); - ioc_info(mrioc, - "IOC in %s state after waiting for reset time\n", - mpi3mr_iocstate_name(ioc_state)); - } - - if (ioc_state == MRIOC_STATE_READY) { - retval = mpi3mr_issue_and_process_mur(mrioc, - MPI3MR_RESET_FROM_BRINGUP); - if (retval) { - ioc_err(mrioc, "Failed to MU reset IOC error %d\n", - retval); - } - ioc_state = mpi3mr_get_iocstate(mrioc); - } - if (ioc_state != MRIOC_STATE_RESET) { - mpi3mr_print_fault_info(mrioc); - retval = mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, - MPI3MR_RESET_FROM_BRINGUP); - if (retval) { - ioc_err(mrioc, - "%s :Failed to soft reset IOC error %d\n", - __func__, retval); - goto out_failed; - } - } - ioc_state = mpi3mr_get_iocstate(mrioc); - if (ioc_state != MRIOC_STATE_RESET) { - retval = -1; - ioc_err(mrioc, "Cannot bring IOC to reset state\n"); - goto out_failed; - } - - retval = mpi3mr_setup_admin_qpair(mrioc); - if (retval) { - ioc_err(mrioc, "Failed to setup admin Qs: error %d\n", - retval); - goto out_failed; - } - retval = mpi3mr_bring_ioc_ready(mrioc); if (retval) { ioc_err(mrioc, "Failed to bring ioc ready: error %d\n", -- cgit v1.2.3 From fe6db615156573d3f6a37564b8a590cb03bbaf25 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:48 +0530 Subject: scsi: mpi3mr: Handle offline FW activation in graceful manner Currently the driver marks the controller as unrecoverable if there is an asynchronous reset or fault during the initialization, reinitialization post reset, and OS resume. Enhance driver to retry the initialization, re-initialization, and resume sequences for a maximum of 3 times if the controller became faulty or asynchronously reset due to a firmware activation during the initialization sequence. Link: https://lore.kernel.org/r/20211220141159.16117-15-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 22 ++--- drivers/scsi/mpi3mr/mpi3mr_fw.c | 180 ++++++++++++++++++---------------------- drivers/scsi/mpi3mr/mpi3mr_os.c | 46 +++++++--- 3 files changed, 120 insertions(+), 128 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 55a07f9c8807..ea5f27fa6c4a 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -185,20 +185,6 @@ enum mpi3mr_iocstate { MRIOC_STATE_UNRECOVERABLE, }; -/* Init type definitions */ -enum mpi3mr_init_type { - MPI3MR_IT_INIT = 0, - MPI3MR_IT_RESET, - MPI3MR_IT_RESUME, -}; - -/* Cleanup reason definitions */ -enum mpi3mr_cleanup_reason { - MPI3MR_COMPLETE_CLEANUP = 0, - MPI3MR_REINIT_FAILURE, - MPI3MR_SUSPEND, -}; - /* Reset reason code definitions*/ enum mpi3mr_reset_reason { MPI3MR_RESET_FROM_BRINGUP = 1, @@ -634,6 +620,7 @@ struct scmd_priv { * @ready_timeout: Controller ready timeout * @intr_info: Interrupt cookie pointer * @intr_info_count: Number of interrupt cookies + * @is_intr_info_set: Flag to indicate intr info is setup * @num_queues: Number of operational queues * @num_op_req_q: Number of operational request queues * @req_qinfo: Operational request queue info pointer @@ -743,6 +730,7 @@ struct mpi3mr_ioc { struct mpi3mr_intr_info *intr_info; u16 intr_info_count; + bool is_intr_info_set; u16 num_queues; u16 num_op_req_q; @@ -873,8 +861,9 @@ struct delayed_dev_rmhs_node { int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc); void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc); -int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type); -void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 reason); +int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc); +int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume); +void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc); int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async); int mpi3mr_admin_request_post(struct mpi3mr_ioc *mrioc, void *admin_req, u16 admin_req_sz, u8 ignore_reset); @@ -891,6 +880,7 @@ void mpi3mr_repost_sense_buf(struct mpi3mr_ioc *mrioc, u64 sense_buf_dma); void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc); +void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc); void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, struct mpi3_event_notification_reply *event_reply); void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 163e8b98f304..bad708af942f 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -82,6 +82,7 @@ static void mpi3mr_cleanup_isr(struct mpi3mr_ioc *mrioc) kfree(mrioc->intr_info); mrioc->intr_info = NULL; mrioc->intr_info_count = 0; + mrioc->is_intr_info_set = false; pci_free_irq_vectors(mrioc->pdev); } @@ -675,6 +676,9 @@ static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) int i; struct irq_affinity desc = { .pre_vectors = 1}; + if (mrioc->is_intr_info_set) + return 0; + mpi3mr_cleanup_isr(mrioc); if (setup_one || reset_devices) @@ -726,6 +730,8 @@ static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) goto out_failed; } } + if (reset_devices || !setup_one) + mrioc->is_intr_info_set = true; mrioc->intr_info_count = max_vectors; mpi3mr_ioc_enable_intr(mrioc); return 0; @@ -1712,7 +1718,8 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) goto out_unlock; } op_reply_q->qid = reply_qid; - mrioc->intr_info[midx].op_reply_q = op_reply_q; + if (midx < mrioc->intr_info_count) + mrioc->intr_info[midx].op_reply_q = op_reply_q; out_unlock: mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; @@ -3074,6 +3081,9 @@ static int mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc) u32 sz, i; u16 num_chains; + if (mrioc->chain_sgl_list) + return retval; + num_chains = mrioc->max_host_ios / MPI3MR_CHAINBUF_FACTOR; if (prot_mask & (SHOST_DIX_TYPE0_PROTECTION @@ -3452,39 +3462,26 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) * * Return: 0 on success and non-zero on failure. */ -int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) +int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc) { int retval = 0; + u8 retry = 0; struct mpi3_ioc_facts_data facts_data; - mrioc->irqpoll_sleep = MPI3MR_IRQ_POLL_SLEEP; - mrioc->change_count = 0; - if (init_type == MPI3MR_IT_INIT) { - mrioc->cpu_count = num_online_cpus(); - retval = mpi3mr_setup_resources(mrioc); - if (retval) { - ioc_err(mrioc, "Failed to setup resources:error %d\n", - retval); - goto out_nocleanup; - } - } - +retry_init: retval = mpi3mr_bring_ioc_ready(mrioc); if (retval) { ioc_err(mrioc, "Failed to bring ioc ready: error %d\n", retval); - goto out_failed; + goto out_failed_noretry; } - if (init_type != MPI3MR_IT_RESET) { - retval = mpi3mr_setup_isr(mrioc, 1); - if (retval) { - ioc_err(mrioc, "Failed to setup ISR error %d\n", - retval); - goto out_failed; - } - } else - mpi3mr_ioc_enable_intr(mrioc); + retval = mpi3mr_setup_isr(mrioc, 1); + if (retval) { + ioc_err(mrioc, "Failed to setup ISR error %d\n", + retval); + goto out_failed_noretry; + } retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); if (retval) { @@ -3494,13 +3491,12 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) } mpi3mr_process_factsdata(mrioc, &facts_data); - if (init_type == MPI3MR_IT_INIT) { - retval = mpi3mr_check_reset_dma_mask(mrioc); - if (retval) { - ioc_err(mrioc, "Resetting dma mask failed %d\n", - retval); - goto out_failed; - } + + retval = mpi3mr_check_reset_dma_mask(mrioc); + if (retval) { + ioc_err(mrioc, "Resetting dma mask failed %d\n", + retval); + goto out_failed_noretry; } mpi3mr_print_ioc_info(mrioc); @@ -3510,16 +3506,14 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) ioc_err(mrioc, "%s :Failed to allocated reply sense buffers %d\n", __func__, retval); - goto out_failed; + goto out_failed_noretry; } - if (init_type == MPI3MR_IT_INIT) { - retval = mpi3mr_alloc_chain_bufs(mrioc); - if (retval) { - ioc_err(mrioc, "Failed to allocated chain buffers %d\n", - retval); - goto out_failed; - } + retval = mpi3mr_alloc_chain_bufs(mrioc); + if (retval) { + ioc_err(mrioc, "Failed to allocated chain buffers %d\n", + retval); + goto out_failed_noretry; } retval = mpi3mr_issue_iocinit(mrioc); @@ -3535,13 +3529,11 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) goto out_failed; } - if (init_type != MPI3MR_IT_RESET) { - retval = mpi3mr_setup_isr(mrioc, 0); - if (retval) { - ioc_err(mrioc, "Failed to re-setup ISR, error %d\n", - retval); - goto out_failed; - } + retval = mpi3mr_setup_isr(mrioc, 0); + if (retval) { + ioc_err(mrioc, "Failed to re-setup ISR, error %d\n", + retval); + goto out_failed_noretry; } retval = mpi3mr_create_op_queues(mrioc); @@ -3551,15 +3543,6 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) goto out_failed; } - if ((init_type != MPI3MR_IT_INIT) && - (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q)) { - retval = -1; - ioc_err(mrioc, - "Cannot create minimum number of OpQueues expected:%d created:%d\n", - mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q); - goto out_failed; - } - retval = mpi3mr_enable_events(mrioc); if (retval) { ioc_err(mrioc, "failed to enable events %d\n", @@ -3567,26 +3550,30 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc, u8 init_type) goto out_failed; } - if (init_type != MPI3MR_IT_INIT) { - ioc_info(mrioc, "Issuing Port Enable\n"); - retval = mpi3mr_issue_port_enable(mrioc, 0); - if (retval) { - ioc_err(mrioc, "Failed to issue port enable %d\n", - retval); - goto out_failed; - } - } + ioc_info(mrioc, "controller initialization completed successfully\n"); return retval; - out_failed: - if (init_type == MPI3MR_IT_INIT) - mpi3mr_cleanup_ioc(mrioc, MPI3MR_COMPLETE_CLEANUP); - else - mpi3mr_cleanup_ioc(mrioc, MPI3MR_REINIT_FAILURE); -out_nocleanup: + if (retry < 2) { + retry++; + ioc_warn(mrioc, "retrying controller initialization, retry_count:%d\n", + retry); + mpi3mr_memset_buffers(mrioc); + goto retry_init; + } +out_failed_noretry: + ioc_err(mrioc, "controller initialization failed\n"); + mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + MPI3MR_RESET_FROM_CTLR_CLEANUP); + mrioc->unrecoverable = 1; return retval; } +int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume) +{ + + return 0; +} + /** * mpi3mr_memset_op_reply_q_buffers - memset the operational reply queue's * segments @@ -3647,17 +3634,22 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) { u16 i; - memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); - memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); - - memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); - memset(mrioc->host_tm_cmds.reply, 0, - sizeof(*mrioc->host_tm_cmds.reply)); - for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) - memset(mrioc->dev_rmhs_cmds[i].reply, 0, - sizeof(*mrioc->dev_rmhs_cmds[i].reply)); - memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); - memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); + mrioc->change_count = 0; + if (mrioc->admin_req_base) + memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); + if (mrioc->admin_reply_base) + memset(mrioc->admin_reply_base, 0, mrioc->admin_reply_q_sz); + + if (mrioc->init_cmds.reply) { + memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply)); + memset(mrioc->host_tm_cmds.reply, 0, + sizeof(*mrioc->host_tm_cmds.reply)); + for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) + memset(mrioc->dev_rmhs_cmds[i].reply, 0, + sizeof(*mrioc->dev_rmhs_cmds[i].reply)); + memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); + memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); + } for (i = 0; i < mrioc->num_queues; i++) { mrioc->op_reply_qinfo[i].qid = 0; @@ -3686,7 +3678,7 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) * * Return: Nothing. */ -static void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) +void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) { u16 i; struct mpi3mr_intr_info *intr_info; @@ -3858,21 +3850,17 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc) /** * mpi3mr_cleanup_ioc - Cleanup controller * @mrioc: Adapter instance reference - * @reason: Cleanup reason - * + * controller cleanup handler, Message unit reset or soft reset - * and shutdown notification is issued to the controller and the - * associated memory resources are freed. + * and shutdown notification is issued to the controller. * * Return: Nothing. */ -void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 reason) +void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc) { enum mpi3mr_iocstate ioc_state; - if (reason == MPI3MR_COMPLETE_CLEANUP) - mpi3mr_stop_watchdog(mrioc); - + dprint_exit(mrioc, "cleaning up the controller\n"); mpi3mr_ioc_disable_intr(mrioc); ioc_state = mpi3mr_get_iocstate(mrioc); @@ -3884,15 +3872,9 @@ void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc, u8 reason) mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, MPI3MR_RESET_FROM_MUR_FAILURE); - - if (reason != MPI3MR_REINIT_FAILURE) - mpi3mr_issue_ioc_shutdown(mrioc); - } - - if (reason == MPI3MR_COMPLETE_CLEANUP) { - mpi3mr_free_mem(mrioc); - mpi3mr_cleanup_resources(mrioc); + mpi3mr_issue_ioc_shutdown(mrioc); } + dprint_exit(mrioc, "controller cleanup completed\n"); } /** @@ -4071,7 +4053,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, mpi3mr_flush_host_io(mrioc); mpi3mr_invalidate_devhandles(mrioc); mpi3mr_memset_buffers(mrioc); - retval = mpi3mr_init_ioc(mrioc, MPI3MR_IT_RESET); + retval = mpi3mr_reinit_ioc(mrioc, 0); if (retval) { pr_err(IOCNAME "reinit after soft reset failed: reason %d\n", mrioc->name, reset_reason); diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 2a153df0f803..e17b2c1d53ae 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -3821,21 +3821,26 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc_err(mrioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); retval = -ENODEV; - goto out_fwevtthread_failed; + goto fwevtthread_failed; } mrioc->is_driver_loading = 1; - if (mpi3mr_init_ioc(mrioc, MPI3MR_IT_INIT)) { - ioc_err(mrioc, "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); + mrioc->cpu_count = num_online_cpus(); + if (mpi3mr_setup_resources(mrioc)) { + ioc_err(mrioc, "setup resources failed\n"); + retval = -ENODEV; + goto resource_alloc_failed; + } + if (mpi3mr_init_ioc(mrioc)) { + ioc_err(mrioc, "initializing IOC failed\n"); retval = -ENODEV; - goto out_iocinit_failed; + goto init_ioc_failed; } shost->nr_hw_queues = mrioc->num_op_reply_q; shost->can_queue = mrioc->max_host_ios; shost->sg_tablesize = MPI3MR_SG_DEPTH; - shost->max_id = mrioc->facts.max_perids; + shost->max_id = mrioc->facts.max_perids + 1; retval = scsi_add_host(shost, &pdev->dev); if (retval) { @@ -3848,10 +3853,14 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) return retval; addhost_failed: - mpi3mr_cleanup_ioc(mrioc, MPI3MR_COMPLETE_CLEANUP); -out_iocinit_failed: + mpi3mr_stop_watchdog(mrioc); + mpi3mr_cleanup_ioc(mrioc); +init_ioc_failed: + mpi3mr_free_mem(mrioc); + mpi3mr_cleanup_resources(mrioc); +resource_alloc_failed: destroy_workqueue(mrioc->fwevt_worker_thread); -out_fwevtthread_failed: +fwevtthread_failed: spin_lock(&mrioc_list_lock); list_del(&mrioc->list); spin_unlock(&mrioc_list_lock); @@ -3864,6 +3873,7 @@ shost_failed: * mpi3mr_remove - PCI remove callback * @pdev: PCI device instance * + * Cleanup the IOC by issuing MUR and shutdown notification. * Free up all memory and resources associated with the * controllerand target devices, unregister the shost. * @@ -3900,7 +3910,10 @@ static void mpi3mr_remove(struct pci_dev *pdev) mpi3mr_tgtdev_del_from_list(mrioc, tgtdev); mpi3mr_tgtdev_put(tgtdev); } - mpi3mr_cleanup_ioc(mrioc, MPI3MR_COMPLETE_CLEANUP); + mpi3mr_stop_watchdog(mrioc); + mpi3mr_cleanup_ioc(mrioc); + mpi3mr_free_mem(mrioc); + mpi3mr_cleanup_resources(mrioc); spin_lock(&mrioc_list_lock); list_del(&mrioc->list); @@ -3940,7 +3953,10 @@ static void mpi3mr_shutdown(struct pci_dev *pdev) spin_unlock_irqrestore(&mrioc->fwevt_lock, flags); if (wq) destroy_workqueue(wq); - mpi3mr_cleanup_ioc(mrioc, MPI3MR_COMPLETE_CLEANUP); + + mpi3mr_stop_watchdog(mrioc); + mpi3mr_cleanup_ioc(mrioc); + mpi3mr_cleanup_resources(mrioc); } #ifdef CONFIG_PM @@ -3970,7 +3986,7 @@ static int mpi3mr_suspend(struct pci_dev *pdev, pm_message_t state) mpi3mr_cleanup_fwevt_list(mrioc); scsi_block_requests(shost); mpi3mr_stop_watchdog(mrioc); - mpi3mr_cleanup_ioc(mrioc, MPI3MR_SUSPEND); + mpi3mr_cleanup_ioc(mrioc); device_state = pci_choose_state(pdev, state); ioc_info(mrioc, "pdev=0x%p, slot=%s, entering operating state [D%d]\n", @@ -4019,7 +4035,11 @@ static int mpi3mr_resume(struct pci_dev *pdev) mrioc->stop_drv_processing = 0; mpi3mr_memset_buffers(mrioc); - mpi3mr_init_ioc(mrioc, MPI3MR_IT_RESUME); + r = mpi3mr_reinit_ioc(mrioc, 1); + if (r) { + ioc_err(mrioc, "resuming controller failed[%d]\n", r); + return r; + } scsi_unblock_requests(shost); mpi3mr_start_watchdog(mrioc); -- cgit v1.2.3 From c0b00a931e5e5fc143ed5563389ef72e40de9814 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:49 +0530 Subject: scsi: mpi3mr: Add IOC reinit function Add IOC reinitialization function. Link: https://lore.kernel.org/r/20211220141159.16117-16-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 116 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index bad708af942f..ea606488de9c 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3568,10 +3568,124 @@ out_failed_noretry: return retval; } +/** + * mpi3mr_reinit_ioc - Re-Initialize the controller + * @mrioc: Adapter instance reference + * @is_resume: Called from resume or reset path + * + * This the controller re-initialization routine, executed from + * the soft reset handler or resume callback. Creates + * operational reply queue pairs, allocate required memory for + * reply pool, sense buffer pool, issue IOC init request to the + * firmware, unmask the events and issue port enable to discover + * SAS/SATA/NVMe devices and RAID volumes. + * + * Return: 0 on success and non-zero on failure. + */ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume) { + int retval = 0; + u8 retry = 0; + struct mpi3_ioc_facts_data facts_data; - return 0; +retry_init: + dprint_reset(mrioc, "bringing up the controller to ready state\n"); + retval = mpi3mr_bring_ioc_ready(mrioc); + if (retval) { + ioc_err(mrioc, "failed to bring to ready state\n"); + goto out_failed_noretry; + } + + if (is_resume) { + dprint_reset(mrioc, "setting up single ISR\n"); + retval = mpi3mr_setup_isr(mrioc, 1); + if (retval) { + ioc_err(mrioc, "failed to setup ISR\n"); + goto out_failed_noretry; + } + } else + mpi3mr_ioc_enable_intr(mrioc); + + dprint_reset(mrioc, "getting ioc_facts\n"); + retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); + if (retval) { + ioc_err(mrioc, "failed to get ioc_facts\n"); + goto out_failed; + } + + mpi3mr_process_factsdata(mrioc, &facts_data); + + mpi3mr_print_ioc_info(mrioc); + + dprint_reset(mrioc, "sending ioc_init\n"); + retval = mpi3mr_issue_iocinit(mrioc); + if (retval) { + ioc_err(mrioc, "failed to send ioc_init\n"); + goto out_failed; + } + + dprint_reset(mrioc, "getting package version\n"); + retval = mpi3mr_print_pkg_ver(mrioc); + if (retval) { + ioc_err(mrioc, "failed to get package version\n"); + goto out_failed; + } + + if (is_resume) { + dprint_reset(mrioc, "setting up multiple ISR\n"); + retval = mpi3mr_setup_isr(mrioc, 0); + if (retval) { + ioc_err(mrioc, "failed to re-setup ISR\n"); + goto out_failed_noretry; + } + } + + dprint_reset(mrioc, "creating operational queue pairs\n"); + retval = mpi3mr_create_op_queues(mrioc); + if (retval) { + ioc_err(mrioc, "failed to create operational queue pairs\n"); + goto out_failed; + } + + if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) { + ioc_err(mrioc, + "cannot create minimum number of operatioanl queues expected:%d created:%d\n", + mrioc->shost->nr_hw_queues, mrioc->num_op_reply_q); + goto out_failed_noretry; + } + + dprint_reset(mrioc, "enabling events\n"); + retval = mpi3mr_enable_events(mrioc); + if (retval) { + ioc_err(mrioc, "failed to enable events\n"); + goto out_failed; + } + + ioc_info(mrioc, "sending port enable\n"); + retval = mpi3mr_issue_port_enable(mrioc, 0); + if (retval) { + ioc_err(mrioc, "failed to issue port enable\n"); + goto out_failed; + } + + ioc_info(mrioc, "controller %s completed successfully\n", + (is_resume)?"resume":"re-initialization"); + return retval; +out_failed: + if (retry < 2) { + retry++; + ioc_warn(mrioc, "retrying controller %s, retry_count:%d\n", + (is_resume)?"resume":"re-initialization", retry); + mpi3mr_memset_buffers(mrioc); + goto retry_init; + } +out_failed_noretry: + ioc_err(mrioc, "controller %s is failed\n", + (is_resume)?"resume":"re-initialization"); + mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, + MPI3MR_RESET_FROM_CTLR_CLEANUP); + mrioc->unrecoverable = 1; + return retval; } /** -- cgit v1.2.3 From b64845a7d4039ab9667bafff9d7bb59365f17c0f Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:50 +0530 Subject: scsi: mpi3mr: Detect async reset that occurred in firmware Detect asynchronous reset that occurred in the firmware by polling for reset history bit of IOC status register is set and if that bit is set, then the driver waits for the controller to become ready and then re-initializes the controller. Also reduce the time driver is waiting for the controller to acknowledge the reset action after issuing a specific reset action to the controller. The wait time is reduced from 510 seconds to 30 seconds. If the controller didn't acknowledge a specific reset action within the time interval then the driver marks the controller as unrecoverable instead of retrying two more times prior to giving up. Link: https://lore.kernel.org/r/20211220141159.16117-17-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 12 ++- drivers/scsi/mpi3mr/mpi3mr_fw.c | 233 +++++++++++++++------------------------- drivers/scsi/mpi3mr/mpi3mr_os.c | 38 ++++--- 3 files changed, 120 insertions(+), 163 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index ea5f27fa6c4a..b24efe2792c7 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -110,6 +110,7 @@ extern int prot_mask; #define MPI3MR_TSUPDATE_INTERVAL 900 #define MPI3MR_DEFAULT_SHUTDOWN_TIME 120 #define MPI3MR_RAID_ERRREC_RESET_TIMEOUT 180 +#define MPI3MR_RESET_ACK_TIMEOUT 30 #define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */ @@ -210,7 +211,8 @@ enum mpi3mr_reset_reason { MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT = 21, MPI3MR_RESET_FROM_PELABORT_TIMEOUT = 22, MPI3MR_RESET_FROM_SYSFS = 23, - MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24 + MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24, + MPI3MR_RESET_FROM_FIRMWARE = 27, }; /** @@ -678,9 +680,9 @@ struct scmd_priv { * @removepend_bitmap: Remove pending bitmap * @delayed_rmhs_list: Delayed device removal list * @ts_update_counter: Timestamp update counter - * @fault_dbg: Fault debug flag * @reset_in_progress: Reset in progress flag * @unrecoverable: Controller unrecoverable flag + * @prev_reset_result: Result of previous reset * @reset_mutex: Controller reset mutex * @reset_waitq: Controller reset wait queue * @diagsave_timeout: Diagnostic information save timeout @@ -804,9 +806,9 @@ struct mpi3mr_ioc { struct list_head delayed_rmhs_list; u32 ts_update_counter; - u8 fault_dbg; u8 reset_in_progress; u8 unrecoverable; + int prev_reset_result; struct mutex reset_mutex; wait_queue_head_t reset_waitq; @@ -891,8 +893,6 @@ void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc); int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, u32 reset_reason, u8 snapdump); -int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc, - u32 reset_reason); void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc); void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc); @@ -907,5 +907,7 @@ void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc); void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc); void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc); void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); +void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc); +void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); #endif /*MPI3MR_H_INCLUDED*/ diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index ea606488de9c..7a0131e713c5 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -808,6 +808,7 @@ static const struct { }, { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" }, { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" }, + { MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" }, }; /** @@ -872,7 +873,7 @@ static const char *mpi3mr_reset_type_name(u16 reset_type) * * Return: Nothing. */ -static void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) +void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) { u32 ioc_status, code, code1, code2, code3; @@ -970,25 +971,25 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); - timeout = mrioc->ready_timeout * 10; + timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; do { ioc_status = readl(&mrioc->sysif_regs->ioc_status); if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) { mpi3mr_clear_reset_history(mrioc); - ioc_config = - readl(&mrioc->sysif_regs->ioc_configuration); - if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || - (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || - (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) { - retval = 0; - break; - } + break; + } + if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { + mpi3mr_print_fault_info(mrioc); + break; } msleep(100); } while (--timeout); - ioc_status = readl(&mrioc->sysif_regs->ioc_status); ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); + if (timeout && !((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || + (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) + retval = 0; ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%x)/(0x%x)\n", (!retval) ? "successful" : "failed", ioc_status, ioc_config); @@ -1117,7 +1118,6 @@ static inline bool mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config) { if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || - (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) return true; return false; @@ -1140,8 +1140,10 @@ static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc, if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) return false; fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; - if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) + if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) { + mpi3mr_print_fault_info(mrioc); return true; + } return false; } @@ -1180,26 +1182,36 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason) { int retval = -1; - u8 unlock_retry_count, reset_retry_count = 0; - u32 host_diagnostic, timeout, ioc_status, ioc_config; + u8 unlock_retry_count = 0; + u32 host_diagnostic, ioc_status, ioc_config; + u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10; - pci_cfg_access_lock(mrioc->pdev); if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) && (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)) - goto out; + return retval; if (mrioc->unrecoverable) - goto out; -retry_reset: - unlock_retry_count = 0; + return retval; + if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) { + retval = 0; + return retval; + } + + ioc_info(mrioc, "%s reset due to %s(0x%x)\n", + mpi3mr_reset_type_name(reset_type), + mpi3mr_reset_rc_name(reset_reason), reset_reason); + mpi3mr_clear_reset_history(mrioc); do { ioc_info(mrioc, "Write magic sequence to unlock host diag register (retry=%d)\n", ++unlock_retry_count); if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) { - writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); + ioc_err(mrioc, + "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n", + mpi3mr_reset_type_name(reset_type), + host_diagnostic); mrioc->unrecoverable = 1; - goto out; + return retval; } writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH, @@ -1224,31 +1236,26 @@ retry_reset: } while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE)); writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); - ioc_info(mrioc, "%s reset due to %s(0x%x)\n", - mpi3mr_reset_type_name(reset_type), - mpi3mr_reset_rc_name(reset_reason), reset_reason); writel(host_diagnostic | reset_type, &mrioc->sysif_regs->host_diagnostic); - timeout = mrioc->ready_timeout * 10; - if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) { + switch (reset_type) { + case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET: do { ioc_status = readl(&mrioc->sysif_regs->ioc_status); - if (ioc_status & - MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { + ioc_config = + readl(&mrioc->sysif_regs->ioc_configuration); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) + && mpi3mr_soft_reset_success(ioc_status, ioc_config) + ) { mpi3mr_clear_reset_history(mrioc); - ioc_config = - readl(&mrioc->sysif_regs->ioc_configuration); - if (mpi3mr_soft_reset_success(ioc_status, - ioc_config)) { - retval = 0; - break; - } + retval = 0; + break; } msleep(100); } while (--timeout); - writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, - &mrioc->sysif_regs->write_sequence); - } else if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) { + mpi3mr_print_fault_info(mrioc); + break; + case MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT: do { ioc_status = readl(&mrioc->sysif_regs->ioc_status); if (mpi3mr_diagfault_success(mrioc, ioc_status)) { @@ -1257,28 +1264,22 @@ retry_reset: } msleep(100); } while (--timeout); - mpi3mr_clear_reset_history(mrioc); - writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, - &mrioc->sysif_regs->write_sequence); - } - if (retval && ((++reset_retry_count) < MPI3MR_MAX_RESET_RETRY_COUNT)) { - ioc_status = readl(&mrioc->sysif_regs->ioc_status); - ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); - ioc_info(mrioc, - "Base IOC Sts/Config after reset try %d is (0x%x)/(0x%x)\n", - reset_retry_count, ioc_status, ioc_config); - goto retry_reset; + break; + default: + break; } -out: - pci_cfg_access_unlock(mrioc->pdev); - ioc_status = readl(&mrioc->sysif_regs->ioc_status); - ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, + &mrioc->sysif_regs->write_sequence); + ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); + ioc_status = readl(&mrioc->sysif_regs->ioc_status); ioc_info(mrioc, - "Base IOC Sts/Config after %s reset is (0x%x)/(0x%x)\n", - (!retval) ? "successful" : "failed", ioc_status, + "ioc_status/ioc_onfig after %s reset is (0x%x)/(0x%x)\n", + (!retval)?"successful":"failed", ioc_status, ioc_config); + if (retval) + mrioc->unrecoverable = 1; return retval; } @@ -2190,6 +2191,9 @@ static void mpi3mr_watchdog_work(struct work_struct *work) enum mpi3mr_iocstate ioc_state; u32 fault, host_diagnostic; + if (mrioc->reset_in_progress || mrioc->unrecoverable) + return; + if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) { mrioc->ts_update_counter = 0; mpi3mr_sync_timestamp(mrioc); @@ -2300,41 +2304,6 @@ void mpi3mr_stop_watchdog(struct mpi3mr_ioc *mrioc) } } -/** - * mpi3mr_kill_ioc - Kill the controller - * @mrioc: Adapter instance reference - * @reason: reason for the failure. - * - * If fault debug is enabled, display the fault info else issue - * diag fault and freeze the system for controller debug - * purpose. - * - * Return: Nothing. - */ -static void mpi3mr_kill_ioc(struct mpi3mr_ioc *mrioc, u32 reason) -{ - enum mpi3mr_iocstate ioc_state; - - if (!mrioc->fault_dbg) - return; - - dump_stack(); - - ioc_state = mpi3mr_get_iocstate(mrioc); - if (ioc_state == MRIOC_STATE_FAULT) - mpi3mr_print_fault_info(mrioc); - else { - ioc_err(mrioc, "Firmware is halted due to the reason %d\n", - reason); - mpi3mr_diagfault_reset_handler(mrioc, reason); - } - if (mrioc->fault_dbg == 2) - for (;;) - ; - else - panic("panic in %s\n", __func__); -} - /** * mpi3mr_setup_admin_qpair - Setup admin queue pair * @mrioc: Adapter instance reference @@ -4039,41 +4008,6 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) } } -/** - * mpi3mr_diagfault_reset_handler - Diag fault reset handler - * @mrioc: Adapter instance reference - * @reset_reason: Reset reason code - * - * This is an handler for issuing diag fault reset from the - * applications through IOCTL path to stop the execution of the - * controller - * - * Return: 0 on success, non-zero on failure. - */ -int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc, - u32 reset_reason) -{ - int retval = 0; - - ioc_info(mrioc, "Entry: reason code: %s\n", - mpi3mr_reset_rc_name(reset_reason)); - mrioc->reset_in_progress = 1; - - mpi3mr_ioc_disable_intr(mrioc); - - retval = mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); - - if (retval) { - ioc_err(mrioc, "The diag fault reset failed: reason %d\n", - reset_reason); - mpi3mr_ioc_enable_intr(mrioc); - } - ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED")); - mrioc->reset_in_progress = 0; - return retval; -} - /** * mpi3mr_soft_reset_handler - Reset the controller * @mrioc: Adapter instance reference @@ -4102,34 +4036,44 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, unsigned long flags; u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; - if (mrioc->fault_dbg) { - if (snapdump) - mpi3mr_set_diagsave(mrioc); - mpi3mr_kill_ioc(mrioc, reset_reason); - } - + /* Block the reset handler until diag save in progress*/ + dprint_reset(mrioc, + "soft_reset_handler: check and block on diagsave_timeout(%d)\n", + mrioc->diagsave_timeout); + while (mrioc->diagsave_timeout) + ssleep(1); /* * Block new resets until the currently executing one is finished and * return the status of the existing reset for all blocked resets */ + dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n"); if (!mutex_trylock(&mrioc->reset_mutex)) { - ioc_info(mrioc, "Another reset in progress\n"); - return -1; + ioc_info(mrioc, + "controller reset triggered by %s is blocked due to another reset in progress\n", + mpi3mr_reset_rc_name(reset_reason)); + do { + ssleep(1); + } while (mrioc->reset_in_progress == 1); + ioc_info(mrioc, + "returning previous reset result(%d) for the reset triggered by %s\n", + mrioc->prev_reset_result, + mpi3mr_reset_rc_name(reset_reason)); + return mrioc->prev_reset_result; } + ioc_info(mrioc, "controller reset is triggered by %s\n", + mpi3mr_reset_rc_name(reset_reason)); + mrioc->reset_in_progress = 1; + mrioc->prev_reset_result = -1; if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) && + (reset_reason != MPI3MR_RESET_FROM_FIRMWARE) && (reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) { for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++) mrioc->event_masks[i] = -1; - retval = mpi3mr_issue_event_notification(mrioc); - - if (retval) { - ioc_err(mrioc, - "Failed to turn off events prior to reset %d\n", - retval); - } + dprint_reset(mrioc, "soft_reset_handler: masking events\n"); + mpi3mr_issue_event_notification(mrioc); } mpi3mr_wait_for_host_io(mrioc, MPI3MR_RESET_HOST_IOWAIT_TIMEOUT); @@ -4177,8 +4121,8 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, out: if (!retval) { + mrioc->diagsave_timeout = 0; mrioc->reset_in_progress = 0; - scsi_unblock_requests(mrioc->shost); mpi3mr_rfresh_tgtdevs(mrioc); mrioc->ts_update_counter = 0; spin_lock_irqsave(&mrioc->watchdog_lock, flags); @@ -4194,8 +4138,9 @@ out: mrioc->reset_in_progress = 0; retval = -1; } - + mrioc->prev_reset_result = retval; mutex_unlock(&mrioc->reset_mutex); - ioc_info(mrioc, "%s\n", ((retval == 0) ? "SUCCESS" : "FAILED")); + ioc_info(mrioc, "controller reset is %s\n", + ((retval == 0) ? "successful" : "failed")); return retval; } diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index e17b2c1d53ae..38e104301142 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -3073,32 +3073,42 @@ static int mpi3mr_scan_finished(struct Scsi_Host *shost, { struct mpi3mr_ioc *mrioc = shost_priv(shost); u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT; + u32 ioc_status = readl(&mrioc->sysif_regs->ioc_status); - if (time >= (pe_timeout * HZ)) { + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { + ioc_err(mrioc, "port enable failed due to fault or reset\n"); + mpi3mr_print_fault_info(mrioc); + mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; + mrioc->scan_started = 0; mrioc->init_cmds.is_waiting = 0; mrioc->init_cmds.callback = NULL; mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; - ioc_err(mrioc, "%s :port enable request timed out\n", __func__); - mrioc->is_driver_loading = 0; - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_PE_TIMEOUT, 1); } - if (mrioc->scan_failed) { - ioc_err(mrioc, - "%s :port enable failed with (ioc_status=0x%08x)\n", - __func__, mrioc->scan_failed); - mrioc->is_driver_loading = 0; - mrioc->stop_drv_processing = 1; - return 1; + if (time >= (pe_timeout * HZ)) { + ioc_err(mrioc, "port enable failed due to time out\n"); + mpi3mr_check_rh_fault_ioc(mrioc, + MPI3MR_RESET_FROM_PE_TIMEOUT); + mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; + mrioc->scan_started = 0; + mrioc->init_cmds.is_waiting = 0; + mrioc->init_cmds.callback = NULL; + mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; } if (mrioc->scan_started) return 0; - ioc_info(mrioc, "%s :port enable: SUCCESS\n", __func__); + + if (mrioc->scan_failed) { + ioc_err(mrioc, + "port enable failed with status=0x%04x\n", + mrioc->scan_failed); + } else + ioc_info(mrioc, "port enable is successfully completed\n"); + mpi3mr_start_watchdog(mrioc); mrioc->is_driver_loading = 0; - return 1; } -- cgit v1.2.3 From c5758fc72b9256aae85f5565f5715a3798d337e0 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:51 +0530 Subject: scsi: mpi3mr: Gracefully handle online FW update operation Enhance driver to gracefully handle discrepancies in certain key data sizes between firmware update operations as mentioned below: - The driver displays an error message and marks the controller as unrecoverable if the firmware reports ReplyFrameSize that is greater than the current ReplyFrameSize. - If the firmware reports ReplyFrameSize greater than the current ReplyFrameSize then the driver uses the current ReplyFrameSize while copying the reply messages. - The driver displays an error message and marks the controller as unrecoverable if the firmware reports MaxOperationalReplyQueues less than the currently allocated operational reply queues count. - If the firmware reports MaxOperationalReplyQueues that is greater than the currently allocated operational reply queue count then the driver ignores the new increased value and uses the previously allocated number of operational queues only. - If the firmware reports MaxDevHandle greater than the previously used MaxDevHandle value after a reset then the driver re-allocates the 'device remove pending bitmap' buffer with the newer size using krealloc(). Link: https://lore.kernel.org/r/20211220141159.16117-18-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 1 + drivers/scsi/mpi3mr/mpi3mr_fw.c | 109 +++++++++++++++++++++++++++++++++------- 2 files changed, 92 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index b24efe2792c7..24b65bb07236 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -752,6 +752,7 @@ struct mpi3mr_ioc { dma_addr_t reply_buf_dma_max_address; u16 reply_free_qsz; + u16 reply_sz; struct dma_pool *reply_free_q_pool; __le64 *reply_free_q; dma_addr_t reply_free_q_dma; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 7a0131e713c5..a9d891457820 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -13,6 +13,8 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason); static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc); +static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, + struct mpi3_ioc_facts_data *facts_data); #if defined(writeq) && defined(CONFIG_64BIT) static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) @@ -376,7 +378,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, if (def_reply) { cmdptr->state |= MPI3MR_CMD_REPLY_VALID; memcpy((u8 *)cmdptr->reply, (u8 *)def_reply, - mrioc->facts.reply_sz); + mrioc->reply_sz); } if (cmdptr->is_waiting) { complete(&cmdptr->done); @@ -996,6 +998,66 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc, return retval; } +/** + * mpi3mr_revalidate_factsdata - validate IOCFacts parameters + * during reset/resume + * @mrioc: Adapter instance reference + * + * Return zero if the new IOCFacts parameters value is compatible with + * older values else return -EPERM + */ +static int +mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc) +{ + u16 dev_handle_bitmap_sz; + void *removepend_bitmap; + + if (mrioc->facts.reply_sz > mrioc->reply_sz) { + ioc_err(mrioc, + "cannot increase reply size from %d to %d\n", + mrioc->reply_sz, mrioc->facts.reply_sz); + return -EPERM; + } + + if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) { + ioc_err(mrioc, + "cannot reduce number of operational reply queues from %d to %d\n", + mrioc->num_op_reply_q, + mrioc->facts.max_op_reply_q); + return -EPERM; + } + + if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) { + ioc_err(mrioc, + "cannot reduce number of operational request queues from %d to %d\n", + mrioc->num_op_req_q, mrioc->facts.max_op_req_q); + return -EPERM; + } + + dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8; + if (mrioc->facts.max_devhandle % 8) + dev_handle_bitmap_sz++; + if (dev_handle_bitmap_sz > mrioc->dev_handle_bitmap_sz) { + removepend_bitmap = krealloc(mrioc->removepend_bitmap, + dev_handle_bitmap_sz, GFP_KERNEL); + if (!removepend_bitmap) { + ioc_err(mrioc, + "failed to increase removepend_bitmap sz from: %d to %d\n", + mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); + return -EPERM; + } + memset(removepend_bitmap + mrioc->dev_handle_bitmap_sz, 0, + dev_handle_bitmap_sz - mrioc->dev_handle_bitmap_sz); + mrioc->removepend_bitmap = removepend_bitmap; + ioc_info(mrioc, + "increased dev_handle_bitmap_sz from %d to %d\n", + mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz); + mrioc->dev_handle_bitmap_sz = dev_handle_bitmap_sz; + } + + return 0; +} + /** * mpi3mr_bring_ioc_ready - Bring controller to ready state * @mrioc: Adapter instance reference @@ -1854,8 +1916,13 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) mrioc->intr_info_count - mrioc->op_reply_q_offset; if (!mrioc->num_queues) mrioc->num_queues = min_t(int, num_queues, msix_count_op_q); - num_queues = mrioc->num_queues; - ioc_info(mrioc, "Trying to create %d Operational Q pairs\n", + /* + * During reset set the num_queues to the number of queues + * that was set before the reset. + */ + num_queues = mrioc->num_op_reply_q ? + mrioc->num_op_reply_q : mrioc->num_queues; + ioc_info(mrioc, "trying to create %d operational queue pairs\n", num_queues); if (!mrioc->req_qinfo) { @@ -2447,6 +2514,7 @@ static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc, goto out_unlock; } memcpy(facts_data, (u8 *)data, data_len); + mpi3mr_process_factsdata(mrioc, facts_data); out_unlock: mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; mutex_unlock(&mrioc->init_cmds.mutex); @@ -2593,12 +2661,6 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n", mrioc->facts.dma_mask, (facts_flags & MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK)); - - mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; - - if (reset_devices) - mrioc->max_host_ios = min_t(int, mrioc->max_host_ios, - MPI3MR_HOST_IOS_KDUMP); } /** @@ -2618,18 +2680,18 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) if (mrioc->init_cmds.reply) return retval; - mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL); + mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->init_cmds.reply) goto out_failed; for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) { - mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz, + mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->dev_rmhs_cmds[i].reply) goto out_failed; } - mrioc->host_tm_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL); + mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->host_tm_cmds.reply) goto out_failed; @@ -2655,7 +2717,7 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1; /* reply buffer pool, 16 byte align */ - sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz; + sz = mrioc->num_reply_bufs * mrioc->reply_sz; mrioc->reply_buf_pool = dma_pool_create("reply_buf pool", &mrioc->pdev->dev, sz, 16, 0); if (!mrioc->reply_buf_pool) { @@ -2731,10 +2793,10 @@ static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc) u32 sz, i; dma_addr_t phy_addr; - sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz; + sz = mrioc->num_reply_bufs * mrioc->reply_sz; ioc_info(mrioc, "reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n", - mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz, + mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz, (sz / 1024), (unsigned long long)mrioc->reply_buf_dma); sz = mrioc->reply_free_qsz * 8; ioc_info(mrioc, @@ -2754,7 +2816,7 @@ static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc) /* initialize Reply buffer Queue */ for (i = 0, phy_addr = mrioc->reply_buf_dma; - i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz) + i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz) mrioc->reply_free_q[i] = cpu_to_le64(phy_addr); mrioc->reply_free_q[i] = cpu_to_le64(0); @@ -3459,7 +3521,13 @@ retry_init: goto out_failed; } - mpi3mr_process_factsdata(mrioc, &facts_data); + mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD; + + if (reset_devices) + mrioc->max_host_ios = min_t(int, mrioc->max_host_ios, + MPI3MR_HOST_IOS_KDUMP); + + mrioc->reply_sz = mrioc->facts.reply_sz; retval = mpi3mr_check_reset_dma_mask(mrioc); if (retval) { @@ -3582,7 +3650,12 @@ retry_init: goto out_failed; } - mpi3mr_process_factsdata(mrioc, &facts_data); + dprint_reset(mrioc, "validating ioc_facts\n"); + retval = mpi3mr_revalidate_factsdata(mrioc); + if (retval) { + ioc_err(mrioc, "failed to revalidate ioc_facts data\n"); + goto out_failed_noretry; + } mpi3mr_print_ioc_info(mrioc); -- cgit v1.2.3 From c1af985d27da2d530c22604644e9025810f57d7c Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:52 +0530 Subject: scsi: mpi3mr: Add Event acknowledgment logic Add Event acknowledgment logic. Link: https://lore.kernel.org/r/20211220141159.16117-19-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 30 +++++++- drivers/scsi/mpi3mr/mpi3mr_fw.c | 48 +++++++++++- drivers/scsi/mpi3mr/mpi3mr_os.c | 158 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 224 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 24b65bb07236..26029570c3eb 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -96,7 +96,11 @@ extern int prot_mask; #define MPI3MR_HOSTTAG_DEVRMCMD_MAX (MPI3MR_HOSTTAG_DEVRMCMD_MIN + \ MPI3MR_NUM_DEVRMCMD - 1) -#define MPI3MR_INTERNAL_CMDS_RESVD MPI3MR_HOSTTAG_DEVRMCMD_MAX +#define MPI3MR_INTERNAL_CMDS_RESVD MPI3MR_HOSTTAG_DEVRMCMD_MAX +#define MPI3MR_NUM_EVTACKCMD 4 +#define MPI3MR_HOSTTAG_EVTACKCMD_MIN (MPI3MR_HOSTTAG_DEVRMCMD_MAX + 1) +#define MPI3MR_HOSTTAG_EVTACKCMD_MAX (MPI3MR_HOSTTAG_EVTACKCMD_MIN + \ + MPI3MR_NUM_EVTACKCMD - 1) /* Reduced resource count definition for crash kernel */ #define MPI3MR_HOST_IOS_KDUMP 128 @@ -674,11 +678,15 @@ struct scmd_priv { * @chain_buf_lock: Chain buffer list lock * @host_tm_cmds: Command tracker for task management commands * @dev_rmhs_cmds: Command tracker for device removal commands + * @evtack_cmds: Command tracker for event ack commands * @devrem_bitmap_sz: Device removal bitmap size * @devrem_bitmap: Device removal bitmap * @dev_handle_bitmap_sz: Device handle bitmap size * @removepend_bitmap: Remove pending bitmap * @delayed_rmhs_list: Delayed device removal list + * @evtack_cmds_bitmap_sz: Event Ack bitmap size + * @evtack_cmds_bitmap: Event Ack bitmap + * @delayed_evtack_cmds_list: Delayed event acknowledgment list * @ts_update_counter: Timestamp update counter * @reset_in_progress: Reset in progress flag * @unrecoverable: Controller unrecoverable flag @@ -800,11 +808,15 @@ struct mpi3mr_ioc { struct mpi3mr_drv_cmd host_tm_cmds; struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD]; + struct mpi3mr_drv_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD]; u16 devrem_bitmap_sz; void *devrem_bitmap; u16 dev_handle_bitmap_sz; void *removepend_bitmap; struct list_head delayed_rmhs_list; + u16 evtack_cmds_bitmap_sz; + void *evtack_cmds_bitmap; + struct list_head delayed_evtack_cmds_list; u32 ts_update_counter; u8 reset_in_progress; @@ -862,6 +874,18 @@ struct delayed_dev_rmhs_node { u8 iou_rc; }; +/** + * struct delayed_evt_ack_node - Delayed event ack node + * @list: list head + * @event: MPI3 event ID + * @event_ctx: event context + */ +struct delayed_evt_ack_node { + struct list_head list; + u8 event; + u32 event_ctx; +}; + int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc); void mpi3mr_cleanup_resources(struct mpi3mr_ioc *mrioc); int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc); @@ -898,7 +922,7 @@ void mpi3mr_ioc_disable_intr(struct mpi3mr_ioc *mrioc); void mpi3mr_ioc_enable_intr(struct mpi3mr_ioc *mrioc); enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc); -int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, +int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event, u32 event_ctx); void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout); @@ -906,7 +930,7 @@ void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc); void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc); void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc); void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc); -void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc); +void mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc); void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc); void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index a9d891457820..b25f8e5ee8a0 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -312,6 +312,12 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag, return &mrioc->dev_rmhs_cmds[idx]; } + if (host_tag >= MPI3MR_HOSTTAG_EVTACKCMD_MIN && + host_tag <= MPI3MR_HOSTTAG_EVTACKCMD_MAX) { + idx = host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; + return &mrioc->evtack_cmds[idx]; + } + return NULL; } @@ -2691,6 +2697,13 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) goto out_failed; } + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { + mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz, + GFP_KERNEL); + if (!mrioc->evtack_cmds[i].reply) + goto out_failed; + } + mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->host_tm_cmds.reply) goto out_failed; @@ -2711,6 +2724,14 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc) if (!mrioc->devrem_bitmap) goto out_failed; + mrioc->evtack_cmds_bitmap_sz = MPI3MR_NUM_EVTACKCMD / 8; + if (MPI3MR_NUM_EVTACKCMD % 8) + mrioc->evtack_cmds_bitmap_sz++; + mrioc->evtack_cmds_bitmap = kzalloc(mrioc->evtack_cmds_bitmap_sz, + GFP_KERNEL); + if (!mrioc->evtack_cmds_bitmap) + goto out_failed; + mrioc->num_reply_bufs = mrioc->facts.max_reqs + MPI3MR_NUM_EVT_REPLIES; mrioc->reply_free_qsz = mrioc->num_reply_bufs + 1; mrioc->num_sense_bufs = mrioc->facts.max_reqs / MPI3MR_SENSEBUF_FACTOR; @@ -3030,17 +3051,17 @@ out: } /** - * mpi3mr_send_event_ack - Send event acknowledgment + * mpi3mr_process_event_ack - Process event acknowledgment * @mrioc: Adapter instance reference * @event: MPI3 event ID - * @event_ctx: Event context + * @event_ctx: event context * * Send event acknowledgment through admin queue and wait for * it to complete. * * Return: 0 on success, non-zero on failures. */ -int mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, +int mpi3mr_process_event_ack(struct mpi3mr_ioc *mrioc, u8 event, u32 event_ctx) { struct mpi3_event_ack_request evtack_req; @@ -3803,8 +3824,13 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) memset(mrioc->dev_rmhs_cmds[i].reply, 0, sizeof(*mrioc->dev_rmhs_cmds[i].reply)); + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) + memset(mrioc->evtack_cmds[i].reply, 0, + sizeof(*mrioc->evtack_cmds[i].reply)); memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); + memset(mrioc->evtack_cmds_bitmap, 0, + mrioc->evtack_cmds_bitmap_sz); } for (i = 0; i < mrioc->num_queues; i++) { @@ -3898,12 +3924,20 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) kfree(mrioc->host_tm_cmds.reply); mrioc->host_tm_cmds.reply = NULL; + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { + kfree(mrioc->evtack_cmds[i].reply); + mrioc->evtack_cmds[i].reply = NULL; + } + kfree(mrioc->removepend_bitmap); mrioc->removepend_bitmap = NULL; kfree(mrioc->devrem_bitmap); mrioc->devrem_bitmap = NULL; + kfree(mrioc->evtack_cmds_bitmap); + mrioc->evtack_cmds_bitmap = NULL; + kfree(mrioc->chain_bitmap); mrioc->chain_bitmap = NULL; @@ -4079,6 +4113,11 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc) cmdptr = &mrioc->dev_rmhs_cmds[i]; mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); } + + for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) { + cmdptr = &mrioc->evtack_cmds[i]; + mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr); + } } /** @@ -4176,10 +4215,11 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, goto out; } - mpi3mr_flush_delayed_rmhs_list(mrioc); + mpi3mr_flush_delayed_cmd_lists(mrioc); mpi3mr_flush_drv_cmds(mrioc); memset(mrioc->devrem_bitmap, 0, mrioc->devrem_bitmap_sz); memset(mrioc->removepend_bitmap, 0, mrioc->dev_handle_bitmap_sz); + memset(mrioc->evtack_cmds_bitmap, 0, mrioc->evtack_cmds_bitmap_sz); mpi3mr_cleanup_fwevt_list(mrioc); mpi3mr_flush_host_io(mrioc); mpi3mr_invalidate_devhandles(mrioc); diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 38e104301142..728d6ce51079 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -34,6 +34,9 @@ MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info (default=0)"); /* Forward declarations*/ +static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, + struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx); + /** * mpi3mr_host_tag_for_scmd - Get host tag for a scmd * @mrioc: Adapter instance reference @@ -1336,7 +1339,7 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, evt_ack: if (fwevt->send_ack) - mpi3mr_send_event_ack(mrioc, fwevt->event_id, + mpi3mr_process_event_ack(mrioc, fwevt->event_id, fwevt->evt_ctx); out: /* Put fwevt reference count to neutralize kref_init increment */ @@ -1400,24 +1403,33 @@ static int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc, } /** - * mpi3mr_flush_delayed_rmhs_list - Flush pending commands + * mpi3mr_flush_delayed_cmd_lists - Flush pending commands * @mrioc: Adapter instance reference * - * Flush pending commands in the delayed removal handshake list - * due to a controller reset or driver removal as a cleanup. + * Flush pending commands in the delayed lists due to a + * controller reset or driver removal as a cleanup. * * Return: Nothing */ -void mpi3mr_flush_delayed_rmhs_list(struct mpi3mr_ioc *mrioc) +void mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc) { struct delayed_dev_rmhs_node *_rmhs_node; + struct delayed_evt_ack_node *_evtack_node; + dprint_reset(mrioc, "flushing delayed dev_remove_hs commands\n"); while (!list_empty(&mrioc->delayed_rmhs_list)) { _rmhs_node = list_entry(mrioc->delayed_rmhs_list.next, struct delayed_dev_rmhs_node, list); list_del(&_rmhs_node->list); kfree(_rmhs_node); } + dprint_reset(mrioc, "flushing delayed event ack commands\n"); + while (!list_empty(&mrioc->delayed_evtack_cmds_list)) { + _evtack_node = list_entry(mrioc->delayed_evtack_cmds_list.next, + struct delayed_evt_ack_node, list); + list_del(&_evtack_node->list); + kfree(_evtack_node); + } } /** @@ -1633,6 +1645,141 @@ out_failed: clear_bit(cmd_idx, mrioc->devrem_bitmap); } +/** + * mpi3mr_complete_evt_ack - event ack request completion + * @mrioc: Adapter instance reference + * @drv_cmd: Internal command tracker + * + * This is the completion handler for non blocking event + * acknowledgment sent to the firmware and this will issue any + * pending event acknowledgment request. + * + * Return: Nothing + */ +static void mpi3mr_complete_evt_ack(struct mpi3mr_ioc *mrioc, + struct mpi3mr_drv_cmd *drv_cmd) +{ + u16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; + struct delayed_evt_ack_node *delayed_evtack = NULL; + + if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { + dprint_event_th(mrioc, + "immediate event ack failed with ioc_status(0x%04x) log_info(0x%08x)\n", + (drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK), + drv_cmd->ioc_loginfo); + } + + if (!list_empty(&mrioc->delayed_evtack_cmds_list)) { + delayed_evtack = + list_entry(mrioc->delayed_evtack_cmds_list.next, + struct delayed_evt_ack_node, list); + mpi3mr_send_event_ack(mrioc, delayed_evtack->event, drv_cmd, + delayed_evtack->event_ctx); + list_del(&delayed_evtack->list); + kfree(delayed_evtack); + return; + } + drv_cmd->state = MPI3MR_CMD_NOTUSED; + drv_cmd->callback = NULL; + clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap); +} + +/** + * mpi3mr_send_event_ack - Issue event acknwoledgment request + * @mrioc: Adapter instance reference + * @event: MPI3 event id + * @cmdparam: Internal command tracker + * @event_ctx: event context + * + * Issues event acknowledgment request to the firmware if there + * is a free command to send the event ack else it to a pend + * list so that it will be processed on a completion of a prior + * event acknowledgment . + * + * Return: Nothing + */ +static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event, + struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx) +{ + struct mpi3_event_ack_request evtack_req; + int retval = 0; + u8 retrycount = 5; + u16 cmd_idx = MPI3MR_NUM_EVTACKCMD; + struct mpi3mr_drv_cmd *drv_cmd = cmdparam; + struct delayed_evt_ack_node *delayed_evtack = NULL; + + if (drv_cmd) { + dprint_event_th(mrioc, + "sending delayed event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n", + event, event_ctx); + goto issue_cmd; + } + dprint_event_th(mrioc, + "sending event ack in the top half for event(0x%02x), event_ctx(0x%08x)\n", + event, event_ctx); + do { + cmd_idx = find_first_zero_bit(mrioc->evtack_cmds_bitmap, + MPI3MR_NUM_EVTACKCMD); + if (cmd_idx < MPI3MR_NUM_EVTACKCMD) { + if (!test_and_set_bit(cmd_idx, + mrioc->evtack_cmds_bitmap)) + break; + cmd_idx = MPI3MR_NUM_EVTACKCMD; + } + } while (retrycount--); + + if (cmd_idx >= MPI3MR_NUM_EVTACKCMD) { + delayed_evtack = kzalloc(sizeof(*delayed_evtack), + GFP_ATOMIC); + if (!delayed_evtack) + return; + INIT_LIST_HEAD(&delayed_evtack->list); + delayed_evtack->event = event; + delayed_evtack->event_ctx = event_ctx; + list_add_tail(&delayed_evtack->list, + &mrioc->delayed_evtack_cmds_list); + dprint_event_th(mrioc, + "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is postponed\n", + event, event_ctx); + return; + } + drv_cmd = &mrioc->evtack_cmds[cmd_idx]; + +issue_cmd: + cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_EVTACKCMD_MIN; + + memset(&evtack_req, 0, sizeof(evtack_req)); + if (drv_cmd->state & MPI3MR_CMD_PENDING) { + dprint_event_th(mrioc, + "sending event ack failed due to command in use\n"); + goto out; + } + drv_cmd->state = MPI3MR_CMD_PENDING; + drv_cmd->is_waiting = 0; + drv_cmd->callback = mpi3mr_complete_evt_ack; + evtack_req.host_tag = cpu_to_le16(drv_cmd->host_tag); + evtack_req.function = MPI3_FUNCTION_EVENT_ACK; + evtack_req.event = event; + evtack_req.event_context = cpu_to_le32(event_ctx); + retval = mpi3mr_admin_request_post(mrioc, &evtack_req, + sizeof(evtack_req), 1); + if (retval) { + dprint_event_th(mrioc, + "posting event ack request is failed\n"); + goto out_failed; + } + + dprint_event_th(mrioc, + "event ack in the top half for event(0x%02x), event_ctx(0x%08x) is posted\n", + event, event_ctx); +out: + return; +out_failed: + drv_cmd->state = MPI3MR_CMD_NOTUSED; + drv_cmd->callback = NULL; + clear_bit(cmd_idx, mrioc->evtack_cmds_bitmap); +} + /** * mpi3mr_pcietopochg_evt_th - PCIETopologyChange evt tophalf * @mrioc: Adapter instance reference @@ -3773,6 +3920,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&mrioc->fwevt_list); INIT_LIST_HEAD(&mrioc->tgtdev_list); INIT_LIST_HEAD(&mrioc->delayed_rmhs_list); + INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list); mutex_init(&mrioc->reset_mutex); mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS); -- cgit v1.2.3 From 78b76a0768ef8a25ab92a28da4ac9a74db762c47 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:53 +0530 Subject: scsi: mpi3mr: Support Prepare for Reset event The IOC sends a Prepare for Reset Event to the host to prepare for a Soft Reset. This event data has two reason codes: 1. Start - The host is expected to gracefully quiesce all I/O within approximately 1 second. 2. Abort - The IOC is requesting to abort a previous Prepare for Reset Event request. Normal I/O may be resumed. Link: https://lore.kernel.org/r/20211220141159.16117-20-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 6 +++ drivers/scsi/mpi3mr/mpi3mr_fw.c | 83 +++++++++++++++++++++++++---------------- drivers/scsi/mpi3mr/mpi3mr_os.c | 40 ++++++++++++++++++++ 3 files changed, 96 insertions(+), 33 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 26029570c3eb..8dd669fa5efb 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -114,6 +114,7 @@ extern int prot_mask; #define MPI3MR_TSUPDATE_INTERVAL 900 #define MPI3MR_DEFAULT_SHUTDOWN_TIME 120 #define MPI3MR_RAID_ERRREC_RESET_TIMEOUT 180 +#define MPI3MR_PREPARE_FOR_RESET_TIMEOUT 180 #define MPI3MR_RESET_ACK_TIMEOUT 30 #define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */ @@ -693,6 +694,8 @@ struct scmd_priv { * @prev_reset_result: Result of previous reset * @reset_mutex: Controller reset mutex * @reset_waitq: Controller reset wait queue + * @prepare_for_reset: Prepare for reset event received + * @prepare_for_reset_timeout_counter: Prepare for reset timeout * @diagsave_timeout: Diagnostic information save timeout * @logging_level: Controller debug logging level * @flush_io_count: I/O count to flush after reset @@ -825,6 +828,9 @@ struct mpi3mr_ioc { struct mutex reset_mutex; wait_queue_head_t reset_waitq; + u8 prepare_for_reset; + u16 prepare_for_reset_timeout_counter; + u16 diagsave_timeout; int logging_level; u16 flush_io_count; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index b25f8e5ee8a0..a9491f790cd8 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -2262,7 +2262,8 @@ static void mpi3mr_watchdog_work(struct work_struct *work) container_of(work, struct mpi3mr_ioc, watchdog_work.work); unsigned long flags; enum mpi3mr_iocstate ioc_state; - u32 fault, host_diagnostic; + u32 fault, host_diagnostic, ioc_status; + u32 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH; if (mrioc->reset_in_progress || mrioc->unrecoverable) return; @@ -2272,43 +2273,55 @@ static void mpi3mr_watchdog_work(struct work_struct *work) mpi3mr_sync_timestamp(mrioc); } + if ((mrioc->prepare_for_reset) && + ((mrioc->prepare_for_reset_timeout_counter++) >= + MPI3MR_PREPARE_FOR_RESET_TIMEOUT)) { + mpi3mr_soft_reset_handler(mrioc, + MPI3MR_RESET_FROM_CIACTVRST_TIMER, 1); + return; + } + + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { + mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0); + return; + } + /*Check for fault state every one second and issue Soft reset*/ ioc_state = mpi3mr_get_iocstate(mrioc); - if (ioc_state == MRIOC_STATE_FAULT) { - fault = readl(&mrioc->sysif_regs->fault) & - MPI3_SYSIF_FAULT_CODE_MASK; - host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); - if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { - if (!mrioc->diagsave_timeout) { - mpi3mr_print_fault_info(mrioc); - ioc_warn(mrioc, "Diag save in progress\n"); - } - if ((mrioc->diagsave_timeout++) <= - MPI3_SYSIF_DIAG_SAVE_TIMEOUT) - goto schedule_work; - } else - mpi3mr_print_fault_info(mrioc); - mrioc->diagsave_timeout = 0; + if (ioc_state != MRIOC_STATE_FAULT) + goto schedule_work; - if (fault == MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED) { - ioc_info(mrioc, - "Factory Reset fault occurred marking controller as unrecoverable" - ); - mrioc->unrecoverable = 1; - goto out; + fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; + host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); + if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { + if (!mrioc->diagsave_timeout) { + mpi3mr_print_fault_info(mrioc); + ioc_warn(mrioc, "diag save in progress\n"); } + if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT) + goto schedule_work; + } - if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) || - (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS) || - (mrioc->reset_in_progress)) - goto out; - if (fault == MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET) - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_CIACTIV_FAULT, 0); - else - mpi3mr_soft_reset_handler(mrioc, - MPI3MR_RESET_FROM_FAULT_WATCH, 0); + mpi3mr_print_fault_info(mrioc); + mrioc->diagsave_timeout = 0; + + switch (fault) { + case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: + ioc_info(mrioc, + "controller requires system power cycle, marking controller as unrecoverable\n"); + mrioc->unrecoverable = 1; + return; + case MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS: + return; + case MPI3_SYSIF_FAULT_CODE_CI_ACTIVATION_RESET: + reset_reason = MPI3MR_RESET_FROM_CIACTIV_FAULT; + break; + default: + break; } + mpi3mr_soft_reset_handler(mrioc, reset_reason, 0); + return; schedule_work: spin_lock_irqsave(&mrioc->watchdog_lock, flags); @@ -2317,7 +2330,6 @@ schedule_work: &mrioc->watchdog_work, msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL)); spin_unlock_irqrestore(&mrioc->watchdog_lock, flags); -out: return; } @@ -3488,6 +3500,7 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_BROADCAST_PRIMITIVE); mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); mpi3mr_unmask_events(mrioc, MPI3_EVENT_PCIE_ENUMERATION); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET); mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); @@ -4223,6 +4236,10 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, mpi3mr_cleanup_fwevt_list(mrioc); mpi3mr_flush_host_io(mrioc); mpi3mr_invalidate_devhandles(mrioc); + if (mrioc->prepare_for_reset) { + mrioc->prepare_for_reset = 0; + mrioc->prepare_for_reset_timeout_counter = 0; + } mpi3mr_memset_buffers(mrioc); retval = mpi3mr_reinit_ioc(mrioc, 0); if (retval) { diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 728d6ce51079..192986f38533 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1988,6 +1988,40 @@ out: mpi3mr_tgtdev_put(tgtdev); } +/** + * mpi3mr_preparereset_evt_th - Prepare for reset event tophalf + * @mrioc: Adapter instance reference + * @event_reply: event data + * + * Blocks and unblocks host level I/O based on the reason code + * + * Return: Nothing + */ +static void mpi3mr_preparereset_evt_th(struct mpi3mr_ioc *mrioc, + struct mpi3_event_notification_reply *event_reply) +{ + struct mpi3_event_data_prepare_for_reset *evtdata = + (struct mpi3_event_data_prepare_for_reset *)event_reply->event_data; + + if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_START) { + dprint_event_th(mrioc, + "prepare for reset event top half with rc=start\n"); + if (mrioc->prepare_for_reset) + return; + mrioc->prepare_for_reset = 1; + mrioc->prepare_for_reset_timeout_counter = 0; + } else if (evtdata->reason_code == MPI3_EVENT_PREPARE_RESET_RC_ABORT) { + dprint_event_th(mrioc, + "prepare for reset top half with rc=abort\n"); + mrioc->prepare_for_reset = 0; + mrioc->prepare_for_reset_timeout_counter = 0; + } + if ((event_reply->msg_flags & MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_MASK) + == MPI3_EVENT_NOTIFY_MSGFLAGS_ACK_REQUIRED) + mpi3mr_send_event_ack(mrioc, event_reply->event, NULL, + le32_to_cpu(event_reply->event_context)); +} + /** * mpi3mr_energypackchg_evt_th - Energy pack change evt tophalf * @mrioc: Adapter instance reference @@ -2075,6 +2109,12 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, mpi3mr_pcietopochg_evt_th(mrioc, event_reply); break; } + case MPI3_EVENT_PREPARE_FOR_RESET: + { + mpi3mr_preparereset_evt_th(mrioc, event_reply); + ack_req = 0; + break; + } case MPI3_EVENT_DEVICE_INFO_CHANGED: { process_evt_bh = 1; -- cgit v1.2.3 From 95cca8d5542a4cde0d3dd685f4108295ca28b63d Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:54 +0530 Subject: scsi: mpi3mr: Print cable mngnt and temp threshold events Print cable management & temperature threshold event data. Use vendor id & device id macro definitions from MPI3 headers. Link: https://lore.kernel.org/r/20211220141159.16117-21-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_fw.c | 1 + drivers/scsi/mpi3mr/mpi3mr_os.c | 75 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index a9491f790cd8..a4decaa89e8d 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3503,6 +3503,7 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc) mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET); mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT); mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE); + mpi3mr_unmask_events(mrioc, MPI3_EVENT_TEMP_THRESHOLD); retval = mpi3mr_issue_event_notification(mrioc); if (retval) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 192986f38533..d893c6d61a60 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -2051,6 +2051,66 @@ static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc, mrioc->facts.shutdown_timeout = shutdown_timeout; } +/** + * mpi3mr_tempthreshold_evt_th - Temp threshold event tophalf + * @mrioc: Adapter instance reference + * @event_reply: event data + * + * Displays temperature threshold event details and fault code + * if any is hit due to temperature exceeding threshold. + * + * Return: Nothing + */ +static void mpi3mr_tempthreshold_evt_th(struct mpi3mr_ioc *mrioc, + struct mpi3_event_notification_reply *event_reply) +{ + struct mpi3_event_data_temp_threshold *evtdata = + (struct mpi3_event_data_temp_threshold *)event_reply->event_data; + + ioc_err(mrioc, "Temperature threshold levels %s%s%s exceeded for sensor: %d !!! Current temperature in Celsius: %d\n", + (le16_to_cpu(evtdata->status) & 0x1) ? "Warning " : " ", + (le16_to_cpu(evtdata->status) & 0x2) ? "Critical " : " ", + (le16_to_cpu(evtdata->status) & 0x4) ? "Fatal " : " ", evtdata->sensor_num, + le16_to_cpu(evtdata->current_temperature)); + mpi3mr_print_fault_info(mrioc); +} + +/** + * mpi3mr_cablemgmt_evt_th - Cable management event tophalf + * @mrioc: Adapter instance reference + * @event_reply: event data + * + * Displays Cable manegemt event details. + * + * Return: Nothing + */ +static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc *mrioc, + struct mpi3_event_notification_reply *event_reply) +{ + struct mpi3_event_data_cable_management *evtdata = + (struct mpi3_event_data_cable_management *)event_reply->event_data; + + switch (evtdata->status) { + case MPI3_EVENT_CABLE_MGMT_STATUS_INSUFFICIENT_POWER: + { + ioc_info(mrioc, "An active cable with receptacle_id %d cannot be powered.\n" + "Devices connected to this cable are not detected.\n" + "This cable requires %d mW of power.\n", + evtdata->receptacle_id, + le32_to_cpu(evtdata->active_cable_power_requirement)); + break; + } + case MPI3_EVENT_CABLE_MGMT_STATUS_DEGRADED: + { + ioc_info(mrioc, "A cable with receptacle_id %d is not running at optimal speed\n", + evtdata->receptacle_id); + break; + } + default: + break; + } +} + /** * mpi3mr_os_handle_events - Firmware event handler * @mrioc: Adapter instance reference @@ -2125,9 +2185,18 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, mpi3mr_energypackchg_evt_th(mrioc, event_reply); break; } + case MPI3_EVENT_TEMP_THRESHOLD: + { + mpi3mr_tempthreshold_evt_th(mrioc, event_reply); + break; + } + case MPI3_EVENT_CABLE_MGMT: + { + mpi3mr_cablemgmt_evt_th(mrioc, event_reply); + break; + } case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: case MPI3_EVENT_SAS_DISCOVERY: - case MPI3_EVENT_CABLE_MGMT: case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR: case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE: case MPI3_EVENT_PCIE_ENUMERATION: @@ -4247,8 +4316,8 @@ static int mpi3mr_resume(struct pci_dev *pdev) static const struct pci_device_id mpi3mr_pci_id_table[] = { { - PCI_DEVICE_SUB(PCI_VENDOR_ID_LSI_LOGIC, 0x00A5, - PCI_ANY_ID, PCI_ANY_ID) + PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, + MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID) }, { 0 } }; -- cgit v1.2.3 From afd3a5793fe2a217513bc5eb2228a5ca8e8b556a Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:55 +0530 Subject: scsi: mpi3mr: Add io_uring interface support in I/O-polled mode Add support for the io_uring interface in I/O-polled mode. This feature is disabled in the driver by default. To enable the feature, a module parameter "poll_queues" has to be set with the desired number of polling queues. When the feature is enabled, the driver reserves a certain number of operational queue pairs for the poll_queues either from the available queue pairs or creates additional queue pairs based on the operational queue availability. The Polling queues will have corresponding IRQ and ISR functions as similar to default queues. However, the IRQ line is disabled by the driver for poll_queues. Link: https://lore.kernel.org/r/20211220141159.16117-22-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 18 ++++ drivers/scsi/mpi3mr/mpi3mr_fw.c | 184 +++++++++++++++++++++++++++++++++------- drivers/scsi/mpi3mr/mpi3mr_os.c | 46 ++++++++-- 3 files changed, 210 insertions(+), 38 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 8dd669fa5efb..64783a8e05aa 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -220,6 +220,12 @@ enum mpi3mr_reset_reason { MPI3MR_RESET_FROM_FIRMWARE = 27, }; +/* Queue type definitions */ +enum queue_type { + MPI3MR_DEFAULT_QUEUE = 0, + MPI3MR_POLL_QUEUE, +}; + /** * struct mpi3mr_compimg_ver - replica of component image * version defined in mpi30_image.h in host endianness @@ -331,6 +337,7 @@ struct op_req_qinfo { * @pend_ios: Number of IOs pending in HW for this queue * @enable_irq_poll: Flag to indicate polling is enabled * @in_use: Queue is handled by poll/ISR + * @qtype: Type of queue (types defined in enum queue_type) */ struct op_reply_qinfo { u16 ci; @@ -345,6 +352,7 @@ struct op_reply_qinfo { atomic_t pend_ios; bool enable_irq_poll; atomic_t in_use; + enum queue_type qtype; }; /** @@ -703,6 +711,9 @@ struct scmd_priv { * @driver_info: Driver, Kernel, OS information to firmware * @change_count: Topology change count * @op_reply_q_offset: Operational reply queue offset with MSIx + * @default_qcount: Total Default queues + * @active_poll_qcount: Currently active poll queue count + * @requested_poll_qcount: User requested poll queue count */ struct mpi3mr_ioc { struct list_head list; @@ -839,6 +850,10 @@ struct mpi3mr_ioc { struct mpi3_driver_info_layout driver_info; u16 change_count; u16 op_reply_q_offset; + + u16 default_qcount; + u16 active_poll_qcount; + u16 requested_poll_qcount; }; /** @@ -940,5 +955,8 @@ void mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc); void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc); void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); +int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, + struct op_reply_qinfo *op_reply_q); +int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num); #endif /*MPI3MR_H_INCLUDED*/ diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index a4decaa89e8d..0fa66b34f0a6 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -16,6 +16,10 @@ static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc); static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, struct mpi3_ioc_facts_data *facts_data); +static int poll_queues; +module_param(poll_queues, int, 0444); +MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); + #if defined(writeq) && defined(CONFIG_64BIT) static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr) { @@ -461,10 +465,21 @@ mpi3mr_get_reply_desc(struct op_reply_qinfo *op_reply_q, u32 reply_ci) return reply_desc; } -static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, - struct mpi3mr_intr_info *intr_info) +/** + * mpi3mr_process_op_reply_q - Operational reply queue handler + * @mrioc: Adapter instance reference + * @op_reply_q: Operational reply queue info + * + * Checks the specific operational reply queue and drains the + * reply queue entries until the queue is empty and process the + * individual reply descriptors. + * + * Return: 0 if queue is already processed,or number of reply + * descriptors processed. + */ +int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, + struct op_reply_qinfo *op_reply_q) { - struct op_reply_qinfo *op_reply_q = intr_info->op_reply_q; struct op_req_qinfo *op_req_q; u32 exp_phase; u32 reply_ci; @@ -515,7 +530,7 @@ static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, * Ensure remaining completion happens from threaded ISR. */ if (num_op_reply > mrioc->max_host_ios) { - intr_info->op_reply_q->enable_irq_poll = true; + op_reply_q->enable_irq_poll = true; break; } @@ -530,6 +545,34 @@ static int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, return num_op_reply; } +/** + * mpi3mr_blk_mq_poll - Operational reply queue handler + * @shost: SCSI Host reference + * @queue_num: Request queue number (w.r.t OS it is hardware context number) + * + * Checks the specific operational reply queue and drains the + * reply queue entries until the queue is empty and process the + * individual reply descriptors. + * + * Return: 0 if queue is already processed,or number of reply + * descriptors processed. + */ +int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) +{ + int num_entries = 0; + struct mpi3mr_ioc *mrioc; + + mrioc = (struct mpi3mr_ioc *)shost->hostdata; + + if ((mrioc->reset_in_progress || mrioc->prepare_for_reset)) + return 0; + + num_entries = mpi3mr_process_op_reply_q(mrioc, + &mrioc->op_reply_qinfo[queue_num]); + + return num_entries; +} + static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) { struct mpi3mr_intr_info *intr_info = privdata; @@ -550,7 +593,8 @@ static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata) if (!midx) num_admin_replies = mpi3mr_process_admin_reply_q(mrioc); if (intr_info->op_reply_q) - num_op_reply = mpi3mr_process_op_reply_q(mrioc, intr_info); + num_op_reply = mpi3mr_process_op_reply_q(mrioc, + intr_info->op_reply_q); if (num_admin_replies || num_op_reply) return IRQ_HANDLED; @@ -621,9 +665,10 @@ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) mpi3mr_process_admin_reply_q(mrioc); if (intr_info->op_reply_q) num_op_reply += - mpi3mr_process_op_reply_q(mrioc, intr_info); + mpi3mr_process_op_reply_q(mrioc, + intr_info->op_reply_q); - usleep_range(mrioc->irqpoll_sleep, 10 * mrioc->irqpoll_sleep); + usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP); } while (atomic_read(&intr_info->op_reply_q->pend_ios) && (num_op_reply < mrioc->max_host_ios)); @@ -667,6 +712,25 @@ static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) return retval; } +static void mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors) +{ + if (!mrioc->requested_poll_qcount) + return; + + /* Reserved for Admin and Default Queue */ + if (max_vectors > 2 && + (mrioc->requested_poll_qcount < max_vectors - 2)) { + ioc_info(mrioc, + "enabled polled queues (%d) msix (%d)\n", + mrioc->requested_poll_qcount, max_vectors); + } else { + ioc_info(mrioc, + "disabled polled queues (%d) msix (%d) because of no resources for default queue\n", + mrioc->requested_poll_qcount, max_vectors); + mrioc->requested_poll_qcount = 0; + } +} + /** * mpi3mr_setup_isr - Setup ISR for the controller * @mrioc: Adapter instance reference @@ -679,51 +743,72 @@ static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) static int mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one) { unsigned int irq_flags = PCI_IRQ_MSIX; - int max_vectors; + int max_vectors, min_vec; int retval; int i; - struct irq_affinity desc = { .pre_vectors = 1}; + struct irq_affinity desc = { .pre_vectors = 1, .post_vectors = 1 }; if (mrioc->is_intr_info_set) return 0; mpi3mr_cleanup_isr(mrioc); - if (setup_one || reset_devices) + if (setup_one || reset_devices) { max_vectors = 1; - else { + retval = pci_alloc_irq_vectors(mrioc->pdev, + 1, max_vectors, irq_flags); + if (retval < 0) { + ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n", + retval); + goto out_failed; + } + } else { max_vectors = - min_t(int, mrioc->cpu_count + 1, mrioc->msix_count); + min_t(int, mrioc->cpu_count + 1 + + mrioc->requested_poll_qcount, mrioc->msix_count); + + mpi3mr_calc_poll_queues(mrioc, max_vectors); ioc_info(mrioc, "MSI-X vectors supported: %d, no of cores: %d,", mrioc->msix_count, mrioc->cpu_count); ioc_info(mrioc, - "MSI-x vectors requested: %d\n", max_vectors); - } + "MSI-x vectors requested: %d poll_queues %d\n", + max_vectors, mrioc->requested_poll_qcount); + + desc.post_vectors = mrioc->requested_poll_qcount; + min_vec = desc.pre_vectors + desc.post_vectors; + irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; + + retval = pci_alloc_irq_vectors_affinity(mrioc->pdev, + min_vec, max_vectors, irq_flags, &desc); + + if (retval < 0) { + ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n", + retval); + goto out_failed; + } - irq_flags |= PCI_IRQ_AFFINITY | PCI_IRQ_ALL_TYPES; - mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0; - retval = pci_alloc_irq_vectors_affinity(mrioc->pdev, - 1, max_vectors, irq_flags, &desc); - if (retval < 0) { - ioc_err(mrioc, "Cannot alloc irq vectors\n"); - goto out_failed; - } - if (retval != max_vectors) { - ioc_info(mrioc, - "allocated vectors (%d) are less than configured (%d)\n", - retval, max_vectors); /* * If only one MSI-x is allocated, then MSI-x 0 will be shared * between Admin queue and operational queue */ - if (retval == 1) + if (retval == min_vec) mrioc->op_reply_q_offset = 0; + else if (retval != (max_vectors)) { + ioc_info(mrioc, + "allocated vectors (%d) are less than configured (%d)\n", + retval, max_vectors); + } max_vectors = retval; + mrioc->op_reply_q_offset = (max_vectors > 1) ? 1 : 0; + + mpi3mr_calc_poll_queues(mrioc, max_vectors); + } + mrioc->intr_info = kzalloc(sizeof(struct mpi3mr_intr_info) * max_vectors, GFP_KERNEL); if (!mrioc->intr_info) { @@ -1511,10 +1596,11 @@ static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) { struct mpi3_delete_reply_queue_request delq_req; + struct op_reply_qinfo *op_reply_q = mrioc->op_reply_qinfo + qidx; int retval = 0; u16 reply_qid = 0, midx; - reply_qid = mrioc->op_reply_qinfo[qidx].qid; + reply_qid = op_reply_q->qid; midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, mrioc->op_reply_q_offset); @@ -1524,6 +1610,9 @@ static int mpi3mr_delete_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) goto out; } + (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount-- : + mrioc->active_poll_qcount--; + memset(&delq_req, 0, sizeof(delq_req)); mutex_lock(&mrioc->init_cmds.mutex); if (mrioc->init_cmds.state & MPI3MR_CMD_PENDING) { @@ -1748,8 +1837,26 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) create_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_INITCMDS); create_req.function = MPI3_FUNCTION_CREATE_REPLY_QUEUE; create_req.queue_id = cpu_to_le16(reply_qid); - create_req.flags = MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; - create_req.msix_index = cpu_to_le16(mrioc->intr_info[midx].msix_index); + + if (midx < (mrioc->intr_info_count - mrioc->requested_poll_qcount)) + op_reply_q->qtype = MPI3MR_DEFAULT_QUEUE; + else + op_reply_q->qtype = MPI3MR_POLL_QUEUE; + + if (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) { + create_req.flags = + MPI3_CREATE_REPLY_QUEUE_FLAGS_INT_ENABLE_ENABLE; + create_req.msix_index = + cpu_to_le16(mrioc->intr_info[midx].msix_index); + } else { + create_req.msix_index = cpu_to_le16(mrioc->intr_info_count - 1); + ioc_info(mrioc, "create reply queue(polled): for qid(%d), midx(%d)\n", + reply_qid, midx); + if (!mrioc->active_poll_qcount) + disable_irq_nosync(pci_irq_vector(mrioc->pdev, + mrioc->intr_info_count - 1)); + } + if (mrioc->enable_segqueue) { create_req.flags |= MPI3_CREATE_REQUEST_QUEUE_FLAGS_SEGMENTED_SEGMENTED; @@ -1790,6 +1897,9 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) if (midx < mrioc->intr_info_count) mrioc->intr_info[midx].op_reply_q = op_reply_q; + (op_reply_q->qtype == MPI3MR_DEFAULT_QUEUE) ? mrioc->default_qcount++ : + mrioc->active_poll_qcount++; + out_unlock: mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED; mutex_unlock(&mrioc->init_cmds.mutex); @@ -1970,8 +2080,10 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc) goto out_failed; } mrioc->num_op_reply_q = mrioc->num_op_req_q = i; - ioc_info(mrioc, "Successfully created %d Operational Q pairs\n", - mrioc->num_op_reply_q); + ioc_info(mrioc, + "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n", + mrioc->num_op_reply_q, mrioc->default_qcount, + mrioc->active_poll_qcount); return retval; out_failed: @@ -2019,7 +2131,7 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc, if (mpi3mr_check_req_qfull(op_req_q)) { midx = REPLY_QUEUE_IDX_TO_MSIX_IDX( reply_qidx, mrioc->op_reply_q_offset); - mpi3mr_process_op_reply_q(mrioc, &mrioc->intr_info[midx]); + mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q); if (mpi3mr_check_req_qfull(op_req_q)) { retval = -EAGAIN; @@ -3465,6 +3577,10 @@ int mpi3mr_setup_resources(struct mpi3mr_ioc *mrioc) mrioc->sysif_regs, memap_sz); ioc_info(mrioc, "Number of MSI-X vectors found in capabilities: (%d)\n", mrioc->msix_count); + + if (!reset_devices && poll_queues > 0) + mrioc->requested_poll_qcount = min_t(int, poll_queues, + mrioc->msix_count - 2); return retval; out_failed: @@ -3826,6 +3942,8 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc) u16 i; mrioc->change_count = 0; + mrioc->active_poll_qcount = 0; + mrioc->default_qcount = 0; if (mrioc->admin_req_base) memset(mrioc->admin_req_base, 0, mrioc->admin_req_q_sz); if (mrioc->admin_reply_base) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index d893c6d61a60..8bf1b590cc58 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -3049,17 +3049,49 @@ static int mpi3mr_bios_param(struct scsi_device *sdev, * mpi3mr_map_queues - Map queues callback handler * @shost: SCSI host reference * - * Call the blk_mq_pci_map_queues with from which operational - * queue the mapping has to be done + * Maps default and poll queues. * - * Return: return of blk_mq_pci_map_queues + * Return: return zero. */ static int mpi3mr_map_queues(struct Scsi_Host *shost) { struct mpi3mr_ioc *mrioc = shost_priv(shost); + int i, qoff, offset; + struct blk_mq_queue_map *map = NULL; + + offset = mrioc->op_reply_q_offset; + + for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { + map = &shost->tag_set.map[i]; + + map->nr_queues = 0; + + if (i == HCTX_TYPE_DEFAULT) + map->nr_queues = mrioc->default_qcount; + else if (i == HCTX_TYPE_POLL) + map->nr_queues = mrioc->active_poll_qcount; + + if (!map->nr_queues) { + BUG_ON(i == HCTX_TYPE_DEFAULT); + continue; + } + + /* + * The poll queue(s) doesn't have an IRQ (and hence IRQ + * affinity), so use the regular blk-mq cpu mapping + */ + map->queue_offset = qoff; + if (i != HCTX_TYPE_POLL) + blk_mq_pci_map_queues(map, mrioc->pdev, offset); + else + blk_mq_map_queues(map); + + qoff += map->nr_queues; + offset += map->nr_queues; + } + + return 0; - return blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT], - mrioc->pdev, mrioc->op_reply_q_offset); } /** @@ -3873,6 +3905,7 @@ static struct scsi_host_template mpi3mr_driver_template = { .eh_host_reset_handler = mpi3mr_eh_host_reset, .bios_param = mpi3mr_bios_param, .map_queues = mpi3mr_map_queues, + .mq_poll = mpi3mr_blk_mq_poll, .no_write_same = 1, .can_queue = 1, .this_id = -1, @@ -4105,6 +4138,9 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) } shost->nr_hw_queues = mrioc->num_op_reply_q; + if (mrioc->active_poll_qcount) + shost->nr_maps = 3; + shost->can_queue = mrioc->max_host_ios; shost->sg_tablesize = MPI3MR_SG_DEPTH; shost->max_id = mrioc->facts.max_perids + 1; -- cgit v1.2.3 From c86651345ca55be6670faffa4aba104616461243 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:56 +0530 Subject: scsi: mpi3mr: Use TM response codes from MPI3 headers Remove locally defined TM response codes and use codes from MPI3 headers. Link: https://lore.kernel.org/r/20211220141159.16117-23-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 7 ------ drivers/scsi/mpi3mr/mpi3mr_os.c | 54 ++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 64783a8e05aa..e9e7a869ef10 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -142,13 +142,6 @@ extern int prot_mask; /* ResponseCode definitions */ #define MPI3MR_RI_MASK_RESPCODE (0x000000FF) -#define MPI3MR_RSP_TM_COMPLETE 0x00 -#define MPI3MR_RSP_INVALID_FRAME 0x02 -#define MPI3MR_RSP_TM_NOT_SUPPORTED 0x04 -#define MPI3MR_RSP_TM_FAILED 0x05 -#define MPI3MR_RSP_TM_SUCCEEDED 0x08 -#define MPI3MR_RSP_TM_INVALID_LUN 0x09 -#define MPI3MR_RSP_TM_OVERLAPPED_TAG 0x0A #define MPI3MR_RSP_IO_QUEUED_ON_IOC \ MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 8bf1b590cc58..b2f1c6a79ea0 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -2799,49 +2799,52 @@ static int mpi3mr_build_sg_scmd(struct mpi3mr_ioc *mrioc, } /** - * mpi3mr_print_response_code - print TM response as a string - * @mrioc: Adapter instance reference + * mpi3mr_tm_response_name - get TM response as a string * @resp_code: TM response code * - * Print TM response code as a readable string. + * Convert known task management response code as a readable + * string. * - * Return: Nothing. + * Return: response code string. */ -static void mpi3mr_print_response_code(struct mpi3mr_ioc *mrioc, u8 resp_code) +static const char *mpi3mr_tm_response_name(u8 resp_code) { char *desc; switch (resp_code) { - case MPI3MR_RSP_TM_COMPLETE: + case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: desc = "task management request completed"; break; - case MPI3MR_RSP_INVALID_FRAME: + case MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME: desc = "invalid frame"; break; - case MPI3MR_RSP_TM_NOT_SUPPORTED: + case MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED: desc = "task management request not supported"; break; - case MPI3MR_RSP_TM_FAILED: + case MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED: desc = "task management request failed"; break; - case MPI3MR_RSP_TM_SUCCEEDED: + case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: desc = "task management request succeeded"; break; - case MPI3MR_RSP_TM_INVALID_LUN: - desc = "invalid lun"; + case MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN: + desc = "invalid LUN"; break; - case MPI3MR_RSP_TM_OVERLAPPED_TAG: + case MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG: desc = "overlapped tag attempted"; break; - case MPI3MR_RSP_IO_QUEUED_ON_IOC: + case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: desc = "task queued, however not sent to target"; break; + case MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED: + desc = "task management request denied by NVMe device"; + break; default: desc = "unknown"; break; } - ioc_info(mrioc, "%s :response_code(0x%01x): %s\n", __func__, - resp_code, desc); + + return desc; } /** @@ -2965,10 +2968,10 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, *resp_code = le32_to_cpu(tm_reply->response_data) & MPI3MR_RI_MASK_RESPCODE; switch (*resp_code) { - case MPI3MR_RSP_TM_SUCCEEDED: - case MPI3MR_RSP_TM_COMPLETE: + case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: + case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: break; - case MPI3MR_RSP_IO_QUEUED_ON_IOC: + case MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC: if (tm_type != MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK) retval = -1; break; @@ -2977,14 +2980,11 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, break; } - ioc_info(mrioc, - "%s :Issue TM: Completed TM type (0x%x) handle(0x%04x) ", - __func__, tm_type, handle); - ioc_info(mrioc, - "with ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", - drv_cmd->ioc_status, drv_cmd->ioc_loginfo, - le32_to_cpu(tm_reply->termination_count)); - mpi3mr_print_response_code(mrioc, *resp_code); + dprint_tm(mrioc, + "task management request type(%d) completed for handle(0x%04x) with ioc_status(0x%04x), log_info(0x%08x), termination_count(%d), response:%s(0x%x)\n", + tm_type, handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo, + le32_to_cpu(tm_reply->termination_count), + mpi3mr_tm_response_name(*resp_code), *resp_code); out_unlock: drv_cmd->state = MPI3MR_CMD_NOTUSED; -- cgit v1.2.3 From a91603a5d504a81b5760aa4e25a46676a41395fc Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:57 +0530 Subject: scsi: mpi3mr: Enhanced Task Management Support Reply handling Enhance driver to consider MPI3_IOCSTATUS_SCSI_IOC_TERMINATED as a success for TMs issued by it and check the pending I/Os to decide the success or failure of the task management requests instead of just considering the MPI3_IOCSTATUS_SCSI_IOC_TERMINATED as a failure of the task management request. Link: https://lore.kernel.org/r/20211220141159.16117-24-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 6 ++ drivers/scsi/mpi3mr/mpi3mr_os.c | 217 +++++++++++++++++++++++++++++++++------- 2 files changed, 185 insertions(+), 38 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index e9e7a869ef10..4ac12957a4e9 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -497,6 +497,8 @@ static inline void mpi3mr_tgtdev_put(struct mpi3mr_tgt_dev *s) * @dev_removedelay: Device is waiting to be removed in FW * @dev_type: Device type * @tgt_dev: Internal target device pointer + * @pend_count: Counter to track pending I/Os during error + * handling */ struct mpi3mr_stgt_priv_data { struct scsi_target *starget; @@ -508,6 +510,7 @@ struct mpi3mr_stgt_priv_data { u8 dev_removedelay; u8 dev_type; struct mpi3mr_tgt_dev *tgt_dev; + u32 pend_count; }; /** @@ -516,11 +519,14 @@ struct mpi3mr_stgt_priv_data { * @tgt_priv_data: Scsi_target private data pointer * @lun_id: LUN ID of the device * @ncq_prio_enable: NCQ priority enable for SATA device + * @pend_count: Counter to track pending I/Os during error + * handling */ struct mpi3mr_sdev_priv_data { struct mpi3mr_stgt_priv_data *tgt_priv_data; u32 lun_id; u8 ncq_prio_enable; + u32 pend_count; }; /** diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index b2f1c6a79ea0..284117da9086 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -420,6 +420,74 @@ out: return(true); } +/** + * mpi3mr_count_dev_pending - Count commands pending for a lun + * @rq: Block request + * @data: SCSI device reference + * @reserved: Unused + * + * This is an iterator function called for each SCSI command in + * a host and if the command is pending in the LLD for the + * specific device(lun) then device specific pending I/O counter + * is updated in the device structure. + * + * Return: true always. + */ + +static bool mpi3mr_count_dev_pending(struct request *rq, + void *data, bool reserved) +{ + struct scsi_device *sdev = (struct scsi_device *)data; + struct mpi3mr_sdev_priv_data *sdev_priv_data = sdev->hostdata; + struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); + struct scmd_priv *priv; + + if (scmd) { + priv = scsi_cmd_priv(scmd); + if (!priv->in_lld_scope) + goto out; + if (scmd->device == sdev) + sdev_priv_data->pend_count++; + } + +out: + return true; +} + +/** + * mpi3mr_count_tgt_pending - Count commands pending for target + * @rq: Block request + * @data: SCSI target reference + * @reserved: Unused + * + * This is an iterator function called for each SCSI command in + * a host and if the command is pending in the LLD for the + * specific target then target specific pending I/O counter is + * updated in the target structure. + * + * Return: true always. + */ + +static bool mpi3mr_count_tgt_pending(struct request *rq, + void *data, bool reserved) +{ + struct scsi_target *starget = (struct scsi_target *)data; + struct mpi3mr_stgt_priv_data *stgt_priv_data = starget->hostdata; + struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq); + struct scmd_priv *priv; + + if (scmd) { + priv = scsi_cmd_priv(scmd); + if (!priv->in_lld_scope) + goto out; + if (scmd->device && (scsi_target(scmd->device) == starget)) + stgt_priv_data->pend_count++; + } + +out: + return true; +} + /** * mpi3mr_flush_host_io - Flush host I/Os * @mrioc: Adapter instance reference @@ -2847,6 +2915,17 @@ static const char *mpi3mr_tm_response_name(u8 resp_code) return desc; } +inline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc) +{ + int i; + int num_of_reply_queues = + mrioc->num_op_reply_q + mrioc->op_reply_q_offset; + + for (i = mrioc->op_reply_q_offset; i < num_of_reply_queues; i++) + mpi3mr_process_op_reply_q(mrioc, + mrioc->intr_info[i].op_reply_q); +} + /** * mpi3mr_issue_tm - Issue Task Management request * @mrioc: Adapter instance reference @@ -2854,9 +2933,10 @@ static const char *mpi3mr_tm_response_name(u8 resp_code) * @handle: Device handle * @lun: lun ID * @htag: Host tag of the TM request + * @timeout: TM timeout value * @drv_cmd: Internal command tracker * @resp_code: Response code place holder - * @cmd_priv: SCSI command private data + * @scmd: SCSI command * * Issues a Task Management Request to the controller for a * specified target, lun and command and wait for its completion @@ -2868,14 +2948,16 @@ static const char *mpi3mr_tm_response_name(u8 resp_code) static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, u16 handle, uint lun, u16 htag, ulong timeout, struct mpi3mr_drv_cmd *drv_cmd, - u8 *resp_code, struct scmd_priv *cmd_priv) + u8 *resp_code, struct scsi_cmnd *scmd) { struct mpi3_scsi_task_mgmt_request tm_req; struct mpi3_scsi_task_mgmt_reply *tm_reply = NULL; int retval = 0; struct mpi3mr_tgt_dev *tgtdev = NULL; struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL; - struct op_req_qinfo *op_req_q = NULL; + struct scmd_priv *cmd_priv = NULL; + struct scsi_device *sdev = NULL; + struct mpi3mr_sdev_priv_data *sdev_priv_data = NULL; ioc_info(mrioc, "%s :Issue TM: TM type (0x%x) for devhandle 0x%04x\n", __func__, tm_type, handle); @@ -2912,16 +2994,21 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, tm_req.function = MPI3_FUNCTION_SCSI_TASK_MGMT; tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle); - if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) { - scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) - tgtdev->starget->hostdata; - atomic_inc(&scsi_tgt_priv_data->block_io); - } - if (cmd_priv) { - op_req_q = &mrioc->req_qinfo[cmd_priv->req_q_idx]; - tm_req.task_host_tag = cpu_to_le16(cmd_priv->host_tag); - tm_req.task_request_queue_id = cpu_to_le16(op_req_q->qid); + + if (scmd) { + sdev = scmd->device; + sdev_priv_data = sdev->hostdata; + scsi_tgt_priv_data = ((sdev_priv_data) ? + sdev_priv_data->tgt_priv_data : NULL); + } else { + if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) + scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *) + tgtdev->starget->hostdata; } + + if (scsi_tgt_priv_data) + atomic_inc(&scsi_tgt_priv_data->block_io); + if (tgtdev && (tgtdev->dev_type == MPI3_DEVICE_DEVFORM_PCIE)) { if (cmd_priv && tgtdev->dev_spec.pcie_inf.abort_to) timeout = tgtdev->dev_spec.pcie_inf.abort_to; @@ -2938,35 +3025,44 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, wait_for_completion_timeout(&drv_cmd->done, (timeout * HZ)); if (!(drv_cmd->state & MPI3MR_CMD_COMPLETE)) { - ioc_err(mrioc, "%s :Issue TM: command timed out\n", __func__); drv_cmd->is_waiting = 0; retval = -1; - if (!(drv_cmd->state & MPI3MR_CMD_RESET)) + if (!(drv_cmd->state & MPI3MR_CMD_RESET)) { + dprint_tm(mrioc, + "task management request timed out after %ld seconds\n", + timeout); + if (mrioc->logging_level & MPI3_DEBUG_TM) + dprint_dump_req(&tm_req, sizeof(tm_req)/4); mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_TM_TIMEOUT, 1); + } goto out_unlock; } - if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID) - tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply; - - if (drv_cmd->ioc_status != MPI3_IOCSTATUS_SUCCESS) { - ioc_err(mrioc, - "%s :Issue TM: handle(0x%04x) Failed ioc_status(0x%04x) Loginfo(0x%08x)\n", - __func__, handle, drv_cmd->ioc_status, - drv_cmd->ioc_loginfo); + if (!(drv_cmd->state & MPI3MR_CMD_REPLY_VALID)) { + dprint_tm(mrioc, "invalid task management reply message\n"); retval = -1; goto out_unlock; } - if (!tm_reply) { - ioc_err(mrioc, "%s :Issue TM: No TM Reply message\n", __func__); + tm_reply = (struct mpi3_scsi_task_mgmt_reply *)drv_cmd->reply; + + switch (drv_cmd->ioc_status) { + case MPI3_IOCSTATUS_SUCCESS: + *resp_code = le32_to_cpu(tm_reply->response_data) & + MPI3MR_RI_MASK_RESPCODE; + break; + case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED: + *resp_code = MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE; + break; + default: + dprint_tm(mrioc, + "task management request to handle(0x%04x) is failed with ioc_status(0x%04x) log_info(0x%08x)\n", + handle, drv_cmd->ioc_status, drv_cmd->ioc_loginfo); retval = -1; goto out_unlock; } - *resp_code = le32_to_cpu(tm_reply->response_data) & - MPI3MR_RI_MASK_RESPCODE; switch (*resp_code) { case MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED: case MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE: @@ -2986,6 +3082,32 @@ static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type, le32_to_cpu(tm_reply->termination_count), mpi3mr_tm_response_name(*resp_code), *resp_code); + if (!retval) { + mpi3mr_ioc_disable_intr(mrioc); + mpi3mr_poll_pend_io_completions(mrioc); + mpi3mr_ioc_enable_intr(mrioc); + mpi3mr_poll_pend_io_completions(mrioc); + } + switch (tm_type) { + case MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET: + if (!scsi_tgt_priv_data) + break; + scsi_tgt_priv_data->pend_count = 0; + blk_mq_tagset_busy_iter(&mrioc->shost->tag_set, + mpi3mr_count_tgt_pending, + (void *)scsi_tgt_priv_data->starget); + break; + case MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: + if (!sdev_priv_data) + break; + sdev_priv_data->pend_count = 0; + blk_mq_tagset_busy_iter(&mrioc->shost->tag_set, + mpi3mr_count_dev_pending, (void *)sdev); + break; + default: + break; + } + out_unlock: drv_cmd->state = MPI3MR_CMD_NOTUSED; mutex_unlock(&drv_cmd->mutex); @@ -2993,14 +3115,6 @@ out_unlock: atomic_dec_if_positive(&scsi_tgt_priv_data->block_io); if (tgtdev) mpi3mr_tgtdev_put(tgtdev); - if (!retval) { - /* - * Flush all IRQ handlers by calling synchronize_irq(). - * mpi3mr_ioc_disable_intr() takes care of it. - */ - mpi3mr_ioc_disable_intr(mrioc); - mpi3mr_ioc_enable_intr(mrioc); - } out: return retval; } @@ -3250,6 +3364,13 @@ static int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd) stgt_priv_data = sdev_priv_data->tgt_priv_data; dev_handle = stgt_priv_data->dev_handle; + if (stgt_priv_data->dev_removed) { + sdev_printk(KERN_INFO, scmd->device, + "%s:target(handle = 0x%04x) is removed, target reset is not issued\n", + mrioc->name, dev_handle); + retval = FAILED; + goto out; + } sdev_printk(KERN_INFO, scmd->device, "Target Reset is issued to handle(0x%04x)\n", dev_handle); @@ -3257,15 +3378,22 @@ static int mpi3mr_eh_target_reset(struct scsi_cmnd *scmd) ret = mpi3mr_issue_tm(mrioc, MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET, dev_handle, sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, - MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL); + MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd); if (ret) goto out; + if (stgt_priv_data->pend_count) { + sdev_printk(KERN_INFO, scmd->device, + "%s: target has %d pending commands, target reset is failed\n", + mrioc->name, sdev_priv_data->pend_count); + goto out; + } + retval = SUCCESS; out: sdev_printk(KERN_INFO, scmd->device, - "Target reset is %s for scmd(%p)\n", + "%s: target reset is %s for scmd(%p)\n", mrioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return retval; @@ -3304,21 +3432,34 @@ static int mpi3mr_eh_dev_reset(struct scsi_cmnd *scmd) stgt_priv_data = sdev_priv_data->tgt_priv_data; dev_handle = stgt_priv_data->dev_handle; + if (stgt_priv_data->dev_removed) { + sdev_printk(KERN_INFO, scmd->device, + "%s: device(handle = 0x%04x) is removed, device(LUN) reset is not issued\n", + mrioc->name, dev_handle); + retval = FAILED; + goto out; + } sdev_printk(KERN_INFO, scmd->device, "Device(lun) Reset is issued to handle(0x%04x)\n", dev_handle); ret = mpi3mr_issue_tm(mrioc, MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, dev_handle, sdev_priv_data->lun_id, MPI3MR_HOSTTAG_BLK_TMS, - MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, NULL); + MPI3MR_RESETTM_TIMEOUT, &mrioc->host_tm_cmds, &resp_code, scmd); if (ret) goto out; + if (sdev_priv_data->pend_count) { + sdev_printk(KERN_INFO, scmd->device, + "%s: device has %d pending commands, device(LUN) reset is failed\n", + mrioc->name, sdev_priv_data->pend_count); + goto out; + } retval = SUCCESS; out: sdev_printk(KERN_INFO, scmd->device, - "Device(lun) reset is %s for scmd(%p)\n", + "%s: device(LUN) reset is %s for scmd(%p)\n", mrioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return retval; -- cgit v1.2.3 From 243bcc8efdb1f44b1a1d415e6821a246714c68ce Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:58 +0530 Subject: scsi: mpi3mr: Fixes around reply request queues Set reply queue depth of 1K for B0 and 4K for A0. While freeing the segmented request queues use the actual queue depth that is used while creating them. Link: https://lore.kernel.org/r/20211220141159.16117-25-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 3 ++- drivers/scsi/mpi3mr/mpi3mr_fw.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 4ac12957a4e9..65ebb77f6896 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -80,7 +80,8 @@ extern int prot_mask; /* Operational queue management definitions */ #define MPI3MR_OP_REQ_Q_QD 512 -#define MPI3MR_OP_REP_Q_QD 4096 +#define MPI3MR_OP_REP_Q_QD 1024 +#define MPI3MR_OP_REP_Q_QD4K 4096 #define MPI3MR_OP_REQ_Q_SEG_SIZE 4096 #define MPI3MR_OP_REP_Q_SEG_SIZE 4096 #define MPI3MR_MAX_SEG_LIST_SIZE 4096 diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 0fa66b34f0a6..c39dd4978c9d 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1523,7 +1523,7 @@ static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; } } else - size = mrioc->req_qinfo[q_idx].num_requests * + size = mrioc->req_qinfo[q_idx].segment_qd * mrioc->facts.op_req_sz; for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) { @@ -1810,6 +1810,8 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) reply_qid = qidx + 1; op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; + if (!mrioc->pdev->revision) + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; op_reply_q->ci = 0; op_reply_q->ephase = 1; atomic_set(&op_reply_q->pend_ios, 0); -- cgit v1.2.3 From c77b1f8a8faeeba43c694d9d09d0b25a4f52cf37 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Mon, 20 Dec 2021 19:41:59 +0530 Subject: scsi: mpi3mr: Bump driver version to 8.0.0.61.0 Update the driver version to newer version format i.e. 8.0.0.61.0. Link: https://lore.kernel.org/r/20211220141159.16117-26-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 65ebb77f6896..fc4eaf6d1e47 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -53,8 +53,8 @@ extern spinlock_t mrioc_list_lock; extern struct list_head mrioc_list; extern int prot_mask; -#define MPI3MR_DRIVER_VERSION "00.255.45.01" -#define MPI3MR_DRIVER_RELDATE "12-December-2020" +#define MPI3MR_DRIVER_VERSION "8.0.0.61.0" +#define MPI3MR_DRIVER_RELDATE "20-December-2021" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" -- cgit v1.2.3