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:
parent
458337dbb1
commit
4ae72a1e46
2 changed files with 37 additions and 37 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]) {
|
||||
|
|
Loading…
Reference in a new issue