From 1d48701c7a99e0a43d86937463f4f41875bb8fcd Mon Sep 17 00:00:00 2001 From: Steven Song Date: Tue, 21 Mar 2023 15:27:22 +0800 Subject: [PATCH] SCSI: SSSRAID: Fix the bug that system automatically reboot when issue a 'pcie-linkdown' command 3snic inclusion category: bugfix feature: sssraid bugzilla: https://gitee.com/openeuler/kernel/issues/I6OUEK CVE: NA ------------------------------------------ [issue description] The system will restart abnormally when issue a 'pcie-linkdown' command [steps to reproduce the bug] 1. Create classic RAID1 and RAID5 2. Issue read & write mixed I/O to the drive letters corresponding to RAID1 and RAID5 3. In the process of reading and writing I/O,issue a 'pcie-linkdown' command by a serial port [Probability of occurrence] 100% [Expected results] The I/O rate is 0 temporarily, and after a period of time the IO is interrupted, the system will not automatically restart, and the RAID card will not be unhealthy after manual restart. [Root cause] 'pcie-linkdown' will trigger I/O timeout and firmware hang dead, and driver will try to access firmware when it dead, Multiple accesses cause this bug. [Solution] Remove communication with firmware in I/O timeout process when firmware hang dead. Signed-off-by: Steven Song Reviewed-by: liangry Reviewed-by: Jiang Yu --- drivers/scsi/sssraid/sssraid.h | 3 ++- drivers/scsi/sssraid/sssraid_fw.c | 42 ++++++++++++++++++++----------- drivers/scsi/sssraid/sssraid_os.c | 2 +- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/sssraid/sssraid.h b/drivers/scsi/sssraid/sssraid.h index f2a597936118..7fe485524da7 100644 --- a/drivers/scsi/sssraid/sssraid.h +++ b/drivers/scsi/sssraid/sssraid.h @@ -58,7 +58,8 @@ #define SSSRAID_ADM_QUEUE_NUM 1 #define SSSRAID_PTCMDS_PERQ 1 #define SSSRAID_IO_BLK_MQ_DEPTH (sdioc->scsi_qd) -#define SSSRAID_NR_IOQ_PTCMDS (SSSRAID_PTCMDS_PERQ * sdioc->shost->nr_hw_queues) +#define SSSRAID_NR_HW_QUEUES (sdioc->init_done_queue_cnt - 1) +#define SSSRAID_NR_IOQ_PTCMDS (SSSRAID_PTCMDS_PERQ * SSSRAID_NR_HW_QUEUES) #define FUA_MASK 0x08 #define SSSRAID_MINORS BIT(MINORBITS) diff --git a/drivers/scsi/sssraid/sssraid_fw.c b/drivers/scsi/sssraid/sssraid_fw.c index 6f553003e19f..440b50fd5689 100644 --- a/drivers/scsi/sssraid/sssraid_fw.c +++ b/drivers/scsi/sssraid/sssraid_fw.c @@ -1316,7 +1316,7 @@ int sssraid_init_ioc(struct sssraid_ioc *sdioc, u8 re_init) /* num_vecs no sense, abandon */ if (!re_init) { - for (i = sdioc->init_done_queue_cnt; i <= sdioc->intr_info_count; i++) { + for (i = sdioc->init_done_queue_cnt; i < sdioc->intr_info_count; i++) { retval = sssraid_alloc_qpair(sdioc, i, sdioc->ioq_depth); if (retval) { ioc_err(sdioc, "Failed to alloc io queue:error %d\n", @@ -1631,27 +1631,30 @@ void sssraid_complete_cqes(struct sssraid_ioc *sdioc, u16 midx, u16 start, u16 e } } -static void sssraid_disable_admin_queue(struct sssraid_ioc *sdioc, bool shutdown) +static int sssraid_disable_admin_queue(struct sssraid_ioc *sdioc, bool shutdown) { struct sssraid_cqueue *adm_cqinfo = &sdioc->cqinfo[0]; u16 start, end; + int ret = 0; if (pci_device_is_present(sdioc->pdev)) { if (shutdown) sssraid_shutdown_ctrl(sdioc); else - sssraid_disable_ctrl(sdioc); + ret = sssraid_disable_ctrl(sdioc); } if (sdioc->init_done_queue_cnt == 0) { ioc_err(sdioc, "err: admin queue has been delete\n"); - return; + return -ENODEV; } spin_lock_irq(&adm_cqinfo->cq_lock); sssraid_process_cq(sdioc, 0, &start, &end, -1); spin_unlock_irq(&adm_cqinfo->cq_lock); sssraid_complete_cqes(sdioc, 0, start, end); + + return ret; } static void sssraid_free_all_queues(struct sssraid_ioc *sdioc) @@ -1722,29 +1725,38 @@ int sssraid_soft_reset_handler(struct sssraid_ioc *sdioc) ioc_info(sdioc, "host reset entry\n"); - sssraid_ioc_disable_intr(sdioc); sssraid_cleanup_fwevt_list(sdioc); - /* realize above here: - * sssraid_dev_disable -> sssraid_back_all_io - */ - sssraid_back_all_io(sdioc); /* * realize sssraid_dev_disable, * i.e. sssraid_cleanup_ioc(1) */ if (sdioc->ctrl_config & SSSRAID_CC_ENABLE) { - ioc_info(sdioc, "start cleanup ioc\n"); - sssraid_cleanup_ioc(sdioc, 1); + ioc_info(sdioc, "start disable admin queue\n"); + retval = sssraid_disable_admin_queue(sdioc, 0); } + sssraid_cleanup_resources(sdioc); + + /* realize above here: + * sssraid_dev_disable -> sssraid_back_all_io + */ + sssraid_back_all_io(sdioc); + + if (retval) + goto host_reset_failed; + retval = sssraid_init_ioc(sdioc, 1); - if (retval) { - ioc_err(sdioc, "err: init ioc fail.\n"); - return retval; - } + if (retval) + goto cleanup_resources; sssraid_change_host_state(sdioc, SSSRAID_LIVE); + return 0; +cleanup_resources: + sssraid_cleanup_resources(sdioc); +host_reset_failed: + sssraid_change_host_state(sdioc, SSSRAID_DEAD); + ioc_err(sdioc, "err, host reset failed\n"); return retval; } diff --git a/drivers/scsi/sssraid/sssraid_os.c b/drivers/scsi/sssraid/sssraid_os.c index 45542dc0e0e1..6b8f143190d1 100644 --- a/drivers/scsi/sssraid/sssraid_os.c +++ b/drivers/scsi/sssraid/sssraid_os.c @@ -566,7 +566,7 @@ static void sssraid_shost_init(struct sssraid_ioc *sdioc) bus = pdev->bus->number; dev_func = pdev->devfn; - sdioc->shost->nr_hw_queues = sdioc->init_done_queue_cnt - 1; + sdioc->shost->nr_hw_queues = SSSRAID_NR_HW_QUEUES; sdioc->shost->can_queue = (sdioc->ioq_depth - SSSRAID_PTCMDS_PERQ); sdioc->shost->sg_tablesize = le16_to_cpu(sdioc->ctrl_info->max_num_sge); -- Gitee