diff options
| -rw-r--r-- | drivers/scsi/libata-eh.c | 85 | ||||
| -rw-r--r-- | include/linux/libata.h | 2 |
2 files changed, 71 insertions, 16 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 531a4e11c078..70b623988a9f 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
| @@ -706,9 +706,35 @@ static void ata_eh_detach_dev(struct ata_device *dev) | |||
| 706 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | 706 | spin_unlock_irqrestore(&ap->host_set->lock, flags); |
| 707 | } | 707 | } |
| 708 | 708 | ||
| 709 | static void ata_eh_clear_action(struct ata_device *dev, | ||
| 710 | struct ata_eh_info *ehi, unsigned int action) | ||
| 711 | { | ||
| 712 | int i; | ||
| 713 | |||
| 714 | if (!dev) { | ||
| 715 | ehi->action &= ~action; | ||
| 716 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
| 717 | ehi->dev_action[i] &= ~action; | ||
| 718 | } else { | ||
| 719 | /* doesn't make sense for port-wide EH actions */ | ||
| 720 | WARN_ON(!(action & ATA_EH_PERDEV_MASK)); | ||
| 721 | |||
| 722 | /* break ehi->action into ehi->dev_action */ | ||
| 723 | if (ehi->action & action) { | ||
| 724 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
| 725 | ehi->dev_action[i] |= ehi->action & action; | ||
| 726 | ehi->action &= ~action; | ||
| 727 | } | ||
| 728 | |||
| 729 | /* turn off the specified per-dev action */ | ||
| 730 | ehi->dev_action[dev->devno] &= ~action; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| 709 | /** | 734 | /** |
| 710 | * ata_eh_about_to_do - about to perform eh_action | 735 | * ata_eh_about_to_do - about to perform eh_action |
| 711 | * @ap: target ATA port | 736 | * @ap: target ATA port |
| 737 | * @dev: target ATA dev for per-dev action (can be NULL) | ||
| 712 | * @action: action about to be performed | 738 | * @action: action about to be performed |
| 713 | * | 739 | * |
| 714 | * Called just before performing EH actions to clear related bits | 740 | * Called just before performing EH actions to clear related bits |
| @@ -718,17 +744,36 @@ static void ata_eh_detach_dev(struct ata_device *dev) | |||
| 718 | * LOCKING: | 744 | * LOCKING: |
| 719 | * None. | 745 | * None. |
| 720 | */ | 746 | */ |
| 721 | static void ata_eh_about_to_do(struct ata_port *ap, unsigned int action) | 747 | static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, |
| 748 | unsigned int action) | ||
| 722 | { | 749 | { |
| 723 | unsigned long flags; | 750 | unsigned long flags; |
| 724 | 751 | ||
| 725 | spin_lock_irqsave(&ap->host_set->lock, flags); | 752 | spin_lock_irqsave(&ap->host_set->lock, flags); |
| 726 | ap->eh_info.action &= ~action; | 753 | ata_eh_clear_action(dev, &ap->eh_info, action); |
| 727 | ap->flags |= ATA_FLAG_RECOVERED; | 754 | ap->flags |= ATA_FLAG_RECOVERED; |
| 728 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | 755 | spin_unlock_irqrestore(&ap->host_set->lock, flags); |
| 729 | } | 756 | } |
| 730 | 757 | ||
| 731 | /** | 758 | /** |
| 759 | * ata_eh_done - EH action complete | ||
| 760 | * @ap: target ATA port | ||
| 761 | * @dev: target ATA dev for per-dev action (can be NULL) | ||
| 762 | * @action: action just completed | ||
| 763 | * | ||
| 764 | * Called right after performing EH actions to clear related bits | ||
| 765 | * in @ap->eh_context. | ||
| 766 | * | ||
| 767 | * LOCKING: | ||
| 768 | * None. | ||
| 769 | */ | ||
| 770 | static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, | ||
| 771 | unsigned int action) | ||
| 772 | { | ||
| 773 | ata_eh_clear_action(dev, &ap->eh_context.i, action); | ||
| 774 | } | ||
| 775 | |||
| 776 | /** | ||
| 732 | * ata_err_string - convert err_mask to descriptive string | 777 | * ata_err_string - convert err_mask to descriptive string |
| 733 | * @err_mask: error mask to convert to string | 778 | * @err_mask: error mask to convert to string |
| 734 | * | 779 | * |
| @@ -1271,10 +1316,6 @@ static void ata_eh_autopsy(struct ata_port *ap) | |||
| 1271 | is_io = 1; | 1316 | is_io = 1; |
| 1272 | } | 1317 | } |
| 1273 | 1318 | ||
| 1274 | /* speed down iff command was in progress */ | ||
| 1275 | if (failed_dev) | ||
| 1276 | action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); | ||
| 1277 | |||
| 1278 | /* enforce default EH actions */ | 1319 | /* enforce default EH actions */ |
| 1279 | if (ap->flags & ATA_FLAG_FROZEN || | 1320 | if (ap->flags & ATA_FLAG_FROZEN || |
| 1280 | all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) | 1321 | all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) |
| @@ -1282,6 +1323,17 @@ static void ata_eh_autopsy(struct ata_port *ap) | |||
| 1282 | else if (all_err_mask) | 1323 | else if (all_err_mask) |
| 1283 | action |= ATA_EH_REVALIDATE; | 1324 | action |= ATA_EH_REVALIDATE; |
| 1284 | 1325 | ||
| 1326 | /* if we have offending qcs and the associated failed device */ | ||
| 1327 | if (failed_dev) { | ||
| 1328 | /* speed down */ | ||
| 1329 | action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); | ||
| 1330 | |||
| 1331 | /* perform per-dev EH action only on the offending device */ | ||
| 1332 | ehc->i.dev_action[failed_dev->devno] |= | ||
| 1333 | action & ATA_EH_PERDEV_MASK; | ||
| 1334 | action &= ~ATA_EH_PERDEV_MASK; | ||
| 1335 | } | ||
| 1336 | |||
| 1285 | /* record autopsy result */ | 1337 | /* record autopsy result */ |
| 1286 | ehc->i.dev = failed_dev; | 1338 | ehc->i.dev = failed_dev; |
| 1287 | ehc->i.action = action; | 1339 | ehc->i.action = action; |
| @@ -1457,7 +1509,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
| 1457 | reset == softreset ? "soft" : "hard"); | 1509 | reset == softreset ? "soft" : "hard"); |
| 1458 | 1510 | ||
| 1459 | /* reset */ | 1511 | /* reset */ |
| 1460 | ata_eh_about_to_do(ap, ATA_EH_RESET_MASK); | 1512 | ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); |
| 1461 | ehc->i.flags |= ATA_EHI_DID_RESET; | 1513 | ehc->i.flags |= ATA_EHI_DID_RESET; |
| 1462 | 1514 | ||
| 1463 | rc = ata_do_reset(ap, reset, classes); | 1515 | rc = ata_do_reset(ap, reset, classes); |
| @@ -1476,7 +1528,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
| 1476 | return -EINVAL; | 1528 | return -EINVAL; |
| 1477 | } | 1529 | } |
| 1478 | 1530 | ||
| 1479 | ata_eh_about_to_do(ap, ATA_EH_RESET_MASK); | 1531 | ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); |
| 1480 | rc = ata_do_reset(ap, reset, classes); | 1532 | rc = ata_do_reset(ap, reset, classes); |
| 1481 | 1533 | ||
| 1482 | if (rc == 0 && classify && | 1534 | if (rc == 0 && classify && |
| @@ -1520,8 +1572,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
| 1520 | postreset(ap, classes); | 1572 | postreset(ap, classes); |
| 1521 | 1573 | ||
| 1522 | /* reset successful, schedule revalidation */ | 1574 | /* reset successful, schedule revalidation */ |
| 1523 | ehc->i.dev = NULL; | 1575 | ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); |
| 1524 | ehc->i.action &= ~ATA_EH_RESET_MASK; | ||
| 1525 | ehc->i.action |= ATA_EH_REVALIDATE; | 1576 | ehc->i.action |= ATA_EH_REVALIDATE; |
| 1526 | } | 1577 | } |
| 1527 | 1578 | ||
| @@ -1539,21 +1590,25 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
| 1539 | DPRINTK("ENTER\n"); | 1590 | DPRINTK("ENTER\n"); |
| 1540 | 1591 | ||
| 1541 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | 1592 | for (i = 0; i < ATA_MAX_DEVICES; i++) { |
| 1593 | unsigned int action; | ||
| 1594 | |||
| 1542 | dev = &ap->device[i]; | 1595 | dev = &ap->device[i]; |
| 1596 | action = ehc->i.action | ehc->i.dev_action[dev->devno]; | ||
| 1543 | 1597 | ||
| 1544 | if (ehc->i.action & ATA_EH_REVALIDATE && ata_dev_enabled(dev) && | 1598 | if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) { |
| 1545 | (!ehc->i.dev || ehc->i.dev == dev)) { | ||
| 1546 | if (ata_port_offline(ap)) { | 1599 | if (ata_port_offline(ap)) { |
| 1547 | rc = -EIO; | 1600 | rc = -EIO; |
| 1548 | break; | 1601 | break; |
| 1549 | } | 1602 | } |
| 1550 | 1603 | ||
| 1551 | ata_eh_about_to_do(ap, ATA_EH_REVALIDATE); | 1604 | ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE); |
| 1552 | rc = ata_dev_revalidate(dev, | 1605 | rc = ata_dev_revalidate(dev, |
| 1553 | ehc->i.flags & ATA_EHI_DID_RESET); | 1606 | ehc->i.flags & ATA_EHI_DID_RESET); |
| 1554 | if (rc) | 1607 | if (rc) |
| 1555 | break; | 1608 | break; |
| 1556 | 1609 | ||
| 1610 | ata_eh_done(ap, dev, ATA_EH_REVALIDATE); | ||
| 1611 | |||
| 1557 | /* schedule the scsi_rescan_device() here */ | 1612 | /* schedule the scsi_rescan_device() here */ |
| 1558 | queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); | 1613 | queue_work(ata_aux_wq, &(ap->scsi_rescan_task)); |
| 1559 | } else if (dev->class == ATA_DEV_UNKNOWN && | 1614 | } else if (dev->class == ATA_DEV_UNKNOWN && |
| @@ -1576,9 +1631,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
| 1576 | } | 1631 | } |
| 1577 | } | 1632 | } |
| 1578 | 1633 | ||
| 1579 | if (rc == 0) | 1634 | if (rc) |
| 1580 | ehc->i.action &= ~ATA_EH_REVALIDATE; | ||
| 1581 | else | ||
| 1582 | *r_failed_dev = dev; | 1635 | *r_failed_dev = dev; |
| 1583 | 1636 | ||
| 1584 | DPRINTK("EXIT\n"); | 1637 | DPRINTK("EXIT\n"); |
diff --git a/include/linux/libata.h b/include/linux/libata.h index f03b8664af11..6b3c3af2c75f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -249,6 +249,7 @@ enum { | |||
| 249 | ATA_EH_HARDRESET = (1 << 2), | 249 | ATA_EH_HARDRESET = (1 << 2), |
| 250 | 250 | ||
| 251 | ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, | 251 | ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, |
| 252 | ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, | ||
| 252 | 253 | ||
| 253 | /* ata_eh_info->flags */ | 254 | /* ata_eh_info->flags */ |
| 254 | ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ | 255 | ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ |
| @@ -462,6 +463,7 @@ struct ata_eh_info { | |||
| 462 | u32 serror; /* SError from LLDD */ | 463 | u32 serror; /* SError from LLDD */ |
| 463 | unsigned int err_mask; /* port-wide err_mask */ | 464 | unsigned int err_mask; /* port-wide err_mask */ |
| 464 | unsigned int action; /* ATA_EH_* action mask */ | 465 | unsigned int action; /* ATA_EH_* action mask */ |
| 466 | unsigned int dev_action[ATA_MAX_DEVICES]; /* dev EH action */ | ||
| 465 | unsigned int flags; /* ATA_EHI_* flags */ | 467 | unsigned int flags; /* ATA_EHI_* flags */ |
| 466 | 468 | ||
| 467 | unsigned long hotplug_timestamp; | 469 | unsigned long hotplug_timestamp; |
