提交 14d2bac1 编写于 作者: T Tejun Heo 提交者: Jeff Garzik

[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: NTejun Heo <htejun@gmail.com>
Signed-off-by: NJeff Garzik <jeff@garzik.org>
上级 cf176e1a
...@@ -1370,11 +1370,18 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev, ...@@ -1370,11 +1370,18 @@ static int ata_dev_configure(struct ata_port *ap, struct ata_device *dev,
static int ata_bus_probe(struct ata_port *ap) static int ata_bus_probe(struct ata_port *ap)
{ {
unsigned int classes[ATA_MAX_DEVICES]; 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; struct ata_device *dev;
ata_port_probe(ap); 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 */ /* reset and determine device classes */
for (i = 0; i < ATA_MAX_DEVICES; i++) for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_UNKNOWN; classes[i] = ATA_DEV_UNKNOWN;
...@@ -1404,21 +1411,23 @@ static int ata_bus_probe(struct ata_port *ap) ...@@ -1404,21 +1411,23 @@ static int ata_bus_probe(struct ata_port *ap)
dev = &ap->device[i]; dev = &ap->device[i];
dev->class = classes[i]; dev->class = classes[i];
if (!ata_dev_enabled(dev)) if (!tries[i]) {
continue; ata_down_xfermask_limit(ap, dev, 1);
ata_dev_disable(ap, dev);
WARN_ON(dev->id != NULL);
if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) {
dev->class = ATA_DEV_NONE;
continue;
} }
if (ata_dev_configure(ap, dev, 1)) { if (!ata_dev_enabled(dev))
ata_dev_disable(ap, dev);
continue; continue;
}
found = 1; kfree(dev->id);
dev->id = NULL;
rc = ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id);
if (rc)
goto fail;
rc = ata_dev_configure(ap, dev, 1);
if (rc)
goto fail;
} }
/* configure transfer mode */ /* configure transfer mode */
...@@ -1427,12 +1436,18 @@ static int ata_bus_probe(struct ata_port *ap) ...@@ -1427,12 +1436,18 @@ static int ata_bus_probe(struct ata_port *ap)
* return error code and failing device on failure as * return error code and failing device on failure as
* ata_set_mode() does. * ata_set_mode() does.
*/ */
if (found) for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->ops->set_mode(ap); if (ata_dev_enabled(&ap->device[i])) {
ap->ops->set_mode(ap);
break;
}
rc = 0; rc = 0;
} else { } else {
while (ata_set_mode(ap, &dev)) rc = ata_set_mode(ap, &dev);
ata_dev_disable(ap, dev); if (rc) {
down_xfermask = 1;
goto fail;
}
} }
for (i = 0; i < ATA_MAX_DEVICES; i++) for (i = 0; i < ATA_MAX_DEVICES; i++)
...@@ -1443,6 +1458,24 @@ static int ata_bus_probe(struct ata_port *ap) ...@@ -1443,6 +1458,24 @@ static int ata_bus_probe(struct ata_port *ap)
ata_port_disable(ap); ata_port_disable(ap);
ap->ops->port_disable(ap); ap->ops->port_disable(ap);
return -ENODEV; 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 { ...@@ -211,6 +211,9 @@ enum {
/* Masks for port functions */ /* Masks for port functions */
ATA_PORT_PRIMARY = (1 << 0), ATA_PORT_PRIMARY = (1 << 0),
ATA_PORT_SECONDARY = (1 << 1), ATA_PORT_SECONDARY = (1 << 1),
/* how hard are we gonna try to probe/recover devices */
ATA_PROBE_MAX_TRIES = 3,
}; };
enum hsm_task_states { enum hsm_task_states {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册