aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-eh.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-31 05:27:50 -0400
committerTejun Heo <htejun@gmail.com>2006-05-31 05:27:50 -0400
commit664faf09a05d74085c0b31e2c621d7647322325b (patch)
tree6506775bb94e7e99f1730f4fd50eb2f3f7359620 /drivers/scsi/libata-eh.c
parentf5914a461eb9703773226a0813f6ffcae10c0861 (diff)
[PATCH] libata-hp-prep: implement followup softreset handling
In some cases, hardreset must be followed by SRST. * some controllers can't classify with hardreset * some controllers can't wait for !BSY after hardreset (LLDD should explicitly request followup softreset by returning -EAGAIN) * (later) PM needs SRST w/ PMP==15 to operate after hardreset To handle above cases, this patch implements follow-up softreset. After a hardreset, ata_eh_reset() checks whether any of above conditions are met and do a follow-up softreset if necessary. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r--drivers/scsi/libata-eh.c58
1 files changed, 52 insertions, 6 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 0e66f140e53..8ecb8424d7b 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1318,16 +1318,28 @@ static void ata_eh_report(struct ata_port *ap)
1318 } 1318 }
1319} 1319}
1320 1320
1321static int ata_eh_reset(struct ata_port *ap, 1321static int ata_eh_followup_srst_needed(int rc, int classify,
1322 const unsigned int *classes)
1323{
1324 if (rc == -EAGAIN)
1325 return 1;
1326 if (rc != 0)
1327 return 0;
1328 if (classify && classes[0] == ATA_DEV_UNKNOWN)
1329 return 1;
1330 return 0;
1331}
1332
1333static int ata_eh_reset(struct ata_port *ap, int classify,
1322 ata_prereset_fn_t prereset, ata_reset_fn_t softreset, 1334 ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
1323 ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) 1335 ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
1324{ 1336{
1325 struct ata_eh_context *ehc = &ap->eh_context; 1337 struct ata_eh_context *ehc = &ap->eh_context;
1326 unsigned int classes[ATA_MAX_DEVICES]; 1338 unsigned int *classes = ehc->classes;
1327 int tries = ATA_EH_RESET_TRIES; 1339 int tries = ATA_EH_RESET_TRIES;
1328 unsigned int action; 1340 unsigned int action;
1329 ata_reset_fn_t reset; 1341 ata_reset_fn_t reset;
1330 int i, rc; 1342 int i, did_followup_srst, rc;
1331 1343
1332 /* Determine which reset to use and record in ehc->i.action. 1344 /* Determine which reset to use and record in ehc->i.action.
1333 * prereset() may examine and modify it. 1345 * prereset() may examine and modify it.
@@ -1381,10 +1393,44 @@ static int ata_eh_reset(struct ata_port *ap,
1381 1393
1382 rc = ata_do_reset(ap, reset, classes); 1394 rc = ata_do_reset(ap, reset, classes);
1383 1395
1396 did_followup_srst = 0;
1397 if (reset == hardreset &&
1398 ata_eh_followup_srst_needed(rc, classify, classes)) {
1399 /* okay, let's do follow-up softreset */
1400 did_followup_srst = 1;
1401 reset = softreset;
1402
1403 if (!reset) {
1404 ata_port_printk(ap, KERN_ERR,
1405 "follow-up softreset required "
1406 "but no softreset avaliable\n");
1407 return -EINVAL;
1408 }
1409
1410 ata_eh_about_to_do(ap, ATA_EH_RESET_MASK);
1411 rc = ata_do_reset(ap, reset, classes);
1412
1413 if (rc == 0 && classify &&
1414 classes[0] == ATA_DEV_UNKNOWN) {
1415 ata_port_printk(ap, KERN_ERR,
1416 "classification failed\n");
1417 return -EINVAL;
1418 }
1419 }
1420
1384 if (rc && --tries) { 1421 if (rc && --tries) {
1422 const char *type;
1423
1424 if (reset == softreset) {
1425 if (did_followup_srst)
1426 type = "follow-up soft";
1427 else
1428 type = "soft";
1429 } else
1430 type = "hard";
1431
1385 ata_port_printk(ap, KERN_WARNING, 1432 ata_port_printk(ap, KERN_WARNING,
1386 "%sreset failed, retrying in 5 secs\n", 1433 "%sreset failed, retrying in 5 secs\n", type);
1387 reset == softreset ? "soft" : "hard");
1388 ssleep(5); 1434 ssleep(5);
1389 1435
1390 if (reset == hardreset) 1436 if (reset == hardreset)
@@ -1508,7 +1554,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
1508 if (ehc->i.action & ATA_EH_RESET_MASK) { 1554 if (ehc->i.action & ATA_EH_RESET_MASK) {
1509 ata_eh_freeze_port(ap); 1555 ata_eh_freeze_port(ap);
1510 1556
1511 rc = ata_eh_reset(ap, prereset, softreset, hardreset, 1557 rc = ata_eh_reset(ap, 0, prereset, softreset, hardreset,
1512 postreset); 1558 postreset);
1513 if (rc) { 1559 if (rc) {
1514 ata_port_printk(ap, KERN_ERR, 1560 ata_port_printk(ap, KERN_ERR,