[PATCH] libata: improve ata_bus_probe()

Improve ata_bus_probe() such that configuration failures are handled
better.  Each device is given ATA_PROBE_MAX_TRIES chances, but any
non-transient error (revalidation failure with -ENODEV, configuration
failure with -EINVAL...) disables the device directly.  Any IO error
results in SATA PHY speed down and ata_set_mode() failure lowers
transfer mode.  The last try always puts a device into PIO-0.

After each failure, the whole port is reset to make sure that the
controller and all the devices are in a known and stable state.  The
reset also applies SATA SPD configuration if necessary.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Tejun Heo 2006-04-02 17:54:46 +09:00 коммит произвёл Jeff Garzik
Родитель cf176e1aa9
Коммит 14d2bac187
2 изменённых файлов: 52 добавлений и 16 удалений

Просмотреть файл

@ -1370,11 +1370,18 @@ err_out_nosup:
static int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
int i, rc, found = 0;
int tries[ATA_MAX_DEVICES];
int i, rc, down_xfermask;
struct ata_device *dev;
ata_port_probe(ap);
for (i = 0; i < ATA_MAX_DEVICES; i++)
tries[i] = ATA_PROBE_MAX_TRIES;
retry:
down_xfermask = 0;
/* reset and determine device classes */
for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_UNKNOWN;
@ -1404,21 +1411,23 @@ static int ata_bus_probe(struct ata_port *ap)
dev = &ap->device[i];
dev->class = classes[i];
if (!tries[i]) {
ata_down_xfermask_limit(ap, dev, 1);
ata_dev_disable(ap, dev);
}
if (!ata_dev_enabled(dev))
continue;
WARN_ON(dev->id != NULL);
if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) {
dev->class = ATA_DEV_NONE;
continue;
}
kfree(dev->id);
dev->id = NULL;
rc = ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id);
if (rc)
goto fail;
if (ata_dev_configure(ap, dev, 1)) {
ata_dev_disable(ap, dev);
continue;
}
found = 1;
rc = ata_dev_configure(ap, dev, 1);
if (rc)
goto fail;
}
/* configure transfer mode */
@ -1427,12 +1436,18 @@ static int ata_bus_probe(struct ata_port *ap)
* return error code and failing device on failure as
* ata_set_mode() does.
*/
if (found)
ap->ops->set_mode(ap);
for (i = 0; i < ATA_MAX_DEVICES; i++)
if (ata_dev_enabled(&ap->device[i])) {
ap->ops->set_mode(ap);
break;
}
rc = 0;
} else {
while (ata_set_mode(ap, &dev))
ata_dev_disable(ap, dev);
rc = ata_set_mode(ap, &dev);
if (rc) {
down_xfermask = 1;
goto fail;
}
}
for (i = 0; i < ATA_MAX_DEVICES; i++)
@ -1443,6 +1458,24 @@ static int ata_bus_probe(struct ata_port *ap)
ata_port_disable(ap);
ap->ops->port_disable(ap);
return -ENODEV;
fail:
switch (rc) {
case -EINVAL:
case -ENODEV:
tries[dev->devno] = 0;
break;
case -EIO:
ata_down_sata_spd_limit(ap);
/* fall through */
default:
tries[dev->devno]--;
if (down_xfermask &&
ata_down_xfermask_limit(ap, dev, tries[dev->devno] == 1))
tries[dev->devno] = 0;
}
goto retry;
}
/**

Просмотреть файл

@ -211,6 +211,9 @@ enum {
/* Masks for port functions */
ATA_PORT_PRIMARY = (1 << 0),
ATA_PORT_SECONDARY = (1 << 1),
/* how hard are we gonna try to probe/recover devices */
ATA_PROBE_MAX_TRIES = 3,
};
enum hsm_task_states {