diff options
| author | Tejun Heo <htejun@gmail.com> | 2006-04-02 04:54:46 -0400 |
|---|---|---|
| committer | Jeff Garzik <jeff@garzik.org> | 2006-04-02 10:02:57 -0400 |
| commit | 14d2bac1877ed4e2cc940d1680db1a4f29225811 (patch) | |
| tree | 60b478485e7453dd5a41aea34699a305dd3c8d2c | |
| parent | cf176e1aa92eb2a3faea8409e841396a66413937 (diff) | |
[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>
| -rw-r--r-- | drivers/scsi/libata-core.c | 65 | ||||
| -rw-r--r-- | include/linux/libata.h | 3 |
2 files changed, 52 insertions, 16 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 68fa64d24721..33b5bff58cc3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
| @@ -1370,11 +1370,18 @@ err_out_nosup: | |||
| 1370 | static int ata_bus_probe(struct ata_port *ap) | 1370 | static int ata_bus_probe(struct ata_port *ap) |
| 1371 | { | 1371 | { |
| 1372 | unsigned int classes[ATA_MAX_DEVICES]; | 1372 | unsigned int classes[ATA_MAX_DEVICES]; |
| 1373 | int i, rc, found = 0; | 1373 | int tries[ATA_MAX_DEVICES]; |
| 1374 | int i, rc, down_xfermask; | ||
| 1374 | struct ata_device *dev; | 1375 | struct ata_device *dev; |
| 1375 | 1376 | ||
| 1376 | ata_port_probe(ap); | 1377 | ata_port_probe(ap); |
| 1377 | 1378 | ||
| 1379 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
| 1380 | tries[i] = ATA_PROBE_MAX_TRIES; | ||
| 1381 | |||
| 1382 | retry: | ||
| 1383 | down_xfermask = 0; | ||
| 1384 | |||
| 1378 | /* reset and determine device classes */ | 1385 | /* reset and determine device classes */ |
| 1379 | for (i = 0; i < ATA_MAX_DEVICES; i++) | 1386 | for (i = 0; i < ATA_MAX_DEVICES; i++) |
| 1380 | classes[i] = ATA_DEV_UNKNOWN; | 1387 | classes[i] = ATA_DEV_UNKNOWN; |
| @@ -1404,21 +1411,23 @@ static int ata_bus_probe(struct ata_port *ap) | |||
| 1404 | dev = &ap->device[i]; | 1411 | dev = &ap->device[i]; |
| 1405 | dev->class = classes[i]; | 1412 | dev->class = classes[i]; |
| 1406 | 1413 | ||
| 1407 | if (!ata_dev_enabled(dev)) | 1414 | if (!tries[i]) { |
| 1408 | continue; | 1415 | ata_down_xfermask_limit(ap, dev, 1); |
| 1409 | 1416 | ata_dev_disable(ap, dev); | |
| 1410 | WARN_ON(dev->id != NULL); | ||
| 1411 | if (ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id)) { | ||
| 1412 | dev->class = ATA_DEV_NONE; | ||
| 1413 | continue; | ||
| 1414 | } | 1417 | } |
| 1415 | 1418 | ||
| 1416 | if (ata_dev_configure(ap, dev, 1)) { | 1419 | if (!ata_dev_enabled(dev)) |
| 1417 | ata_dev_disable(ap, dev); | ||
| 1418 | continue; | 1420 | continue; |
| 1419 | } | ||
| 1420 | 1421 | ||
| 1421 | found = 1; | 1422 | kfree(dev->id); |
| 1423 | dev->id = NULL; | ||
| 1424 | rc = ata_dev_read_id(ap, dev, &dev->class, 1, &dev->id); | ||
| 1425 | if (rc) | ||
| 1426 | goto fail; | ||
| 1427 | |||
| 1428 | rc = ata_dev_configure(ap, dev, 1); | ||
| 1429 | if (rc) | ||
| 1430 | goto fail; | ||
| 1422 | } | 1431 | } |
| 1423 | 1432 | ||
| 1424 | /* configure transfer mode */ | 1433 | /* configure transfer mode */ |
| @@ -1427,12 +1436,18 @@ static int ata_bus_probe(struct ata_port *ap) | |||
| 1427 | * return error code and failing device on failure as | 1436 | * return error code and failing device on failure as |
| 1428 | * ata_set_mode() does. | 1437 | * ata_set_mode() does. |
| 1429 | */ | 1438 | */ |
| 1430 | if (found) | 1439 | for (i = 0; i < ATA_MAX_DEVICES; i++) |
| 1431 | ap->ops->set_mode(ap); | 1440 | if (ata_dev_enabled(&ap->device[i])) { |
| 1441 | ap->ops->set_mode(ap); | ||
| 1442 | break; | ||
| 1443 | } | ||
| 1432 | rc = 0; | 1444 | rc = 0; |
| 1433 | } else { | 1445 | } else { |
| 1434 | while (ata_set_mode(ap, &dev)) | 1446 | rc = ata_set_mode(ap, &dev); |
| 1435 | ata_dev_disable(ap, dev); | 1447 | if (rc) { |
| 1448 | down_xfermask = 1; | ||
| 1449 | goto fail; | ||
| 1450 | } | ||
| 1436 | } | 1451 | } |
| 1437 | 1452 | ||
| 1438 | for (i = 0; i < ATA_MAX_DEVICES; i++) | 1453 | for (i = 0; i < ATA_MAX_DEVICES; i++) |
| @@ -1443,6 +1458,24 @@ static int ata_bus_probe(struct ata_port *ap) | |||
| 1443 | ata_port_disable(ap); | 1458 | ata_port_disable(ap); |
| 1444 | ap->ops->port_disable(ap); | 1459 | ap->ops->port_disable(ap); |
| 1445 | return -ENODEV; | 1460 | return -ENODEV; |
| 1461 | |||
| 1462 | fail: | ||
| 1463 | switch (rc) { | ||
| 1464 | case -EINVAL: | ||
| 1465 | case -ENODEV: | ||
| 1466 | tries[dev->devno] = 0; | ||
| 1467 | break; | ||
| 1468 | case -EIO: | ||
| 1469 | ata_down_sata_spd_limit(ap); | ||
| 1470 | /* fall through */ | ||
| 1471 | default: | ||
| 1472 | tries[dev->devno]--; | ||
| 1473 | if (down_xfermask && | ||
| 1474 | ata_down_xfermask_limit(ap, dev, tries[dev->devno] == 1)) | ||
| 1475 | tries[dev->devno] = 0; | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | goto retry; | ||
| 1446 | } | 1479 | } |
| 1447 | 1480 | ||
| 1448 | /** | 1481 | /** |
diff --git a/include/linux/libata.h b/include/linux/libata.h index a5207e66ca52..a4a1e6304e78 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -211,6 +211,9 @@ enum { | |||
| 211 | /* Masks for port functions */ | 211 | /* Masks for port functions */ |
| 212 | ATA_PORT_PRIMARY = (1 << 0), | 212 | ATA_PORT_PRIMARY = (1 << 0), |
| 213 | ATA_PORT_SECONDARY = (1 << 1), | 213 | ATA_PORT_SECONDARY = (1 << 1), |
| 214 | |||
| 215 | /* how hard are we gonna try to probe/recover devices */ | ||
| 216 | ATA_PROBE_MAX_TRIES = 3, | ||
| 214 | }; | 217 | }; |
| 215 | 218 | ||
| 216 | enum hsm_task_states { | 219 | enum hsm_task_states { |
