diff options
| -rw-r--r-- | drivers/scsi/libata-eh.c | 123 | ||||
| -rw-r--r-- | include/linux/libata.h | 13 |
2 files changed, 115 insertions, 21 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index a049bffdf770..b53e2e7db498 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
| @@ -932,10 +932,8 @@ static void ata_eh_analyze_serror(struct ata_port *ap) | |||
| 932 | err_mask |= AC_ERR_SYSTEM; | 932 | err_mask |= AC_ERR_SYSTEM; |
| 933 | action |= ATA_EH_SOFTRESET; | 933 | action |= ATA_EH_SOFTRESET; |
| 934 | } | 934 | } |
| 935 | if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) { | 935 | if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) |
| 936 | err_mask |= AC_ERR_ATA_BUS; | 936 | ata_ehi_hotplugged(&ehc->i); |
| 937 | action |= ATA_EH_HARDRESET; | ||
| 938 | } | ||
| 939 | 937 | ||
| 940 | ehc->i.err_mask |= err_mask; | 938 | ehc->i.err_mask |= err_mask; |
| 941 | ehc->i.action |= action; | 939 | ehc->i.action |= action; |
| @@ -1487,11 +1485,12 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
| 1487 | return rc; | 1485 | return rc; |
| 1488 | } | 1486 | } |
| 1489 | 1487 | ||
| 1490 | static int ata_eh_revalidate(struct ata_port *ap, | 1488 | static int ata_eh_revalidate_and_attach(struct ata_port *ap, |
| 1491 | struct ata_device **r_failed_dev) | 1489 | struct ata_device **r_failed_dev) |
| 1492 | { | 1490 | { |
| 1493 | struct ata_eh_context *ehc = &ap->eh_context; | 1491 | struct ata_eh_context *ehc = &ap->eh_context; |
| 1494 | struct ata_device *dev; | 1492 | struct ata_device *dev; |
| 1493 | unsigned long flags; | ||
| 1495 | int i, rc = 0; | 1494 | int i, rc = 0; |
| 1496 | 1495 | ||
| 1497 | DPRINTK("ENTER\n"); | 1496 | DPRINTK("ENTER\n"); |
| @@ -1513,6 +1512,23 @@ static int ata_eh_revalidate(struct ata_port *ap, | |||
| 1513 | break; | 1512 | break; |
| 1514 | 1513 | ||
| 1515 | ehc->i.action &= ~ATA_EH_REVALIDATE; | 1514 | ehc->i.action &= ~ATA_EH_REVALIDATE; |
| 1515 | } else if (dev->class == ATA_DEV_UNKNOWN && | ||
| 1516 | ehc->tries[dev->devno] && | ||
| 1517 | ata_class_enabled(ehc->classes[dev->devno])) { | ||
| 1518 | dev->class = ehc->classes[dev->devno]; | ||
| 1519 | |||
| 1520 | rc = ata_dev_read_id(dev, &dev->class, 1, dev->id); | ||
| 1521 | if (rc == 0) | ||
| 1522 | rc = ata_dev_configure(dev, 1); | ||
| 1523 | |||
| 1524 | if (rc) { | ||
| 1525 | dev->class = ATA_DEV_UNKNOWN; | ||
| 1526 | break; | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
| 1530 | ap->flags |= ATA_FLAG_SCSI_HOTPLUG; | ||
| 1531 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
| 1516 | } | 1532 | } |
| 1517 | } | 1533 | } |
| 1518 | 1534 | ||
| @@ -1533,6 +1549,36 @@ static int ata_port_nr_enabled(struct ata_port *ap) | |||
| 1533 | return cnt; | 1549 | return cnt; |
| 1534 | } | 1550 | } |
| 1535 | 1551 | ||
| 1552 | static int ata_port_nr_vacant(struct ata_port *ap) | ||
| 1553 | { | ||
| 1554 | int i, cnt = 0; | ||
| 1555 | |||
| 1556 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
| 1557 | if (ap->device[i].class == ATA_DEV_UNKNOWN) | ||
| 1558 | cnt++; | ||
| 1559 | return cnt; | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | static int ata_eh_skip_recovery(struct ata_port *ap) | ||
| 1563 | { | ||
| 1564 | struct ata_eh_context *ehc = &ap->eh_context; | ||
| 1565 | int i; | ||
| 1566 | |||
| 1567 | if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap)) | ||
| 1568 | return 0; | ||
| 1569 | |||
| 1570 | /* skip if class codes for all vacant slots are ATA_DEV_NONE */ | ||
| 1571 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
| 1572 | struct ata_device *dev = &ap->device[i]; | ||
| 1573 | |||
| 1574 | if (dev->class == ATA_DEV_UNKNOWN && | ||
| 1575 | ehc->classes[dev->devno] != ATA_DEV_NONE) | ||
| 1576 | return 0; | ||
| 1577 | } | ||
| 1578 | |||
| 1579 | return 1; | ||
| 1580 | } | ||
| 1581 | |||
| 1536 | /** | 1582 | /** |
| 1537 | * ata_eh_recover - recover host port after error | 1583 | * ata_eh_recover - recover host port after error |
| 1538 | * @ap: host port to recover | 1584 | * @ap: host port to recover |
| @@ -1543,9 +1589,10 @@ static int ata_port_nr_enabled(struct ata_port *ap) | |||
| 1543 | * | 1589 | * |
| 1544 | * This is the alpha and omega, eum and yang, heart and soul of | 1590 | * This is the alpha and omega, eum and yang, heart and soul of |
| 1545 | * libata exception handling. On entry, actions required to | 1591 | * libata exception handling. On entry, actions required to |
| 1546 | * recover each devices are recorded in eh_context. This | 1592 | * recover the port and hotplug requests are recorded in |
| 1547 | * function executes all the operations with appropriate retrials | 1593 | * eh_context. This function executes all the operations with |
| 1548 | * and fallbacks to resurrect failed devices. | 1594 | * appropriate retrials and fallbacks to resurrect failed |
| 1595 | * devices, detach goners and greet newcomers. | ||
| 1549 | * | 1596 | * |
| 1550 | * LOCKING: | 1597 | * LOCKING: |
| 1551 | * Kernel thread context (may sleep). | 1598 | * Kernel thread context (may sleep). |
| @@ -1568,6 +1615,19 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1568 | dev = &ap->device[i]; | 1615 | dev = &ap->device[i]; |
| 1569 | 1616 | ||
| 1570 | ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; | 1617 | ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; |
| 1618 | |||
| 1619 | /* process hotplug request */ | ||
| 1620 | if (dev->flags & ATA_DFLAG_DETACH) | ||
| 1621 | ata_eh_detach_dev(dev); | ||
| 1622 | |||
| 1623 | if (!ata_dev_enabled(dev) && | ||
| 1624 | ((ehc->i.probe_mask & (1 << dev->devno)) && | ||
| 1625 | !(ehc->did_probe_mask & (1 << dev->devno)))) { | ||
| 1626 | ata_eh_detach_dev(dev); | ||
| 1627 | ata_dev_init(dev); | ||
| 1628 | ehc->did_probe_mask |= (1 << dev->devno); | ||
| 1629 | ehc->i.action |= ATA_EH_SOFTRESET; | ||
| 1630 | } | ||
| 1571 | } | 1631 | } |
| 1572 | 1632 | ||
| 1573 | retry: | 1633 | retry: |
| @@ -1575,15 +1635,18 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1575 | rc = 0; | 1635 | rc = 0; |
| 1576 | 1636 | ||
| 1577 | /* skip EH if possible. */ | 1637 | /* skip EH if possible. */ |
| 1578 | if (!ata_port_nr_enabled(ap) && !(ap->flags & ATA_FLAG_FROZEN)) | 1638 | if (ata_eh_skip_recovery(ap)) |
| 1579 | ehc->i.action = 0; | 1639 | ehc->i.action = 0; |
| 1580 | 1640 | ||
| 1641 | for (i = 0; i < ATA_MAX_DEVICES; i++) | ||
| 1642 | ehc->classes[i] = ATA_DEV_UNKNOWN; | ||
| 1643 | |||
| 1581 | /* reset */ | 1644 | /* reset */ |
| 1582 | if (ehc->i.action & ATA_EH_RESET_MASK) { | 1645 | if (ehc->i.action & ATA_EH_RESET_MASK) { |
| 1583 | ata_eh_freeze_port(ap); | 1646 | ata_eh_freeze_port(ap); |
| 1584 | 1647 | ||
| 1585 | rc = ata_eh_reset(ap, 0, prereset, softreset, hardreset, | 1648 | rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset, |
| 1586 | postreset); | 1649 | softreset, hardreset, postreset); |
| 1587 | if (rc) { | 1650 | if (rc) { |
| 1588 | ata_port_printk(ap, KERN_ERR, | 1651 | ata_port_printk(ap, KERN_ERR, |
| 1589 | "reset failed, giving up\n"); | 1652 | "reset failed, giving up\n"); |
| @@ -1593,8 +1656,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1593 | ata_eh_thaw_port(ap); | 1656 | ata_eh_thaw_port(ap); |
| 1594 | } | 1657 | } |
| 1595 | 1658 | ||
| 1596 | /* revalidate existing devices */ | 1659 | /* revalidate existing devices and attach new ones */ |
| 1597 | rc = ata_eh_revalidate(ap, &dev); | 1660 | rc = ata_eh_revalidate_and_attach(ap, &dev); |
| 1598 | if (rc) | 1661 | if (rc) |
| 1599 | goto dev_fail; | 1662 | goto dev_fail; |
| 1600 | 1663 | ||
| @@ -1612,6 +1675,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1612 | dev_fail: | 1675 | dev_fail: |
| 1613 | switch (rc) { | 1676 | switch (rc) { |
| 1614 | case -ENODEV: | 1677 | case -ENODEV: |
| 1678 | /* device missing, schedule probing */ | ||
| 1679 | ehc->i.probe_mask |= (1 << dev->devno); | ||
| 1615 | case -EINVAL: | 1680 | case -EINVAL: |
| 1616 | ehc->tries[dev->devno] = 0; | 1681 | ehc->tries[dev->devno] = 0; |
| 1617 | break; | 1682 | break; |
| @@ -1624,15 +1689,31 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1624 | ehc->tries[dev->devno] = 0; | 1689 | ehc->tries[dev->devno] = 0; |
| 1625 | } | 1690 | } |
| 1626 | 1691 | ||
| 1627 | /* disable device if it has used up all its chances */ | 1692 | if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) { |
| 1628 | if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) | 1693 | /* disable device if it has used up all its chances */ |
| 1629 | ata_dev_disable(dev); | 1694 | ata_dev_disable(dev); |
| 1630 | 1695 | ||
| 1631 | /* soft didn't work? be haaaaard */ | 1696 | /* detach if offline */ |
| 1632 | if (ehc->i.flags & ATA_EHI_DID_RESET) | 1697 | if (ata_port_offline(ap)) |
| 1633 | ehc->i.action |= ATA_EH_HARDRESET; | 1698 | ata_eh_detach_dev(dev); |
| 1634 | else | 1699 | |
| 1635 | ehc->i.action |= ATA_EH_SOFTRESET; | 1700 | /* probe if requested */ |
| 1701 | if ((ehc->i.probe_mask & (1 << dev->devno)) && | ||
| 1702 | !(ehc->did_probe_mask & (1 << dev->devno))) { | ||
| 1703 | ata_eh_detach_dev(dev); | ||
| 1704 | ata_dev_init(dev); | ||
| 1705 | |||
| 1706 | ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; | ||
| 1707 | ehc->did_probe_mask |= (1 << dev->devno); | ||
| 1708 | ehc->i.action |= ATA_EH_SOFTRESET; | ||
| 1709 | } | ||
| 1710 | } else { | ||
| 1711 | /* soft didn't work? be haaaaard */ | ||
| 1712 | if (ehc->i.flags & ATA_EHI_DID_RESET) | ||
| 1713 | ehc->i.action |= ATA_EH_HARDRESET; | ||
| 1714 | else | ||
| 1715 | ehc->i.action |= ATA_EH_SOFTRESET; | ||
| 1716 | } | ||
| 1636 | 1717 | ||
| 1637 | if (ata_port_nr_enabled(ap)) { | 1718 | if (ata_port_nr_enabled(ap)) { |
| 1638 | ata_port_printk(ap, KERN_WARNING, "failed to recover some " | 1719 | ata_port_printk(ap, KERN_WARNING, "failed to recover some " |
diff --git a/include/linux/libata.h b/include/linux/libata.h index a1ceb5b67b97..56971943d261 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -824,6 +824,19 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 824 | (ehi)->desc_len = 0; \ | 824 | (ehi)->desc_len = 0; \ |
| 825 | } while (0) | 825 | } while (0) |
| 826 | 826 | ||
| 827 | static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi) | ||
| 828 | { | ||
| 829 | if (ehi->flags & ATA_EHI_HOTPLUGGED) | ||
| 830 | return; | ||
| 831 | |||
| 832 | ehi->flags |= ATA_EHI_HOTPLUGGED; | ||
| 833 | ehi->hotplug_timestamp = jiffies; | ||
| 834 | |||
| 835 | ehi->err_mask |= AC_ERR_ATA_BUS; | ||
| 836 | ehi->action |= ATA_EH_SOFTRESET; | ||
| 837 | ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1; | ||
| 838 | } | ||
| 839 | |||
| 827 | /* | 840 | /* |
| 828 | * qc helpers | 841 | * qc helpers |
| 829 | */ | 842 | */ |
