Commit 5160acf2 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev
Browse files

+enable_panic

parent 163a9091
Loading
Loading
Loading
Loading
+177 −107
Original line number Original line Diff line number Diff line
@@ -25,7 +25,7 @@
 *
 *
 *
 *
 *  libata documentation is available via 'make {ps|pdf}docs',
 *  libata documentation is available via 'make {ps|pdf}docs',
 *  as Documentation/DocBook/libata.*
 *  as Documentation/driver-api/libata.rst
 *
 *
 *  Hardware documentation available from http://www.t13.org/ and
 *  Hardware documentation available from http://www.t13.org/ and
 *  http://www.sata-io.org/
 *  http://www.sata-io.org/
@@ -46,6 +46,7 @@


#include <linux/libata.h>
#include <linux/libata.h>


#include <trace/events/libata.h>
#include "libata.h"
#include "libata.h"


enum {
enum {
@@ -548,6 +549,7 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
	DPRINTK("EXIT, ret=%d\n", ret);
	DPRINTK("EXIT, ret=%d\n", ret);
	return ret;
	return ret;
}
}
EXPORT_SYMBOL(ata_scsi_timed_out);


static void ata_eh_unload(struct ata_port *ap)
static void ata_eh_unload(struct ata_port *ap)
{
{
@@ -605,7 +607,7 @@ void ata_scsi_error(struct Scsi_Host *host)
	ata_scsi_port_error_handler(host, ap);
	ata_scsi_port_error_handler(host, ap);


	/* finish or retry handled scmd's and clean up */
	/* finish or retry handled scmd's and clean up */
	WARN_ON(host->host_failed || !list_empty(&eh_work_q));
	WARN_ON(!list_empty(&eh_work_q));


	DPRINTK("EXIT\n");
	DPRINTK("EXIT\n");
}
}
@@ -643,12 +645,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
	 * completions are honored.  A scmd is determined to have
	 * completions are honored.  A scmd is determined to have
	 * timed out iff its associated qc is active and not failed.
	 * timed out iff its associated qc is active and not failed.
	 */
	 */
	spin_lock_irqsave(ap->lock, flags);
	if (ap->ops->error_handler) {
	if (ap->ops->error_handler) {
		struct scsi_cmnd *scmd, *tmp;
		struct scsi_cmnd *scmd, *tmp;
		int nr_timedout = 0;
		int nr_timedout = 0;


		spin_lock_irqsave(ap->lock, flags);

		/* This must occur under the ap->lock as we don't want
		/* This must occur under the ap->lock as we don't want
		   a polled recovery to race the real interrupt handler
		   a polled recovery to race the real interrupt handler


@@ -698,12 +699,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
		if (nr_timedout)
		if (nr_timedout)
			__ata_port_freeze(ap);
			__ata_port_freeze(ap);


		spin_unlock_irqrestore(ap->lock, flags);


		/* initialize eh_tries */
		/* initialize eh_tries */
		ap->eh_tries = ATA_EH_MAX_TRIES;
		ap->eh_tries = ATA_EH_MAX_TRIES;
	} else
	}
		spin_unlock_wait(ap->lock);
	spin_unlock_irqrestore(ap->lock, flags);


}
}
EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
@@ -968,7 +968,7 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
{
{
	struct ata_port *ap = qc->ap;
	struct ata_port *ap = qc->ap;
	struct request_queue *q;
	struct request_queue *q = qc->scsicmd->device->request_queue;
	unsigned long flags;
	unsigned long flags;


	WARN_ON(!ap->ops->error_handler);
	WARN_ON(!ap->ops->error_handler);
@@ -981,13 +981,10 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
	 * this function completes.
	 * this function completes.
	 */
	 */
	if (qc->scsicmd != NULL) {
		q = qc->scsicmd->device->request_queue;
	spin_lock_irqsave(q->queue_lock, flags);
	spin_lock_irqsave(q->queue_lock, flags);
	blk_abort_request(qc->scsicmd->request);
	blk_abort_request(qc->scsicmd->request);
	spin_unlock_irqrestore(q->queue_lock, flags);
	spin_unlock_irqrestore(q->queue_lock, flags);
}
}
}


/**
/**
 * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine
 * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine
@@ -1435,7 +1432,7 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,


/**
/**
 *	ata_eh_done - EH action complete
 *	ata_eh_done - EH action complete
*	@ap: target ATA port
 *	@link: ATA link for which EH actions are complete
 *	@dev: target ATA dev for per-dev action (can be NULL)
 *	@dev: target ATA dev for per-dev action (can be NULL)
 *	@action: action just completed
 *	@action: action just completed
 *
 *
@@ -1488,46 +1485,6 @@ static const char *ata_err_string(unsigned int err_mask)
	return "unknown error";
	return "unknown error";
}
}


/**
 *	ata_read_log_page - read a specific log page
 *	@dev: target device
 *	@log: log to read
 *	@page: page to read
 *	@buf: buffer to store read page
 *	@sectors: number of sectors to read
 *
 *	Read log page using READ_LOG_EXT command.
 *
 *	LOCKING:
 *	Kernel thread context (may sleep).
 *
 *	RETURNS:
 *	0 on success, AC_ERR_* mask otherwise.
 */
unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
			       u8 page, void *buf, unsigned int sectors)
{
	struct ata_taskfile tf;
	unsigned int err_mask;

	DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);

	ata_tf_init(dev, &tf);
	tf.command = ATA_CMD_READ_LOG_EXT;
	tf.lbal = log;
	tf.lbam = page;
	tf.nsect = sectors;
	tf.hob_nsect = sectors >> 8;
	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
	tf.protocol = ATA_PROT_PIO;

	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
				     buf, sectors * ATA_SECT_SIZE, 0);

	DPRINTK("EXIT, err_mask=%x\n", err_mask);
	return err_mask;
}

/**
/**
 *	ata_eh_read_log_10h - Read log page 10h for NCQ error details
 *	ata_eh_read_log_10h - Read log page 10h for NCQ error details
 *	@dev: Device to read log page 10h from
 *	@dev: Device to read log page 10h from
@@ -1578,6 +1535,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
	tf->hob_lbah = buf[10];
	tf->hob_lbah = buf[10];
	tf->nsect = buf[12];
	tf->nsect = buf[12];
	tf->hob_nsect = buf[13];
	tf->hob_nsect = buf[13];
	if (ata_id_has_ncq_autosense(dev->id))
		tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];


	return 0;
	return 0;
}
}
@@ -1613,6 +1572,56 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
	return err_mask;
	return err_mask;
}
}


/**
 *	ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
 *	@qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to
 *	@cmd: scsi command for which the sense code should be set
 *
 *	Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
 *	SENSE.  This function is an EH helper.
 *
 *	LOCKING:
 *	Kernel thread context (may sleep).
 */
static void ata_eh_request_sense(struct ata_queued_cmd *qc,
				 struct scsi_cmnd *cmd)
{
	struct ata_device *dev = qc->dev;
	struct ata_taskfile tf;
	unsigned int err_mask;

	if (qc->ap->pflags & ATA_PFLAG_FROZEN) {
		ata_dev_warn(dev, "sense data available but port frozen\n");
		return;
	}

	if (!cmd || qc->flags & ATA_QCFLAG_SENSE_VALID)
		return;

	if (!ata_id_sense_reporting_enabled(dev->id)) {
		ata_dev_warn(qc->dev, "sense data reporting disabled\n");
		return;
	}

	DPRINTK("ATA request sense\n");

	ata_tf_init(dev, &tf);
	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
	tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
	tf.command = ATA_CMD_REQ_SENSE_DATA;
	tf.protocol = ATA_PROT_NODATA;

	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
	/* Ignore err_mask; ATA_ERR might be set */
	if (tf.command & ATA_SENSE) {
		ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal);
		qc->flags |= ATA_QCFLAG_SENSE_VALID;
	} else {
		ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
			     tf.command, err_mask);
	}
}

/**
/**
 *	atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
 *	atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
 *	@dev: device to perform REQUEST_SENSE to
 *	@dev: device to perform REQUEST_SENSE to
@@ -1775,6 +1784,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
	memcpy(&qc->result_tf, &tf, sizeof(tf));
	memcpy(&qc->result_tf, &tf, sizeof(tf));
	qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
	qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
	qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
	qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
	if ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary) {
		char sense_key, asc, ascq;

		sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
		asc = (qc->result_tf.auxiliary >> 8) & 0xff;
		ascq = qc->result_tf.auxiliary & 0xff;
		ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq);
		ata_scsi_set_sense_information(dev, qc->scsicmd,
					       &qc->result_tf);
		qc->flags |= ATA_QCFLAG_SENSE_VALID;
	}

	ehc->i.err_mask &= ~AC_ERR_DEV;
	ehc->i.err_mask &= ~AC_ERR_DEV;
}
}


@@ -1804,14 +1825,23 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
		return ATA_EH_RESET;
		return ATA_EH_RESET;
	}
	}


	if (stat & (ATA_ERR | ATA_DF))
	if (stat & (ATA_ERR | ATA_DF)) {
		qc->err_mask |= AC_ERR_DEV;
		qc->err_mask |= AC_ERR_DEV;
	else
		/*
		 * Sense data reporting does not work if the
		 * device fault bit is set.
		 */
		if (stat & ATA_DF)
			stat &= ~ATA_SENSE;
	} else {
		return 0;
		return 0;
	}


	switch (qc->dev->class) {
	switch (qc->dev->class) {
	case ATA_DEV_ATA:
	case ATA_DEV_ATA:
	case ATA_DEV_ZAC:
	case ATA_DEV_ZAC:
		if (stat & ATA_SENSE)
			ata_eh_request_sense(qc, qc->scsicmd);
		if (err & ATA_ICRC)
		if (err & ATA_ICRC)
			qc->err_mask |= AC_ERR_ATA_BUS;
			qc->err_mask |= AC_ERR_ATA_BUS;
		if (err & (ATA_UNC | ATA_AMNF))
		if (err & (ATA_UNC | ATA_AMNF))
@@ -1825,20 +1855,31 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
			tmp = atapi_eh_request_sense(qc->dev,
			tmp = atapi_eh_request_sense(qc->dev,
						qc->scsicmd->sense_buffer,
						qc->scsicmd->sense_buffer,
						qc->result_tf.feature >> 4);
						qc->result_tf.feature >> 4);
			if (!tmp) {
			if (!tmp)
				/* ATA_QCFLAG_SENSE_VALID is used to
				 * tell atapi_qc_complete() that sense
				 * data is already valid.
				 *
				 * TODO: interpret sense data and set
				 * appropriate err_mask.
				 */
				qc->flags |= ATA_QCFLAG_SENSE_VALID;
				qc->flags |= ATA_QCFLAG_SENSE_VALID;
			} else
			else
				qc->err_mask |= tmp;
				qc->err_mask |= tmp;
		}
		}
	}
	}


	if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
		int ret = scsi_check_sense(qc->scsicmd);
		/*
		 * SUCCESS here means that the sense code could
		 * evaluated and should be passed to the upper layers
		 * for correct evaluation.
		 * FAILED means the sense code could not interpreted
		 * and the device would need to be reset.
		 * NEEDS_RETRY and ADD_TO_MLQUEUE means that the
		 * command would need to be retried.
		 */
		if (ret == NEEDS_RETRY || ret == ADD_TO_MLQUEUE) {
			qc->flags |= ATA_QCFLAG_RETRY;
			qc->err_mask |= AC_ERR_OTHER;
		} else if (ret != SUCCESS) {
			qc->err_mask |= AC_ERR_HSM;
		}
	}
	if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
	if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
		action |= ATA_EH_RESET;
		action |= ATA_EH_RESET;


@@ -1927,7 +1968,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
 *	This is to expedite speed down decisions right after device is
 *	This is to expedite speed down decisions right after device is
 *	initially configured.
 *	initially configured.
 *
 *
 *	The followings are speed down rules.  #1 and #2 deal with
 *	The following are speed down rules.  #1 and #2 deal with
 *	DUBIOUS errors.
 *	DUBIOUS errors.
 *
 *
 *	1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors
 *	1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors
@@ -2189,6 +2230,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
		all_err_mask |= qc->err_mask;
		all_err_mask |= qc->err_mask;
		if (qc->flags & ATA_QCFLAG_IO)
		if (qc->flags & ATA_QCFLAG_IO)
			eflags |= ATA_EFLAG_IS_IO;
			eflags |= ATA_EFLAG_IS_IO;
		trace_ata_eh_link_autopsy_qc(qc);
	}
	}


	/* enforce default EH actions */
	/* enforce default EH actions */
@@ -2223,7 +2265,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
			eflags |= ATA_EFLAG_DUBIOUS_XFER;
			eflags |= ATA_EFLAG_DUBIOUS_XFER;
		ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask);
		ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask);
	}
	}

	trace_ata_eh_link_autopsy(dev, ehc->i.action, all_err_mask);
	DPRINTK("EXIT\n");
	DPRINTK("EXIT\n");
}
}


@@ -2375,6 +2417,8 @@ const char *ata_get_cmd_descript(u8 command)
		{ ATA_CMD_CFA_WRITE_MULT_NE,	"CFA WRITE MULTIPLE WITHOUT ERASE" },
		{ ATA_CMD_CFA_WRITE_MULT_NE,	"CFA WRITE MULTIPLE WITHOUT ERASE" },
		{ ATA_CMD_REQ_SENSE_DATA,	"REQUEST SENSE DATA EXT" },
		{ ATA_CMD_REQ_SENSE_DATA,	"REQUEST SENSE DATA EXT" },
		{ ATA_CMD_SANITIZE_DEVICE,	"SANITIZE DEVICE" },
		{ ATA_CMD_SANITIZE_DEVICE,	"SANITIZE DEVICE" },
		{ ATA_CMD_ZAC_MGMT_IN,		"ZAC MANAGEMENT IN" },
		{ ATA_CMD_ZAC_MGMT_OUT,		"ZAC MANAGEMENT OUT" },
		{ ATA_CMD_READ_LONG,		"READ LONG (with retries)" },
		{ ATA_CMD_READ_LONG,		"READ LONG (with retries)" },
		{ ATA_CMD_READ_LONG_ONCE,	"READ LONG (without retries)" },
		{ ATA_CMD_READ_LONG_ONCE,	"READ LONG (without retries)" },
		{ ATA_CMD_WRITE_LONG,		"WRITE LONG (with retries)" },
		{ ATA_CMD_WRITE_LONG,		"WRITE LONG (with retries)" },
@@ -2499,17 +2543,39 @@ static void ata_eh_link_report(struct ata_link *link)
				[DMA_TO_DEVICE]		= "out",
				[DMA_TO_DEVICE]		= "out",
				[DMA_FROM_DEVICE]	= "in",
				[DMA_FROM_DEVICE]	= "in",
			};
			};
			static const char *prot_str[] = {
			const char *prot_str = NULL;
				[ATA_PROT_PIO]		= "pio",
				[ATA_PROT_DMA]		= "dma",
				[ATA_PROT_NCQ]		= "ncq",
				[ATAPI_PROT_PIO]	= "pio",
				[ATAPI_PROT_DMA]	= "dma",
			};


			switch (qc->tf.protocol) {
			case ATA_PROT_UNKNOWN:
				prot_str = "unknown";
				break;
			case ATA_PROT_NODATA:
				prot_str = "nodata";
				break;
			case ATA_PROT_PIO:
				prot_str = "pio";
				break;
			case ATA_PROT_DMA:
				prot_str = "dma";
				break;
			case ATA_PROT_NCQ:
				prot_str = "ncq dma";
				break;
			case ATA_PROT_NCQ_NODATA:
				prot_str = "ncq nodata";
				break;
			case ATAPI_PROT_NODATA:
				prot_str = "nodata";
				break;
			case ATAPI_PROT_PIO:
				prot_str = "pio";
				break;
			case ATAPI_PROT_DMA:
				prot_str = "dma";
				break;
			}
			snprintf(data_buf, sizeof(data_buf), " %s %u %s",
			snprintf(data_buf, sizeof(data_buf), " %s %u %s",
				 prot_str[qc->tf.protocol], qc->nbytes,
				 prot_str, qc->nbytes, dma_str[qc->dma_dir]);
				 dma_str[qc->dma_dir]);
		}
		}


		if (ata_is_atapi(qc->tf.protocol)) {
		if (ata_is_atapi(qc->tf.protocol)) {
@@ -2551,14 +2617,15 @@ static void ata_eh_link_report(struct ata_link *link)


#ifdef CONFIG_ATA_VERBOSE_ERROR
#ifdef CONFIG_ATA_VERBOSE_ERROR
		if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
		if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
				    ATA_ERR)) {
				    ATA_SENSE | ATA_ERR)) {
			if (res->command & ATA_BUSY)
			if (res->command & ATA_BUSY)
				ata_dev_err(qc->dev, "status: { Busy }\n");
				ata_dev_err(qc->dev, "status: { Busy }\n");
			else
			else
				ata_dev_err(qc->dev, "status: { %s%s%s%s}\n",
				ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n",
				  res->command & ATA_DRDY ? "DRDY " : "",
				  res->command & ATA_DRDY ? "DRDY " : "",
				  res->command & ATA_DF ? "DF " : "",
				  res->command & ATA_DF ? "DF " : "",
				  res->command & ATA_DRQ ? "DRQ " : "",
				  res->command & ATA_DRQ ? "DRQ " : "",
				  res->command & ATA_SENSE ? "SENSE " : "",
				  res->command & ATA_ERR ? "ERR " : "");
				  res->command & ATA_ERR ? "ERR " : "");
		}
		}


@@ -2574,6 +2641,7 @@ static void ata_eh_link_report(struct ata_link *link)
#endif
#endif
	}
	}
}
}

/**
/**
 *	ata_eh_report - report error handling to user
 *	ata_eh_report - report error handling to user
 *	@ap: ATA port to report EH about
 *	@ap: ATA port to report EH about
@@ -3071,7 +3139,7 @@ static void ata_eh_park_issue_cmd(struct ata_device *dev, int park)
	}
	}


	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
	tf.protocol |= ATA_PROT_NODATA;
	tf.protocol = ATA_PROT_NODATA;
	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
	if (park && (err_mask || tf.lbal != 0xc4)) {
	if (park && (err_mask || tf.lbal != 0xc4)) {
		ata_dev_err(dev, "head unload failed!\n");
		ata_dev_err(dev, "head unload failed!\n");
@@ -3496,6 +3564,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
		}
		}
	}
	}


	link->last_lpm_change = jiffies;
	link->flags |= ATA_LFLAG_CHANGED;

	return 0;
	return 0;


fail:
fail:
@@ -4107,7 +4178,6 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
	struct ata_link *link;
	struct ata_link *link;
	struct ata_device *dev;
	struct ata_device *dev;
	unsigned long flags;
	unsigned long flags;
	int rc = 0;


	/* are we resuming? */
	/* are we resuming? */
	spin_lock_irqsave(ap->lock, flags);
	spin_lock_irqsave(ap->lock, flags);
@@ -4134,7 +4204,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
	ata_acpi_set_state(ap, ap->pm_mesg);
	ata_acpi_set_state(ap, ap->pm_mesg);


	if (ap->ops->port_resume)
	if (ap->ops->port_resume)
		rc = ap->ops->port_resume(ap);
		ap->ops->port_resume(ap);


	/* tell ACPI that we're resuming */
	/* tell ACPI that we're resuming */
	ata_acpi_on_resume(ap);
	ata_acpi_on_resume(ap);