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: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Tejun Heo 2007-02-02 16:22:30 +09:00 committed by Jeff Garzik
parent 458337dbb1
commit 4ae72a1e46
2 changed files with 37 additions and 37 deletions

View file

@ -600,6 +600,8 @@ void ata_dev_disable(struct ata_device *dev)
{
if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
ata_dev_printk(dev, KERN_WARNING, "disabled\n");
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
ATA_DNXFER_QUIET);
dev->class++;
}
}
@ -1778,9 +1780,8 @@ int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
int tries[ATA_MAX_DEVICES];
int i, rc, down_xfermask;
int i, rc;
struct ata_device *dev;
int dnxfer_sel;
ata_port_probe(ap);
@ -1788,8 +1789,6 @@ int ata_bus_probe(struct ata_port *ap)
tries[i] = ATA_PROBE_MAX_TRIES;
retry:
down_xfermask = 0;
/* reset and determine device classes */
ap->ops->phy_reset(ap);
@ -1837,10 +1836,8 @@ int ata_bus_probe(struct ata_port *ap)
/* configure transfer mode */
rc = ata_set_mode(ap, &dev);
if (rc) {
down_xfermask = 1;
if (rc)
goto fail;
}
for (i = 0; i < ATA_MAX_DEVICES; i++)
if (ata_dev_enabled(&ap->device[i]))
@ -1852,27 +1849,29 @@ int ata_bus_probe(struct ata_port *ap)
return -ENODEV;
fail:
tries[dev->devno]--;
switch (rc) {
case -EINVAL:
case -ENODEV:
/* eeek, something went very wrong, give up */
tries[dev->devno] = 0;
break;
case -ENODEV:
/* give it just one more chance */
tries[dev->devno] = min(tries[dev->devno], 1);
case -EIO:
sata_down_spd_limit(ap);
/* fall through */
default:
tries[dev->devno]--;
dnxfer_sel = ATA_DNXFER_ANY;
if (tries[dev->devno] == 1)
dnxfer_sel = ATA_DNXFER_FORCE_PIO0;
if (down_xfermask && ata_down_xfermask_limit(dev, dnxfer_sel))
tries[dev->devno] = 0;
if (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 (!tries[dev->devno]) {
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0);
if (!tries[dev->devno])
ata_dev_disable(dev);
}
goto retry;
}

View file

@ -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_device *dev;
int down_xfermask, i, rc;
int dnxfer_sel;
int i, rc;
DPRINTK("ENTER\n");
@ -1994,7 +1993,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
}
retry:
down_xfermask = 0;
rc = 0;
/* if UNLOADING, finish immediately */
@ -2039,10 +2037,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
/* configure transfer mode if necessary */
if (ehc->i.flags & ATA_EHI_SETMODE) {
rc = ata_set_mode(ap, &dev);
if (rc) {
down_xfermask = 1;
if (rc)
goto dev_fail;
}
ehc->i.flags &= ~ATA_EHI_SETMODE;
}
@ -2054,22 +2050,27 @@ 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, schedule probing */
ehc->i.probe_mask |= (1 << dev->devno);
case -EINVAL:
/* eeek, something went very wrong, give up */
ehc->tries[dev->devno] = 0;
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:
sata_down_spd_limit(ap);
default:
ehc->tries[dev->devno]--;
dnxfer_sel = ATA_DNXFER_ANY;
if (ehc->tries[dev->devno] == 1)
dnxfer_sel = ATA_DNXFER_FORCE_PIO0;
if (down_xfermask && ata_down_xfermask_limit(dev, dnxfer_sel))
ehc->tries[dev->devno] = 0;
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]) {