Commit 1d48701c authored by Steven Song's avatar Steven Song
Browse files

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: default avatarSteven Song <steven.song@3snic.com>
Reviewed-by: default avatar <liangry&lt;liangry1@3snic.com>
Reviewed-by: default avatarJiang <Yu&lt;yujiang@3snic.com>
parent 07502d82
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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)
+27 −15
Original line number Diff line number Diff line
@@ -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;
}
+1 −1
Original line number Diff line number Diff line
@@ -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);