Commit 4ae72a1e authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

libata: improve probe failure handling

* Move forcing device to PIO0 on device disable into
  ata_dev_disable().  This makes both old and new EHs act the same
  way.

* Speed down only PIO mode on probe failure.  All commands used during
  probing are PIO commands.  There's no point in speeding down DMA.

* Retry at least once after -ENODEV.  Some devices report garbled
  IDENTIFY data after certain events.  This shouldn't cause device
  detach and re-attach.

* Rearrange EH failure path for simplicity.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 458337db
...@@ -600,6 +600,8 @@ void ata_dev_disable(struct ata_device *dev) ...@@ -600,6 +600,8 @@ void ata_dev_disable(struct ata_device *dev)
{ {
if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) { if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
ata_dev_printk(dev, KERN_WARNING, "disabled\n"); ata_dev_printk(dev, KERN_WARNING, "disabled\n");
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
ATA_DNXFER_QUIET);
dev->class++; dev->class++;
} }
} }
...@@ -1778,9 +1780,8 @@ int ata_bus_probe(struct ata_port *ap) ...@@ -1778,9 +1780,8 @@ int ata_bus_probe(struct ata_port *ap)
{ {
unsigned int classes[ATA_MAX_DEVICES]; unsigned int classes[ATA_MAX_DEVICES];
int tries[ATA_MAX_DEVICES]; int tries[ATA_MAX_DEVICES];
int i, rc, down_xfermask; int i, rc;
struct ata_device *dev; struct ata_device *dev;
int dnxfer_sel;
ata_port_probe(ap); ata_port_probe(ap);
...@@ -1788,8 +1789,6 @@ int ata_bus_probe(struct ata_port *ap) ...@@ -1788,8 +1789,6 @@ int ata_bus_probe(struct ata_port *ap)
tries[i] = ATA_PROBE_MAX_TRIES; tries[i] = ATA_PROBE_MAX_TRIES;
retry: retry:
down_xfermask = 0;
/* reset and determine device classes */ /* reset and determine device classes */
ap->ops->phy_reset(ap); ap->ops->phy_reset(ap);
...@@ -1837,10 +1836,8 @@ int ata_bus_probe(struct ata_port *ap) ...@@ -1837,10 +1836,8 @@ int ata_bus_probe(struct ata_port *ap)
/* configure transfer mode */ /* configure transfer mode */
rc = ata_set_mode(ap, &dev); rc = ata_set_mode(ap, &dev);
if (rc) { if (rc)
down_xfermask = 1;
goto fail; goto fail;
}
for (i = 0; i < ATA_MAX_DEVICES; i++) for (i = 0; i < ATA_MAX_DEVICES; i++)
if (ata_dev_enabled(&ap->device[i])) if (ata_dev_enabled(&ap->device[i]))
...@@ -1852,27 +1849,29 @@ int ata_bus_probe(struct ata_port *ap) ...@@ -1852,27 +1849,29 @@ int ata_bus_probe(struct ata_port *ap)
return -ENODEV; return -ENODEV;
fail: fail:
tries[dev->devno]--;
switch (rc) { switch (rc) {
case -EINVAL: case -EINVAL:
case -ENODEV: /* eeek, something went very wrong, give up */
tries[dev->devno] = 0; tries[dev->devno] = 0;
break; break;
case -ENODEV:
/* give it just one more chance */
tries[dev->devno] = min(tries[dev->devno], 1);
case -EIO: case -EIO:
sata_down_spd_limit(ap); if (tries[dev->devno] == 1) {
/* fall through */ /* This is the last chance, better to slow
default: * down than lose it.
tries[dev->devno]--; */
dnxfer_sel = ATA_DNXFER_ANY; sata_down_spd_limit(ap);
if (tries[dev->devno] == 1) ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
dnxfer_sel = ATA_DNXFER_FORCE_PIO0; }
if (down_xfermask && ata_down_xfermask_limit(dev, dnxfer_sel))
tries[dev->devno] = 0;
} }
if (!tries[dev->devno]) { if (!tries[dev->devno])
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0);
ata_dev_disable(dev); ata_dev_disable(dev);
}
goto retry; goto retry;
} }
......
...@@ -1964,8 +1964,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -1964,8 +1964,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
{ {
struct ata_eh_context *ehc = &ap->eh_context; struct ata_eh_context *ehc = &ap->eh_context;
struct ata_device *dev; struct ata_device *dev;
int down_xfermask, i, rc; int i, rc;
int dnxfer_sel;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
...@@ -1994,7 +1993,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -1994,7 +1993,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
} }
retry: retry:
down_xfermask = 0;
rc = 0; rc = 0;
/* if UNLOADING, finish immediately */ /* if UNLOADING, finish immediately */
...@@ -2039,10 +2037,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -2039,10 +2037,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
/* configure transfer mode if necessary */ /* configure transfer mode if necessary */
if (ehc->i.flags & ATA_EHI_SETMODE) { if (ehc->i.flags & ATA_EHI_SETMODE) {
rc = ata_set_mode(ap, &dev); rc = ata_set_mode(ap, &dev);
if (rc) { if (rc)
down_xfermask = 1;
goto dev_fail; goto dev_fail;
}
ehc->i.flags &= ~ATA_EHI_SETMODE; ehc->i.flags &= ~ATA_EHI_SETMODE;
} }
...@@ -2054,22 +2050,27 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ...@@ -2054,22 +2050,27 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
goto out; goto out;
dev_fail: dev_fail:
ehc->tries[dev->devno]--;
switch (rc) { switch (rc) {
case -ENODEV:
/* device missing, schedule probing */
ehc->i.probe_mask |= (1 << dev->devno);
case -EINVAL: case -EINVAL:
/* eeek, something went very wrong, give up */
ehc->tries[dev->devno] = 0; ehc->tries[dev->devno] = 0;
break; break;
case -ENODEV:
/* device missing or wrong IDENTIFY data, schedule probing */
ehc->i.probe_mask |= (1 << dev->devno);
/* give it just one more chance */
ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
case -EIO: case -EIO:
sata_down_spd_limit(ap); if (ehc->tries[dev->devno] == 1) {
default: /* This is the last chance, better to slow
ehc->tries[dev->devno]--; * down than lose it.
dnxfer_sel = ATA_DNXFER_ANY; */
if (ehc->tries[dev->devno] == 1) sata_down_spd_limit(ap);
dnxfer_sel = ATA_DNXFER_FORCE_PIO0; ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
if (down_xfermask && ata_down_xfermask_limit(dev, dnxfer_sel)) }
ehc->tries[dev->devno] = 0;
} }
if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) { if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment