Commit 4f5deeb4 authored by Ruksar Devadi's avatar Ruksar Devadi Committed by Martin K. Petersen
Browse files

scsi: pm80xx: Completing pending I/O after fatal error

When controller runs into fatal error, I/Os get stuck with no response,
handler event is defined to complete the pending I/Os (SAS task and
internal task) and also perform the cleanup for the drives.

Link: https://lore.kernel.org/r/20210415103352.3580-7-Viswas.G@microchip.com


Acked-by: default avatarJack Wang <jinpu.wang@cloud.ionos.com>
Signed-off-by: default avatarRuksar Devadi <Ruksar.devadi@microchip.com>
Signed-off-by: default avatarViswas G <Viswas.G@microchip.com>
Signed-off-by: default avatarAshokkumar N <Ashokkumar.N@microchip.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent b0c306e6
Loading
Loading
Loading
Loading
+60 −6
Original line number Diff line number Diff line
@@ -1499,6 +1499,7 @@ void pm8001_work_fn(struct work_struct *work)
	 * was cancelled. This nullification happens when the device
	 * goes away.
	 */
	if (pw->handler != IO_FATAL_ERROR) {
		pm8001_dev = pw->data; /* Most stash device structure */
		if ((pm8001_dev == NULL)
		 || ((pw->handler != IO_XFER_ERROR_BREAK)
@@ -1506,6 +1507,7 @@ void pm8001_work_fn(struct work_struct *work)
			kfree(pw);
			return;
		}
	}

	switch (pw->handler) {
	case IO_XFER_ERROR_BREAK:
@@ -1668,6 +1670,58 @@ void pm8001_work_fn(struct work_struct *work)
		dev = pm8001_dev->sas_device;
		pm8001_I_T_nexus_reset(dev);
		break;
	case IO_FATAL_ERROR:
	{
		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
		struct pm8001_ccb_info *ccb;
		struct task_status_struct *ts;
		struct sas_task *task;
		int i;
		u32 tag, device_id;

		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
			ccb = &pm8001_ha->ccb_info[i];
			task = ccb->task;
			ts = &task->task_status;
			tag = ccb->ccb_tag;
			/* check if tag is NULL */
			if (!tag) {
				pm8001_dbg(pm8001_ha, FAIL,
					"tag Null\n");
				continue;
			}
			if (task != NULL) {
				dev = task->dev;
				if (!dev) {
					pm8001_dbg(pm8001_ha, FAIL,
						"dev is NULL\n");
					continue;
				}
				/*complete sas task and update to top layer */
				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
				ts->resp = SAS_TASK_COMPLETE;
				task->task_done(task);
			} else if (tag != 0xFFFFFFFF) {
				/* complete the internal commands/non-sas task */
				pm8001_dev = ccb->device;
				if (pm8001_dev->dcompletion) {
					complete(pm8001_dev->dcompletion);
					pm8001_dev->dcompletion = NULL;
				}
				complete(pm8001_ha->nvmd_completion);
				pm8001_tag_free(pm8001_ha, tag);
			}
		}
		/* Deregister all the device ids  */
		for (i = 0; i < PM8001_MAX_DEVICES; i++) {
			pm8001_dev = &pm8001_ha->devices[i];
			device_id = pm8001_dev->device_id;
			if (device_id) {
				PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
				pm8001_free_dev(pm8001_dev);
			}
		}
	}	break;
	}
	kfree(pw);
}
+1 −0
Original line number Diff line number Diff line
@@ -805,6 +805,7 @@ struct set_dev_state_resp {
#define IO_ABORT_IN_PROGRESS				0x40
#define IO_ABORT_DELAYED				0x41
#define IO_INVALID_LENGTH				0x42
#define IO_FATAL_ERROR					0x51

/* WARNING: This error code must always be the last number.
 * If you add error code, modify this code also
+1 −1
Original line number Diff line number Diff line
@@ -590,7 +590,7 @@ struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha,
	return NULL;
}

static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
void pm8001_free_dev(struct pm8001_device *pm8001_dev)
{
	u32 id = pm8001_dev->id;
	memset(pm8001_dev, 0, sizeof(*pm8001_dev));
+1 −0
Original line number Diff line number Diff line
@@ -726,6 +726,7 @@ ssize_t pm80xx_get_non_fatal_dump(struct device *cdev,
		struct device_attribute *attr, char *buf);
ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
int pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha);
void pm8001_free_dev(struct pm8001_device *pm8001_dev);
/* ctl shared API */
extern struct device_attribute *pm8001_host_attrs[];

+1 −0
Original line number Diff line number Diff line
@@ -4126,6 +4126,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
			pm8001_dbg(pm8001_ha, FAIL,
				   "Firmware Fatal error! Regval:0x%x\n",
				   regval);
			pm8001_handle_event(pm8001_ha, NULL, IO_FATAL_ERROR);
			print_scratchpad_registers(pm8001_ha);
			return ret;
		}
Loading