aboutsummaryrefslogtreecommitdiff
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c181
1 files changed, 128 insertions, 53 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a9b28203800..dad83df555c 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1,7 +1,7 @@
/*
* libata-eh.c - libata error handling
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -95,12 +95,13 @@ enum {
* represents timeout for that try. The first try can be soft or
* hardreset. All others are hardreset if available. In most cases
* the first reset w/ 10sec timeout should succeed. Following entries
- * are mostly for error handling, hotplug and retarded devices.
+ * are mostly for error handling, hotplug and those outlier devices that
+ * take an exceptionally long time to recover from reset.
*/
static const unsigned long ata_eh_reset_timeouts[] = {
10000, /* most drives spin up by 10sec */
10000, /* > 99% working drives spin up before 20sec */
- 35000, /* give > 30 secs of idleness for retarded devices */
+ 35000, /* give > 30 secs of idleness for outlier devices */
5000, /* and sweet one last chance */
ULONG_MAX, /* > 1 min has elapsed, give up */
};
@@ -419,7 +420,7 @@ int ata_ering_map(struct ata_ering *ering,
return rc;
}
-int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg)
+static int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg)
{
ent->eflags |= ATA_EFLAG_OLD_ER;
return 0;
@@ -793,12 +794,12 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
ata_for_each_link(link, ap, HOST_FIRST)
memset(&link->eh_info, 0, sizeof(link->eh_info));
- /* Clear host_eh_scheduled while holding ap->lock such
- * that if exception occurs after this point but
- * before EH completion, SCSI midlayer will
+ /* end eh (clear host_eh_scheduled) while holding
+ * ap->lock such that if exception occurs after this
+ * point but before EH completion, SCSI midlayer will
* re-initiate EH.
*/
- host->host_eh_scheduled = 0;
+ ap->ops->end_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
ata_eh_release(ap);
@@ -863,6 +864,7 @@ void ata_port_wait_eh(struct ata_port *ap)
goto retry;
}
}
+EXPORT_SYMBOL_GPL(ata_port_wait_eh);
static int ata_eh_nr_in_flight(struct ata_port *ap)
{
@@ -985,16 +987,13 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
}
/**
- * ata_port_schedule_eh - schedule error handling without a qc
- * @ap: ATA port to schedule EH for
- *
- * Schedule error handling for @ap. EH will kick in as soon as
- * all commands are drained.
+ * ata_std_sched_eh - non-libsas ata_ports issue eh with this common routine
+ * @ap: ATA port to schedule EH for
*
- * LOCKING:
+ * LOCKING: inherited from ata_port_schedule_eh
* spin_lock_irqsave(host lock)
*/
-void ata_port_schedule_eh(struct ata_port *ap)
+void ata_std_sched_eh(struct ata_port *ap)
{
WARN_ON(!ap->ops->error_handler);
@@ -1006,6 +1005,44 @@ void ata_port_schedule_eh(struct ata_port *ap)
DPRINTK("port EH scheduled\n");
}
+EXPORT_SYMBOL_GPL(ata_std_sched_eh);
+
+/**
+ * ata_std_end_eh - non-libsas ata_ports complete eh with this common routine
+ * @ap: ATA port to end EH for
+ *
+ * In the libata object model there is a 1:1 mapping of ata_port to
+ * shost, so host fields can be directly manipulated under ap->lock, in
+ * the libsas case we need to hold a lock at the ha->level to coordinate
+ * these events.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_std_end_eh(struct ata_port *ap)
+{
+ struct Scsi_Host *host = ap->scsi_host;
+
+ host->host_eh_scheduled = 0;
+}
+EXPORT_SYMBOL(ata_std_end_eh);
+
+
+/**
+ * ata_port_schedule_eh - schedule error handling without a qc
+ * @ap: ATA port to schedule EH for
+ *
+ * Schedule error handling for @ap. EH will kick in as soon as
+ * all commands are drained.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_port_schedule_eh(struct ata_port *ap)
+{
+ /* see: ata_std_sched_eh, unless you know better */
+ ap->ops->sched_eh(ap);
+}
static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
{
@@ -1286,14 +1323,14 @@ void ata_eh_qc_complete(struct ata_queued_cmd *qc)
* should be retried. To be used from EH.
*
* SCSI midlayer limits the number of retries to scmd->allowed.
- * scmd->retries is decremented for commands which get retried
+ * scmd->allowed is incremented for commands which get retried
* due to unrelated failures (qc->err_mask is zero).
*/
void ata_eh_qc_retry(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
- if (!qc->err_mask && scmd->retries)
- scmd->retries--;
+ if (!qc->err_mask)
+ scmd->allowed++;
__ata_eh_qc_complete(qc);
}
@@ -1451,6 +1488,7 @@ static const char *ata_err_string(unsigned int err_mask)
/**
* 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
@@ -1463,17 +1501,18 @@ static const char *ata_err_string(unsigned int err_mask)
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
-static unsigned int ata_read_log_page(struct ata_device *dev,
- u8 page, void *buf, unsigned int sectors)
+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 - page %d\n", page);
+ 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 = page;
+ 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;
@@ -1509,7 +1548,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
u8 csum;
int i;
- err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
+ err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1);
if (err_mask)
return -EIO;
@@ -1553,7 +1592,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
* RETURNS:
* 0 on success, AC_ERR_* mask on failure.
*/
-static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
+unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
{
u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
struct ata_taskfile tf;
@@ -1586,7 +1625,7 @@ static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
* RETURNS:
* 0 on success, AC_ERR_* mask on failure
*/
-static unsigned int atapi_eh_request_sense(struct ata_device *dev,
+unsigned int atapi_eh_request_sense(struct ata_device *dev,
u8 *sense_buf, u8 dfl_sense_key)
{
u8 cdb[ATAPI_CDB_LEN] =
@@ -1772,7 +1811,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
case ATA_DEV_ATA:
if (err & ATA_ICRC)
qc->err_mask |= AC_ERR_ATA_BUS;
- if (err & ATA_UNC)
+ if (err & (ATA_UNC | ATA_AMNF))
qc->err_mask |= AC_ERR_MEDIA;
if (err & ATA_IDNF)
qc->err_mask |= AC_ERR_INVALID;
@@ -2046,6 +2085,26 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
}
/**
+ * ata_eh_worth_retry - analyze error and decide whether to retry
+ * @qc: qc to possibly retry
+ *
+ * Look at the cause of the error and decide if a retry
+ * might be useful or not. We don't want to retry media errors
+ * because the drive itself has probably already taken 10-30 seconds
+ * doing its own internal retries before reporting the failure.
+ */
+static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
+{
+ if (qc->err_mask & AC_ERR_MEDIA)
+ return 0; /* don't retry media errors */
+ if (qc->flags & ATA_QCFLAG_IO)
+ return 1; /* otherwise retry anything from fs stack */
+ if (qc->err_mask & AC_ERR_INVALID)
+ return 0; /* don't retry these */
+ return qc->err_mask != AC_ERR_DEV; /* retry if not dev error */
+}
+
+/**
* ata_eh_link_autopsy - analyze error and determine recovery action
* @link: host link to perform autopsy on
*
@@ -2119,9 +2178,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
/* determine whether the command is worth retrying */
- if (qc->flags & ATA_QCFLAG_IO ||
- (!(qc->err_mask & AC_ERR_INVALID) &&
- qc->err_mask != AC_ERR_DEV))
+ if (ata_eh_worth_retry(qc))
qc->flags |= ATA_QCFLAG_RETRY;
/* accumulate error info */
@@ -2237,6 +2294,7 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_IDLE, "IDLE" },
{ ATA_CMD_EDD, "EXECUTE DEVICE DIAGNOSTIC" },
{ ATA_CMD_DOWNLOAD_MICRO, "DOWNLOAD MICROCODE" },
+ { ATA_CMD_DOWNLOAD_MICRO_DMA, "DOWNLOAD MICROCODE DMA" },
{ ATA_CMD_NOP, "NOP" },
{ ATA_CMD_FLUSH, "FLUSH CACHE" },
{ ATA_CMD_FLUSH_EXT, "FLUSH CACHE EXT" },
@@ -2257,6 +2315,8 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_WRITE_QUEUED_FUA_EXT, "WRITE DMA QUEUED FUA EXT" },
{ ATA_CMD_FPDMA_READ, "READ FPDMA QUEUED" },
{ ATA_CMD_FPDMA_WRITE, "WRITE FPDMA QUEUED" },
+ { ATA_CMD_FPDMA_SEND, "SEND FPDMA QUEUED" },
+ { ATA_CMD_FPDMA_RECV, "RECEIVE FPDMA QUEUED" },
{ ATA_CMD_PIO_READ, "READ SECTOR(S)" },
{ ATA_CMD_PIO_READ_EXT, "READ SECTOR(S) EXT" },
{ ATA_CMD_PIO_WRITE, "WRITE SECTOR(S)" },
@@ -2283,12 +2343,15 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_WRITE_LOG_EXT, "WRITE LOG EXT" },
{ ATA_CMD_READ_LOG_DMA_EXT, "READ LOG DMA EXT" },
{ ATA_CMD_WRITE_LOG_DMA_EXT, "WRITE LOG DMA EXT" },
+ { ATA_CMD_TRUSTED_NONDATA, "TRUSTED NON-DATA" },
{ ATA_CMD_TRUSTED_RCV, "TRUSTED RECEIVE" },
{ ATA_CMD_TRUSTED_RCV_DMA, "TRUSTED RECEIVE DMA" },
{ ATA_CMD_TRUSTED_SND, "TRUSTED SEND" },
{ ATA_CMD_TRUSTED_SND_DMA, "TRUSTED SEND DMA" },
{ ATA_CMD_PMP_READ, "READ BUFFER" },
+ { ATA_CMD_PMP_READ_DMA, "READ BUFFER DMA" },
{ ATA_CMD_PMP_WRITE, "WRITE BUFFER" },
+ { ATA_CMD_PMP_WRITE_DMA, "WRITE BUFFER DMA" },
{ ATA_CMD_CONF_OVERLAY, "DEVICE CONFIGURATION OVERLAY" },
{ ATA_CMD_SEC_SET_PASS, "SECURITY SET PASSWORD" },
{ ATA_CMD_SEC_UNLOCK, "SECURITY UNLOCK" },
@@ -2307,6 +2370,8 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_CFA_TRANS_SECT, "CFA TRANSLATE SECTOR" },
{ ATA_CMD_CFA_ERASE, "CFA ERASE SECTORS" },
{ ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" },
+ { ATA_CMD_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" },
+ { ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" },
{ ATA_CMD_READ_LONG, "READ LONG (with retries)" },
{ ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" },
{ ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" },
@@ -2338,7 +2403,7 @@ static void ata_eh_link_report(struct ata_link *link)
struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
const char *frozen, *desc;
- char tries_buf[6];
+ char tries_buf[6] = "";
int tag, nr_failed = 0;
if (ehc->i.flags & ATA_EHI_QUIET)
@@ -2369,9 +2434,8 @@ static void ata_eh_link_report(struct ata_link *link)
if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
- memset(tries_buf, 0, sizeof(tries_buf));
if (ap->eh_tries < ATA_EH_MAX_TRIES)
- snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+ snprintf(tries_buf, sizeof(tries_buf), " t%d",
ap->eh_tries);
if (ehc->i.dev) {
@@ -2492,11 +2556,12 @@ static void ata_eh_link_report(struct ata_link *link)
}
if (cmd->command != ATA_CMD_PACKET &&
- (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF |
- ATA_ABORTED)))
- ata_dev_err(qc->dev, "error: { %s%s%s%s}\n",
+ (res->feature & (ATA_ICRC | ATA_UNC | ATA_AMNF |
+ ATA_IDNF | ATA_ABORTED)))
+ ata_dev_err(qc->dev, "error: { %s%s%s%s%s}\n",
res->feature & ATA_ICRC ? "ICRC " : "",
res->feature & ATA_UNC ? "UNC " : "",
+ res->feature & ATA_AMNF ? "AMNF " : "",
res->feature & ATA_IDNF ? "IDNF " : "",
res->feature & ATA_ABORTED ? "ABRT " : "");
#endif
@@ -2569,6 +2634,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
*/
while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX)
max_tries++;
+ if (link->flags & ATA_LFLAG_RST_ONCE)
+ max_tries = 1;
if (link->flags & ATA_LFLAG_NO_HRST)
hardreset = NULL;
if (link->flags & ATA_LFLAG_NO_SRST)
@@ -2599,6 +2666,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
* bus as we may be talking too fast.
*/
dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = 0xff;
/* If the controller has a pio mode setup function
* then use it to set the chipset to rights. Don't
@@ -2950,7 +3018,7 @@ static inline void ata_eh_pull_park_action(struct ata_port *ap)
* ourselves at the beginning of each pass over the loop.
*
* Additionally, all write accesses to &ap->park_req_pending
- * through INIT_COMPLETION() (see below) or complete_all()
+ * through reinit_completion() (see below) or complete_all()
* (see ata_scsi_park_store()) are protected by the host lock.
* As a result we have that park_req_pending.done is zero on
* exit from this function, i.e. when ATA_EH_PARK actions for
@@ -2964,7 +3032,7 @@ static inline void ata_eh_pull_park_action(struct ata_port *ap)
*/
spin_lock_irqsave(ap->lock, flags);
- INIT_COMPLETION(ap->park_req_pending);
+ reinit_completion(&ap->park_req_pending);
ata_for_each_link(link, ap, EDGE) {
ata_for_each_dev(dev, link, ALL) {
struct ata_eh_info *ehi = &link->eh_info;
@@ -3500,7 +3568,8 @@ static int ata_count_probe_trials_cb(struct ata_ering_entry *ent, void *void_arg
u64 now = get_jiffies_64();
int *trials = void_arg;
- if (ent->timestamp < now - min(now, interval))
+ if ((ent->eflags & ATA_EFLAG_OLD_ER) ||
+ (ent->timestamp < now - min(now, interval)))
return -1;
(*trials)++;
@@ -3797,6 +3866,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = atapi_eh_clear_ua(dev);
if (rc)
goto rest_fail;
+ if (zpodd_dev_enabled(dev))
+ zpodd_post_poweron(dev);
}
}
@@ -3962,11 +4033,12 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
{
unsigned long flags;
int rc = 0;
+ struct ata_device *dev;
/* are we suspending? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
- ap->pm_mesg.event == PM_EVENT_ON) {
+ ap->pm_mesg.event & PM_EVENT_RESUME) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
@@ -3974,6 +4046,18 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+ /*
+ * If we have a ZPODD attached, check its zero
+ * power ready status before the port is frozen.
+ * Only needed for runtime suspend.
+ */
+ if (PMSG_IS_AUTO(ap->pm_mesg)) {
+ ata_for_each_dev(dev, &ap->link, ENABLED) {
+ if (zpodd_dev_enabled(dev))
+ zpodd_on_suspend(dev);
+ }
+ }
+
/* tell ACPI we're suspending */
rc = ata_acpi_on_suspend(ap);
if (rc)
@@ -3985,9 +4069,9 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
if (ap->ops->port_suspend)
rc = ap->ops->port_suspend(ap, ap->pm_mesg);
- ata_acpi_set_state(ap, PMSG_SUSPEND);
+ ata_acpi_set_state(ap, ap->pm_mesg);
out:
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_PM_PENDING;
@@ -3996,11 +4080,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
else if (ap->pflags & ATA_PFLAG_FROZEN)
ata_port_schedule_eh(ap);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
-
spin_unlock_irqrestore(ap->lock, flags);
return;
@@ -4025,7 +4104,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
/* are we resuming? */
spin_lock_irqsave(ap->lock, flags);
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
- ap->pm_mesg.event != PM_EVENT_ON) {
+ !(ap->pm_mesg.event & PM_EVENT_RESUME)) {
spin_unlock_irqrestore(ap->lock, flags);
return;
}
@@ -4044,7 +4123,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
ata_for_each_dev(dev, link, ALL)
ata_ering_clear(&dev->ering);
- ata_acpi_set_state(ap, PMSG_ON);
+ ata_acpi_set_state(ap, ap->pm_mesg);
if (ap->ops->port_resume)
rc = ap->ops->port_resume(ap);
@@ -4052,13 +4131,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
/* tell ACPI that we're resuming */
ata_acpi_on_resume(ap);
- /* report result */
+ /* update the flags */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
- if (ap->pm_result) {
- *ap->pm_result = rc;
- ap->pm_result = NULL;
- }
spin_unlock_irqrestore(ap->lock, flags);
}
#endif /* CONFIG_PM */