diff options
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 226 |
1 files changed, 98 insertions, 128 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index a5830329eda..61dcd0026c6 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -873,9 +873,9 @@ int sata_async_notification(struct ata_port *ap) if (rc == 0) sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf); - if (!ap->nr_pmp_links || rc) { + if (!sata_pmp_attached(ap) || rc) { /* PMP is not attached or SNTF is not available */ - if (!ap->nr_pmp_links) { + if (!sata_pmp_attached(ap)) { /* PMP is not attached. Check whether ATAPI * AN is configured. If so, notify media * change. @@ -1079,19 +1079,6 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev, spin_lock_irqsave(ap->lock, flags); - /* Reset is represented by combination of actions and EHI - * flags. Suck in all related bits before clearing eh_info to - * avoid losing requested action. - */ - if (action & ATA_EH_RESET_MASK) { - ehc->i.action |= ehi->action & ATA_EH_RESET_MASK; - ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK; - - /* make sure all reset actions are cleared & clear EHI flags */ - action |= ATA_EH_RESET_MASK; - ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; - } - ata_eh_clear_action(link, dev, ehi, action); if (!(ehc->i.flags & ATA_EHI_QUIET)) @@ -1117,12 +1104,6 @@ void ata_eh_done(struct ata_link *link, struct ata_device *dev, { struct ata_eh_context *ehc = &link->eh_context; - /* if reset is complete, clear all reset actions & reset modifier */ - if (action & ATA_EH_RESET_MASK) { - action |= ATA_EH_RESET_MASK; - ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; - } - ata_eh_clear_action(link, dev, &ehc->i, action); } @@ -1329,20 +1310,20 @@ static void ata_eh_analyze_serror(struct ata_link *link) if (serror & SERR_PERSISTENT) { err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; } if (serror & (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) { err_mask |= AC_ERR_ATA_BUS; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; } if (serror & SERR_PROTOCOL) { err_mask |= AC_ERR_HSM; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; } if (serror & SERR_INTERNAL) { err_mask |= AC_ERR_SYSTEM; - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; } /* Determine whether a hotplug event has occurred. Both @@ -1421,6 +1402,7 @@ static void ata_eh_analyze_ncq_error(struct ata_link *link) /* we've got the perpetrator, condemn it */ qc = __ata_qc_from_tag(ap, tag); memcpy(&qc->result_tf, &tf, sizeof(tf)); + qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48; qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ; ehc->i.err_mask &= ~AC_ERR_DEV; } @@ -1448,7 +1430,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) { qc->err_mask |= AC_ERR_HSM; - return ATA_EH_SOFTRESET; + return ATA_EH_RESET; } if (stat & (ATA_ERR | ATA_DF)) @@ -1484,7 +1466,7 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, } if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS)) - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; return action; } @@ -1685,7 +1667,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ if (sata_down_spd_limit(link) == 0) { - action |= ATA_EH_HARDRESET; + action |= ATA_EH_RESET; goto done; } @@ -1705,7 +1687,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, dev->spdn_cnt++; if (ata_down_xfermask_limit(dev, sel) == 0) { - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; goto done; } } @@ -1719,7 +1701,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, (dev->xfer_shift != ATA_SHIFT_PIO)) { if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { dev->spdn_cnt = 0; - action |= ATA_EH_SOFTRESET; + action |= ATA_EH_RESET; goto done; } } @@ -1764,9 +1746,9 @@ static void ata_eh_link_autopsy(struct ata_link *link) ehc->i.serror |= serror; ata_eh_analyze_serror(link); } else if (rc != -EOPNOTSUPP) { - /* SError read failed, force hardreset and probing */ - ata_ehi_schedule_probe(&ehc->i); - ehc->i.action |= ATA_EH_HARDRESET; + /* SError read failed, force reset and probing */ + ehc->i.probe_mask |= ATA_ALL_DEVICES; + ehc->i.action |= ATA_EH_RESET; ehc->i.err_mask |= AC_ERR_OTHER; } @@ -1804,6 +1786,11 @@ static void ata_eh_link_autopsy(struct ata_link *link) if (qc->flags & ATA_QCFLAG_SENSE_VALID) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); + /* determine whether the command is worth retrying */ + if (!(qc->err_mask & AC_ERR_INVALID) && + ((qc->flags & ATA_QCFLAG_IO) || qc->err_mask != AC_ERR_DEV)) + qc->flags |= ATA_QCFLAG_RETRY; + /* accumulate error info */ ehc->i.dev = qc->dev; all_err_mask |= qc->err_mask; @@ -1814,7 +1801,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) /* enforce default EH actions */ if (ap->pflags & ATA_PFLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) - ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.action |= ATA_EH_RESET; else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) || (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV))) ehc->i.action |= ATA_EH_REVALIDATE; @@ -1867,7 +1854,7 @@ void ata_eh_autopsy(struct ata_port *ap) /* Autopsy of fanout ports can affect host link autopsy. * Perform host link autopsy last. */ - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) ata_eh_link_autopsy(&ap->link); } @@ -2066,41 +2053,29 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, classes[dev->devno] = ATA_DEV_UNKNOWN; rc = reset(link, classes, deadline); - if (rc) - return rc; - /* If any class isn't ATA_DEV_UNKNOWN, consider classification - * is complete and convert all ATA_DEV_UNKNOWN to - * ATA_DEV_NONE. - */ + /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */ ata_link_for_each_dev(dev, link) - if (classes[dev->devno] != ATA_DEV_UNKNOWN) - break; - - if (dev) { - ata_link_for_each_dev(dev, link) { - if (classes[dev->devno] == ATA_DEV_UNKNOWN) - classes[dev->devno] = ATA_DEV_NONE; - } - } + if (classes[dev->devno] == ATA_DEV_UNKNOWN) + classes[dev->devno] = ATA_DEV_NONE; - return 0; + return rc; } static int ata_eh_followup_srst_needed(struct ata_link *link, int rc, int classify, const unsigned int *classes) { - if (link->flags & ATA_LFLAG_NO_SRST) + if ((link->flags & ATA_LFLAG_NO_SRST) || ata_link_offline(link)) return 0; - if (rc == -EAGAIN) - return 1; + if (rc == -EAGAIN) { + if (classify) + return 1; + rc = 0; + } if (rc != 0) return 0; - if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link)) - return 1; - if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) && - classes[0] == ATA_DEV_UNKNOWN) + if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) return 1; return 0; } @@ -2118,7 +2093,6 @@ int ata_eh_reset(struct ata_link *link, int classify, int try = 0; struct ata_device *dev; unsigned long deadline, now; - unsigned int tmp_action; ata_reset_fn_t reset; unsigned long flags; u32 sstatus; @@ -2129,7 +2103,7 @@ int ata_eh_reset(struct ata_link *link, int classify, ap->pflags |= ATA_PFLAG_RESETTING; spin_unlock_irqrestore(ap->lock, flags); - ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ATA_EH_RESET); ata_link_for_each_dev(dev, link) { /* If we issue an SRST then an ATA drive (not ATAPI) @@ -2159,17 +2133,20 @@ int ata_eh_reset(struct ata_link *link, int classify, goto done; } - /* Determine which reset to use and record in ehc->i.action. - * prereset() may examine and modify it. - */ - if (softreset && (!hardreset || (!(lflags & ATA_LFLAG_NO_SRST) && - !sata_set_spd_needed(link) && - !(ehc->i.action & ATA_EH_HARDRESET)))) - tmp_action = ATA_EH_SOFTRESET; - else - tmp_action = ATA_EH_HARDRESET; - - ehc->i.action = (ehc->i.action & ~ATA_EH_RESET_MASK) | tmp_action; + /* prefer hardreset */ + ehc->i.action &= ~ATA_EH_RESET; + if (hardreset) { + reset = hardreset; + ehc->i.action = ATA_EH_HARDRESET; + } else if (softreset) { + reset = softreset; + ehc->i.action = ATA_EH_SOFTRESET; + } else { + ata_link_printk(link, KERN_ERR, "BUG: no reset method, " + "please report to linux-ide@vger.kernel.org\n"); + dump_stack(); + return -EINVAL; + } if (prereset) { rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT); @@ -2177,7 +2154,7 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc == -ENOENT) { ata_link_printk(link, KERN_DEBUG, "port disabled. ignoring.\n"); - ehc->i.action &= ~ATA_EH_RESET_MASK; + ehc->i.action &= ~ATA_EH_RESET; ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; @@ -2190,12 +2167,8 @@ int ata_eh_reset(struct ata_link *link, int classify, } } - /* prereset() might have modified ehc->i.action */ - if (ehc->i.action & ATA_EH_HARDRESET) - reset = hardreset; - else if (ehc->i.action & ATA_EH_SOFTRESET) - reset = softreset; - else { + /* prereset() might have cleared ATA_EH_RESET */ + if (!(ehc->i.action & ATA_EH_RESET)) { /* prereset told us not to reset, bang classes and return */ ata_link_for_each_dev(dev, link) classes[dev->devno] = ATA_DEV_NONE; @@ -2203,14 +2176,6 @@ int ata_eh_reset(struct ata_link *link, int classify, goto out; } - /* did prereset() screw up? if so, fix up to avoid oopsing */ - if (!reset) { - if (softreset) - reset = softreset; - else - reset = hardreset; - } - retry: deadline = jiffies + ata_eh_reset_timeouts[try++]; @@ -2240,7 +2205,7 @@ int ata_eh_reset(struct ata_link *link, int classify, goto fail; } - ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK); + ata_eh_about_to_do(link, NULL, ATA_EH_RESET); rc = ata_do_reset(link, reset, classes, deadline); } @@ -2248,21 +2213,6 @@ int ata_eh_reset(struct ata_link *link, int classify, if (rc && rc != -EAGAIN) goto fail; - /* was classification successful? */ - if (classify && classes[0] == ATA_DEV_UNKNOWN && - !(lflags & ATA_LFLAG_ASSUME_CLASS)) { - if (try < max_tries) { - ata_link_printk(link, KERN_WARNING, - "classification failed\n"); - rc = -EINVAL; - goto fail; - } - - ata_link_printk(link, KERN_WARNING, - "classfication failed, assuming ATA\n"); - lflags |= ATA_LFLAG_ASSUME_ATA; - } - done: ata_link_for_each_dev(dev, link) { /* After the reset, the device state is PIO 0 and the @@ -2290,7 +2240,7 @@ int ata_eh_reset(struct ata_link *link, int classify, postreset(link, classes); /* reset successful, schedule revalidation */ - ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK); + ata_eh_done(link, NULL, ATA_EH_RESET); ehc->i.action |= ATA_EH_REVALIDATE; rc = 0; @@ -2305,6 +2255,11 @@ int ata_eh_reset(struct ata_link *link, int classify, return rc; fail: + /* if SCR isn't accessible on a fan-out port, PMP needs to be reset */ + if (!ata_is_host_link(link) && + sata_scr_read(link, SCR_STATUS, &sstatus)) + rc = -ERESTART; + if (rc == -ERESTART || try >= max_tries) goto out; @@ -2515,6 +2470,7 @@ static int ata_link_nr_vacant(struct ata_link *link) static int ata_eh_skip_recovery(struct ata_link *link) { + struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; @@ -2522,9 +2478,13 @@ static int ata_eh_skip_recovery(struct ata_link *link) if (link->flags & ATA_LFLAG_DISABLED) return 1; - /* thaw frozen port, resume link and recover failed devices */ - if ((link->ap->pflags & ATA_PFLAG_FROZEN) || - (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link)) + /* thaw frozen port and recover failed devices */ + if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link)) + return 0; + + /* reset at least once if reset is requested */ + if ((ehc->i.action & ATA_EH_RESET) && + !(ehc->i.flags & ATA_EHI_DID_RESET)) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ @@ -2548,7 +2508,7 @@ static int ata_eh_schedule_probe(struct ata_device *dev) ata_eh_detach_dev(dev); ata_dev_init(dev); ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; + ehc->i.action |= ATA_EH_RESET; ehc->saved_xfer_mode[dev->devno] = 0; ehc->saved_ncq_enabled &= ~(1 << dev->devno); @@ -2592,12 +2552,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) return 1; } else { - /* soft didn't work? be haaaaard */ - if (ehc->i.flags & ATA_EHI_DID_RESET) - ehc->i.action |= ATA_EH_HARDRESET; - else - ehc->i.action |= ATA_EH_SOFTRESET; - + ehc->i.action |= ATA_EH_RESET; return 0; } } @@ -2690,7 +2645,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ehc->i.action = 0; /* do we need to reset? */ - if (ehc->i.action & ATA_EH_RESET_MASK) + if (ehc->i.action & ATA_EH_RESET) reset = 1; ata_link_for_each_dev(dev, link) @@ -2702,13 +2657,13 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* if PMP is attached, this function only deals with * downstream links, port should stay thawed. */ - if (!ap->nr_pmp_links) + if (!sata_pmp_attached(ap)) ata_eh_freeze_port(ap); ata_port_for_each_link(link, ap) { struct ata_eh_context *ehc = &link->eh_context; - if (!(ehc->i.action & ATA_EH_RESET_MASK)) + if (!(ehc->i.action & ATA_EH_RESET)) continue; rc = ata_eh_reset(link, ata_link_nr_vacant(link), @@ -2721,7 +2676,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } } - if (!ap->nr_pmp_links) + if (!sata_pmp_attached(ap)) ata_eh_thaw_port(ap); } @@ -2765,7 +2720,7 @@ dev_fail: /* PMP reset requires working host port. * Can't retry if it's frozen. */ - if (ap->nr_pmp_links) + if (sata_pmp_attached(ap)) goto out; break; } @@ -2817,18 +2772,11 @@ void ata_eh_finish(struct ata_port *ap) /* FIXME: Once EH migration is complete, * generate sense data in this function, * considering both err_mask and tf. - * - * There's no point in retrying invalid - * (detected by libata) and non-IO device - * errors (rejected by device). Finish them - * immediately. */ - if ((qc->err_mask & AC_ERR_INVALID) || - (!(qc->flags & ATA_QCFLAG_IO) && - qc->err_mask == AC_ERR_DEV)) - ata_eh_qc_complete(qc); - else + if (qc->flags & ATA_QCFLAG_RETRY) ata_eh_qc_retry(qc); + else + ata_eh_qc_complete(qc); } else { if (qc->flags & ATA_QCFLAG_SENSE_VALID) { ata_eh_qc_complete(qc); @@ -2848,6 +2796,7 @@ void ata_eh_finish(struct ata_port *ap) /** * ata_do_eh - do standard error handling * @ap: host port to handle error for + * * @prereset: prereset method (can be NULL) * @softreset: softreset method (can be NULL) * @hardreset: hardreset method (can be NULL) @@ -2878,6 +2827,27 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_eh_finish(ap); } +/** + * ata_std_error_handler - standard error handler + * @ap: host port to handle error for + * + * Standard error handler + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_std_error_handler(struct ata_port *ap) +{ + struct ata_port_operations *ops = ap->ops; + ata_reset_fn_t hardreset = ops->hardreset; + + /* ignore built-in hardreset if SCR access is not available */ + if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link)) + hardreset = NULL; + + ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset); +} + #ifdef CONFIG_PM /** * ata_eh_handle_port_suspend - perform port suspend operation |