diff options
| -rw-r--r-- | drivers/scsi/libata-core.c | 5 | ||||
| -rw-r--r-- | drivers/scsi/libata-eh.c | 185 | ||||
| -rw-r--r-- | include/linux/libata.h | 12 |
3 files changed, 198 insertions, 4 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index f368536f8e91..ad5cac79627c 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
| @@ -2146,7 +2146,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) | |||
| 2146 | * return error code and failing device on failure. | 2146 | * return error code and failing device on failure. |
| 2147 | */ | 2147 | */ |
| 2148 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | 2148 | for (i = 0; i < ATA_MAX_DEVICES; i++) { |
| 2149 | if (ata_dev_enabled(&ap->device[i])) { | 2149 | if (ata_dev_ready(&ap->device[i])) { |
| 2150 | ap->ops->set_mode(ap); | 2150 | ap->ops->set_mode(ap); |
| 2151 | break; | 2151 | break; |
| 2152 | } | 2152 | } |
| @@ -2212,7 +2212,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) | |||
| 2212 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | 2212 | for (i = 0; i < ATA_MAX_DEVICES; i++) { |
| 2213 | dev = &ap->device[i]; | 2213 | dev = &ap->device[i]; |
| 2214 | 2214 | ||
| 2215 | if (!ata_dev_enabled(dev)) | 2215 | /* don't udpate suspended devices' xfer mode */ |
| 2216 | if (!ata_dev_ready(dev)) | ||
| 2216 | continue; | 2217 | continue; |
| 2217 | 2218 | ||
| 2218 | rc = ata_dev_set_mode(dev); | 2219 | rc = ata_dev_set_mode(dev); |
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1e9e73d13485..b9df49a36214 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
| @@ -1610,7 +1610,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
| 1610 | dev = &ap->device[i]; | 1610 | dev = &ap->device[i]; |
| 1611 | action = ata_eh_dev_action(dev); | 1611 | action = ata_eh_dev_action(dev); |
| 1612 | 1612 | ||
| 1613 | if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) { | 1613 | if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { |
| 1614 | if (ata_port_offline(ap)) { | 1614 | if (ata_port_offline(ap)) { |
| 1615 | rc = -EIO; | 1615 | rc = -EIO; |
| 1616 | break; | 1616 | break; |
| @@ -1653,6 +1653,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
| 1653 | return rc; | 1653 | return rc; |
| 1654 | } | 1654 | } |
| 1655 | 1655 | ||
| 1656 | /** | ||
| 1657 | * ata_eh_suspend - handle suspend EH action | ||
| 1658 | * @ap: target host port | ||
| 1659 | * @r_failed_dev: result parameter to indicate failing device | ||
| 1660 | * | ||
| 1661 | * Handle suspend EH action. Disk devices are spinned down and | ||
| 1662 | * other types of devices are just marked suspended. Once | ||
| 1663 | * suspended, no EH action to the device is allowed until it is | ||
| 1664 | * resumed. | ||
| 1665 | * | ||
| 1666 | * LOCKING: | ||
| 1667 | * Kernel thread context (may sleep). | ||
| 1668 | * | ||
| 1669 | * RETURNS: | ||
| 1670 | * 0 on success, -errno otherwise | ||
| 1671 | */ | ||
| 1672 | static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
| 1673 | { | ||
| 1674 | struct ata_device *dev; | ||
| 1675 | int i, rc = 0; | ||
| 1676 | |||
| 1677 | DPRINTK("ENTER\n"); | ||
| 1678 | |||
| 1679 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
| 1680 | unsigned long flags; | ||
| 1681 | unsigned int action, err_mask; | ||
| 1682 | |||
| 1683 | dev = &ap->device[i]; | ||
| 1684 | action = ata_eh_dev_action(dev); | ||
| 1685 | |||
| 1686 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND)) | ||
| 1687 | continue; | ||
| 1688 | |||
| 1689 | WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED); | ||
| 1690 | |||
| 1691 | ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND); | ||
| 1692 | |||
| 1693 | if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { | ||
| 1694 | /* flush cache */ | ||
| 1695 | rc = ata_flush_cache(dev); | ||
| 1696 | if (rc) | ||
| 1697 | break; | ||
| 1698 | |||
| 1699 | /* spin down */ | ||
| 1700 | err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); | ||
| 1701 | if (err_mask) { | ||
| 1702 | ata_dev_printk(dev, KERN_ERR, "failed to " | ||
| 1703 | "spin down (err_mask=0x%x)\n", | ||
| 1704 | err_mask); | ||
| 1705 | rc = -EIO; | ||
| 1706 | break; | ||
| 1707 | } | ||
| 1708 | } | ||
| 1709 | |||
| 1710 | spin_lock_irqsave(ap->lock, flags); | ||
| 1711 | dev->flags |= ATA_DFLAG_SUSPENDED; | ||
| 1712 | spin_unlock_irqrestore(ap->lock, flags); | ||
| 1713 | |||
| 1714 | ata_eh_done(ap, dev, ATA_EH_SUSPEND); | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | if (rc) | ||
| 1718 | *r_failed_dev = dev; | ||
| 1719 | |||
| 1720 | DPRINTK("EXIT\n"); | ||
| 1721 | return 0; | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | /** | ||
| 1725 | * ata_eh_prep_resume - prep for resume EH action | ||
| 1726 | * @ap: target host port | ||
| 1727 | * | ||
| 1728 | * Clear SUSPENDED in preparation for scheduled resume actions. | ||
| 1729 | * This allows other parts of EH to access the devices being | ||
| 1730 | * resumed. | ||
| 1731 | * | ||
| 1732 | * LOCKING: | ||
| 1733 | * Kernel thread context (may sleep). | ||
| 1734 | */ | ||
| 1735 | static void ata_eh_prep_resume(struct ata_port *ap) | ||
| 1736 | { | ||
| 1737 | struct ata_device *dev; | ||
| 1738 | unsigned long flags; | ||
| 1739 | int i; | ||
| 1740 | |||
| 1741 | DPRINTK("ENTER\n"); | ||
| 1742 | |||
| 1743 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
| 1744 | unsigned int action; | ||
| 1745 | |||
| 1746 | dev = &ap->device[i]; | ||
| 1747 | action = ata_eh_dev_action(dev); | ||
| 1748 | |||
| 1749 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) | ||
| 1750 | continue; | ||
| 1751 | |||
| 1752 | spin_lock_irqsave(ap->lock, flags); | ||
| 1753 | dev->flags &= ~ATA_DFLAG_SUSPENDED; | ||
| 1754 | spin_unlock_irqrestore(ap->lock, flags); | ||
| 1755 | } | ||
| 1756 | |||
| 1757 | DPRINTK("EXIT\n"); | ||
| 1758 | } | ||
| 1759 | |||
| 1760 | /** | ||
| 1761 | * ata_eh_resume - handle resume EH action | ||
| 1762 | * @ap: target host port | ||
| 1763 | * @r_failed_dev: result parameter to indicate failing device | ||
| 1764 | * | ||
| 1765 | * Handle resume EH action. Target devices are already reset and | ||
| 1766 | * revalidated. Spinning up is the only operation left. | ||
| 1767 | * | ||
| 1768 | * LOCKING: | ||
| 1769 | * Kernel thread context (may sleep). | ||
| 1770 | * | ||
| 1771 | * RETURNS: | ||
| 1772 | * 0 on success, -errno otherwise | ||
| 1773 | */ | ||
| 1774 | static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
| 1775 | { | ||
| 1776 | struct ata_device *dev; | ||
| 1777 | int i, rc = 0; | ||
| 1778 | |||
| 1779 | DPRINTK("ENTER\n"); | ||
| 1780 | |||
| 1781 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
| 1782 | unsigned int action, err_mask; | ||
| 1783 | |||
| 1784 | dev = &ap->device[i]; | ||
| 1785 | action = ata_eh_dev_action(dev); | ||
| 1786 | |||
| 1787 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) | ||
| 1788 | continue; | ||
| 1789 | |||
| 1790 | ata_eh_about_to_do(ap, dev, ATA_EH_RESUME); | ||
| 1791 | |||
| 1792 | if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { | ||
| 1793 | err_mask = ata_do_simple_cmd(dev, | ||
| 1794 | ATA_CMD_IDLEIMMEDIATE); | ||
| 1795 | if (err_mask) { | ||
| 1796 | ata_dev_printk(dev, KERN_ERR, "failed to " | ||
| 1797 | "spin up (err_mask=0x%x)\n", | ||
| 1798 | err_mask); | ||
| 1799 | rc = -EIO; | ||
| 1800 | break; | ||
| 1801 | } | ||
| 1802 | } | ||
| 1803 | |||
| 1804 | ata_eh_done(ap, dev, ATA_EH_RESUME); | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | if (rc) | ||
| 1808 | *r_failed_dev = dev; | ||
| 1809 | |||
| 1810 | DPRINTK("EXIT\n"); | ||
| 1811 | return 0; | ||
| 1812 | } | ||
| 1813 | |||
| 1656 | static int ata_port_nr_enabled(struct ata_port *ap) | 1814 | static int ata_port_nr_enabled(struct ata_port *ap) |
| 1657 | { | 1815 | { |
| 1658 | int i, cnt = 0; | 1816 | int i, cnt = 0; |
| @@ -1678,6 +1836,18 @@ static int ata_eh_skip_recovery(struct ata_port *ap) | |||
| 1678 | struct ata_eh_context *ehc = &ap->eh_context; | 1836 | struct ata_eh_context *ehc = &ap->eh_context; |
| 1679 | int i; | 1837 | int i; |
| 1680 | 1838 | ||
| 1839 | /* skip if all possible devices are suspended */ | ||
| 1840 | for (i = 0; i < ata_port_max_devices(ap); i++) { | ||
| 1841 | struct ata_device *dev = &ap->device[i]; | ||
| 1842 | |||
| 1843 | if (ata_dev_absent(dev) || ata_dev_ready(dev)) | ||
| 1844 | break; | ||
| 1845 | } | ||
| 1846 | |||
| 1847 | if (i == ata_port_max_devices(ap)) | ||
| 1848 | return 1; | ||
| 1849 | |||
| 1850 | /* always thaw frozen port and recover failed devices */ | ||
| 1681 | if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap)) | 1851 | if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap)) |
| 1682 | return 0; | 1852 | return 0; |
| 1683 | 1853 | ||
| @@ -1752,6 +1922,9 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1752 | if (ap->pflags & ATA_PFLAG_UNLOADING) | 1922 | if (ap->pflags & ATA_PFLAG_UNLOADING) |
| 1753 | goto out; | 1923 | goto out; |
| 1754 | 1924 | ||
| 1925 | /* prep for resume */ | ||
| 1926 | ata_eh_prep_resume(ap); | ||
| 1927 | |||
| 1755 | /* skip EH if possible. */ | 1928 | /* skip EH if possible. */ |
| 1756 | if (ata_eh_skip_recovery(ap)) | 1929 | if (ata_eh_skip_recovery(ap)) |
| 1757 | ehc->i.action = 0; | 1930 | ehc->i.action = 0; |
| @@ -1779,6 +1952,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1779 | if (rc) | 1952 | if (rc) |
| 1780 | goto dev_fail; | 1953 | goto dev_fail; |
| 1781 | 1954 | ||
| 1955 | /* resume devices */ | ||
| 1956 | rc = ata_eh_resume(ap, &dev); | ||
| 1957 | if (rc) | ||
| 1958 | goto dev_fail; | ||
| 1959 | |||
| 1782 | /* configure transfer mode if the port has been reset */ | 1960 | /* configure transfer mode if the port has been reset */ |
| 1783 | if (ehc->i.flags & ATA_EHI_DID_RESET) { | 1961 | if (ehc->i.flags & ATA_EHI_DID_RESET) { |
| 1784 | rc = ata_set_mode(ap, &dev); | 1962 | rc = ata_set_mode(ap, &dev); |
| @@ -1788,6 +1966,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
| 1788 | } | 1966 | } |
| 1789 | } | 1967 | } |
| 1790 | 1968 | ||
| 1969 | /* suspend devices */ | ||
| 1970 | rc = ata_eh_suspend(ap, &dev); | ||
| 1971 | if (rc) | ||
| 1972 | goto dev_fail; | ||
| 1973 | |||
| 1791 | goto out; | 1974 | goto out; |
| 1792 | 1975 | ||
| 1793 | dev_fail: | 1976 | dev_fail: |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 2aa1398bbd52..363c7501843a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -131,6 +131,7 @@ enum { | |||
| 131 | ATA_DFLAG_CFG_MASK = (1 << 8) - 1, | 131 | ATA_DFLAG_CFG_MASK = (1 << 8) - 1, |
| 132 | 132 | ||
| 133 | ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ | 133 | ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ |
| 134 | ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */ | ||
| 134 | ATA_DFLAG_INIT_MASK = (1 << 16) - 1, | 135 | ATA_DFLAG_INIT_MASK = (1 << 16) - 1, |
| 135 | 136 | ||
| 136 | ATA_DFLAG_DETACH = (1 << 16), | 137 | ATA_DFLAG_DETACH = (1 << 16), |
| @@ -253,9 +254,13 @@ enum { | |||
| 253 | ATA_EH_REVALIDATE = (1 << 0), | 254 | ATA_EH_REVALIDATE = (1 << 0), |
| 254 | ATA_EH_SOFTRESET = (1 << 1), | 255 | ATA_EH_SOFTRESET = (1 << 1), |
| 255 | ATA_EH_HARDRESET = (1 << 2), | 256 | ATA_EH_HARDRESET = (1 << 2), |
| 257 | ATA_EH_SUSPEND = (1 << 3), | ||
| 258 | ATA_EH_RESUME = (1 << 4), | ||
| 259 | ATA_EH_PM_FREEZE = (1 << 5), | ||
| 256 | 260 | ||
| 257 | ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, | 261 | ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, |
| 258 | ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, | 262 | ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_SUSPEND | |
| 263 | ATA_EH_RESUME | ATA_EH_PM_FREEZE, | ||
| 259 | 264 | ||
| 260 | /* ata_eh_info->flags */ | 265 | /* ata_eh_info->flags */ |
| 261 | ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ | 266 | ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ |
| @@ -944,6 +949,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev) | |||
| 944 | return ata_class_absent(dev->class); | 949 | return ata_class_absent(dev->class); |
| 945 | } | 950 | } |
| 946 | 951 | ||
| 952 | static inline unsigned int ata_dev_ready(const struct ata_device *dev) | ||
| 953 | { | ||
| 954 | return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED); | ||
| 955 | } | ||
| 956 | |||
| 947 | /* | 957 | /* |
| 948 | * port helpers | 958 | * port helpers |
| 949 | */ | 959 | */ |
