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)) {
|
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
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:
|
||||||
|
if (tries[dev->devno] == 1) {
|
||||||
|
/* This is the last chance, better to slow
|
||||||
|
* down than lose it.
|
||||||
|
*/
|
||||||
sata_down_spd_limit(ap);
|
sata_down_spd_limit(ap);
|
||||||
/* fall through */
|
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
||||||
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]) {
|
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
/* 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,
|
||||||
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:
|
||||||
|
if (ehc->tries[dev->devno] == 1) {
|
||||||
|
/* This is the last chance, better to slow
|
||||||
|
* down than lose it.
|
||||||
|
*/
|
||||||
sata_down_spd_limit(ap);
|
sata_down_spd_limit(ap);
|
||||||
default:
|
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
|
||||||
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 (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
|
if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue