diff options
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r-- | drivers/scsi/libata-eh.c | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 9173d8f2ce5d..0e66f140e53b 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -1318,20 +1318,58 @@ static void ata_eh_report(struct ata_port *ap) | |||
1318 | } | 1318 | } |
1319 | } | 1319 | } |
1320 | 1320 | ||
1321 | static int ata_eh_reset(struct ata_port *ap, ata_reset_fn_t softreset, | 1321 | static int ata_eh_reset(struct ata_port *ap, |
1322 | ata_prereset_fn_t prereset, ata_reset_fn_t softreset, | ||
1322 | ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) | 1323 | ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) |
1323 | { | 1324 | { |
1324 | struct ata_eh_context *ehc = &ap->eh_context; | 1325 | struct ata_eh_context *ehc = &ap->eh_context; |
1325 | unsigned int classes[ATA_MAX_DEVICES]; | 1326 | unsigned int classes[ATA_MAX_DEVICES]; |
1326 | int tries = ATA_EH_RESET_TRIES; | 1327 | int tries = ATA_EH_RESET_TRIES; |
1328 | unsigned int action; | ||
1327 | ata_reset_fn_t reset; | 1329 | ata_reset_fn_t reset; |
1328 | int i, rc; | 1330 | int i, rc; |
1329 | 1331 | ||
1332 | /* Determine which reset to use and record in ehc->i.action. | ||
1333 | * prereset() may examine and modify it. | ||
1334 | */ | ||
1335 | action = ehc->i.action; | ||
1336 | ehc->i.action &= ~ATA_EH_RESET_MASK; | ||
1330 | if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && | 1337 | if (softreset && (!hardreset || (!sata_set_spd_needed(ap) && |
1331 | !(ehc->i.action & ATA_EH_HARDRESET)))) | 1338 | !(action & ATA_EH_HARDRESET)))) |
1332 | reset = softreset; | 1339 | ehc->i.action |= ATA_EH_SOFTRESET; |
1333 | else | 1340 | else |
1341 | ehc->i.action |= ATA_EH_HARDRESET; | ||
1342 | |||
1343 | if (prereset) { | ||
1344 | rc = prereset(ap); | ||
1345 | if (rc) { | ||
1346 | ata_port_printk(ap, KERN_ERR, | ||
1347 | "prereset failed (errno=%d)\n", rc); | ||
1348 | return rc; | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | /* prereset() might have modified ehc->i.action */ | ||
1353 | if (ehc->i.action & ATA_EH_HARDRESET) | ||
1334 | reset = hardreset; | 1354 | reset = hardreset; |
1355 | else if (ehc->i.action & ATA_EH_SOFTRESET) | ||
1356 | reset = softreset; | ||
1357 | else { | ||
1358 | /* prereset told us not to reset, bang classes and return */ | ||
1359 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
1360 | classes[i] = ATA_DEV_NONE; | ||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | /* did prereset() screw up? if so, fix up to avoid oopsing */ | ||
1365 | if (!reset) { | ||
1366 | ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested " | ||
1367 | "invalid reset type\n"); | ||
1368 | if (softreset) | ||
1369 | reset = softreset; | ||
1370 | else | ||
1371 | reset = hardreset; | ||
1372 | } | ||
1335 | 1373 | ||
1336 | retry: | 1374 | retry: |
1337 | ata_port_printk(ap, KERN_INFO, "%s resetting port\n", | 1375 | ata_port_printk(ap, KERN_INFO, "%s resetting port\n", |
@@ -1424,6 +1462,7 @@ static int ata_port_nr_enabled(struct ata_port *ap) | |||
1424 | /** | 1462 | /** |
1425 | * ata_eh_recover - recover host port after error | 1463 | * ata_eh_recover - recover host port after error |
1426 | * @ap: host port to recover | 1464 | * @ap: host port to recover |
1465 | * @prereset: prereset method (can be NULL) | ||
1427 | * @softreset: softreset method (can be NULL) | 1466 | * @softreset: softreset method (can be NULL) |
1428 | * @hardreset: hardreset method (can be NULL) | 1467 | * @hardreset: hardreset method (can be NULL) |
1429 | * @postreset: postreset method (can be NULL) | 1468 | * @postreset: postreset method (can be NULL) |
@@ -1440,8 +1479,8 @@ static int ata_port_nr_enabled(struct ata_port *ap) | |||
1440 | * RETURNS: | 1479 | * RETURNS: |
1441 | * 0 on success, -errno on failure. | 1480 | * 0 on success, -errno on failure. |
1442 | */ | 1481 | */ |
1443 | static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset, | 1482 | static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, |
1444 | ata_reset_fn_t hardreset, | 1483 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, |
1445 | ata_postreset_fn_t postreset) | 1484 | ata_postreset_fn_t postreset) |
1446 | { | 1485 | { |
1447 | struct ata_eh_context *ehc = &ap->eh_context; | 1486 | struct ata_eh_context *ehc = &ap->eh_context; |
@@ -1469,7 +1508,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset, | |||
1469 | if (ehc->i.action & ATA_EH_RESET_MASK) { | 1508 | if (ehc->i.action & ATA_EH_RESET_MASK) { |
1470 | ata_eh_freeze_port(ap); | 1509 | ata_eh_freeze_port(ap); |
1471 | 1510 | ||
1472 | rc = ata_eh_reset(ap, softreset, hardreset, postreset); | 1511 | rc = ata_eh_reset(ap, prereset, softreset, hardreset, |
1512 | postreset); | ||
1473 | if (rc) { | 1513 | if (rc) { |
1474 | ata_port_printk(ap, KERN_ERR, | 1514 | ata_port_printk(ap, KERN_ERR, |
1475 | "reset failed, giving up\n"); | 1515 | "reset failed, giving up\n"); |
@@ -1586,6 +1626,7 @@ static void ata_eh_finish(struct ata_port *ap) | |||
1586 | /** | 1626 | /** |
1587 | * ata_do_eh - do standard error handling | 1627 | * ata_do_eh - do standard error handling |
1588 | * @ap: host port to handle error for | 1628 | * @ap: host port to handle error for |
1629 | * @prereset: prereset method (can be NULL) | ||
1589 | * @softreset: softreset method (can be NULL) | 1630 | * @softreset: softreset method (can be NULL) |
1590 | * @hardreset: hardreset method (can be NULL) | 1631 | * @hardreset: hardreset method (can be NULL) |
1591 | * @postreset: postreset method (can be NULL) | 1632 | * @postreset: postreset method (can be NULL) |
@@ -1595,11 +1636,12 @@ static void ata_eh_finish(struct ata_port *ap) | |||
1595 | * LOCKING: | 1636 | * LOCKING: |
1596 | * Kernel thread context (may sleep). | 1637 | * Kernel thread context (may sleep). |
1597 | */ | 1638 | */ |
1598 | void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset, | 1639 | void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, |
1599 | ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) | 1640 | ata_reset_fn_t softreset, ata_reset_fn_t hardreset, |
1641 | ata_postreset_fn_t postreset) | ||
1600 | { | 1642 | { |
1601 | ata_eh_autopsy(ap); | 1643 | ata_eh_autopsy(ap); |
1602 | ata_eh_report(ap); | 1644 | ata_eh_report(ap); |
1603 | ata_eh_recover(ap, softreset, hardreset, postreset); | 1645 | ata_eh_recover(ap, prereset, softreset, hardreset, postreset); |
1604 | ata_eh_finish(ap); | 1646 | ata_eh_finish(ap); |
1605 | } | 1647 | } |