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 /drivers | |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/libata-core.c | 65 |
1 files changed, 49 insertions, 16 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 68fa64d2472..33b5bff58cc 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 | /** |