|
@@ -1897,6 +1897,57 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
|
|
|
+{
|
|
|
+ struct ata_port *ap = dev->ap;
|
|
|
+ struct ata_eh_context *ehc = &ap->eh_context;
|
|
|
+
|
|
|
+ ehc->tries[dev->devno]--;
|
|
|
+
|
|
|
+ switch (err) {
|
|
|
+ case -ENODEV:
|
|
|
+ /* device missing or wrong IDENTIFY data, schedule probing */
|
|
|
+ ehc->i.probe_mask |= (1 << dev->devno);
|
|
|
+ case -EINVAL:
|
|
|
+ /* give it just one more chance */
|
|
|
+ ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
|
|
|
+ case -EIO:
|
|
|
+ if (ehc->tries[dev->devno] == 1) {
|
|
|
+ /* This is the last chance, better to slow
|
|
|
+ * down than lose it.
|
|
|
+ */
|
|
|
+ sata_down_spd_limit(ap);
|
|
|
+ ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
|
|
|
+ /* disable device if it has used up all its chances */
|
|
|
+ ata_dev_disable(dev);
|
|
|
+
|
|
|
+ /* detach if offline */
|
|
|
+ if (ata_port_offline(ap))
|
|
|
+ ata_eh_detach_dev(dev);
|
|
|
+
|
|
|
+ /* probe if requested */
|
|
|
+ if ((ehc->i.probe_mask & (1 << dev->devno)) &&
|
|
|
+ !(ehc->did_probe_mask & (1 << dev->devno))) {
|
|
|
+ ata_eh_detach_dev(dev);
|
|
|
+ ata_dev_init(dev);
|
|
|
+
|
|
|
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
|
|
|
+ ehc->did_probe_mask |= (1 << dev->devno);
|
|
|
+ ehc->i.action |= ATA_EH_SOFTRESET;
|
|
|
+ }
|
|
|
+ } 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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ata_eh_recover - recover host port after error
|
|
|
* @ap: host port to recover
|
|
@@ -1997,50 +2048,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
|
|
goto out;
|
|
|
|
|
|
dev_fail:
|
|
|
- ehc->tries[dev->devno]--;
|
|
|
-
|
|
|
- switch (rc) {
|
|
|
- case -ENODEV:
|
|
|
- /* device missing or wrong IDENTIFY data, schedule probing */
|
|
|
- ehc->i.probe_mask |= (1 << dev->devno);
|
|
|
- case -EINVAL:
|
|
|
- /* give it just one more chance */
|
|
|
- ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
|
|
|
- case -EIO:
|
|
|
- if (ehc->tries[dev->devno] == 1) {
|
|
|
- /* This is the last chance, better to slow
|
|
|
- * down than lose it.
|
|
|
- */
|
|
|
- sata_down_spd_limit(ap);
|
|
|
- ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
|
|
|
- /* disable device if it has used up all its chances */
|
|
|
- ata_dev_disable(dev);
|
|
|
-
|
|
|
- /* detach if offline */
|
|
|
- if (ata_port_offline(ap))
|
|
|
- ata_eh_detach_dev(dev);
|
|
|
-
|
|
|
- /* probe if requested */
|
|
|
- if ((ehc->i.probe_mask & (1 << dev->devno)) &&
|
|
|
- !(ehc->did_probe_mask & (1 << dev->devno))) {
|
|
|
- ata_eh_detach_dev(dev);
|
|
|
- ata_dev_init(dev);
|
|
|
-
|
|
|
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
|
|
|
- ehc->did_probe_mask |= (1 << dev->devno);
|
|
|
- ehc->i.action |= ATA_EH_SOFTRESET;
|
|
|
- }
|
|
|
- } 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;
|
|
|
- }
|
|
|
+ ata_eh_handle_dev_fail(dev, rc);
|
|
|
|
|
|
if (ata_port_nr_enabled(ap)) {
|
|
|
ata_port_printk(ap, KERN_WARNING, "failed to recover some "
|