[PATCH] libata: implement PM EH actions

Implement two PM per-dev EH actions - ATA_EH_SUSPEND and
ATA_EH_RESUME. Each action puts the target device into suspended mode
and resumes from it respectively.

Once a device is put to suspended mode, no EH operations other than
RESUME is allowed on the device. The device will stay suspended till
it gets resumed and thus reset and revalidated. To implement this, a
new device state helper - ata_dev_ready() - is implemented and used in
EH action implementations to make them operate only on attached &
running devices.

If all possible devices on a port are suspended, reset is skipped too.
This prevents spurious events including hotplug events from disrupting
suspended devices.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>

authored by Tejun Heo and committed by Jeff Garzik 02670bf3 c0b6c037

+198 -4
+3 -2
drivers/scsi/libata-core.c
··· 2146 2146 * return error code and failing device on failure. 2147 2147 */ 2148 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 2150 ap->ops->set_mode(ap); 2151 2151 break; 2152 2152 } ··· 2212 2212 for (i = 0; i < ATA_MAX_DEVICES; i++) { 2213 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 2217 continue; 2217 2218 2218 2219 rc = ata_dev_set_mode(dev);
+184 -1
drivers/scsi/libata-eh.c
··· 1610 1610 dev = &ap->device[i]; 1611 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 1614 if (ata_port_offline(ap)) { 1615 1615 rc = -EIO; 1616 1616 break; ··· 1653 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 1814 static int ata_port_nr_enabled(struct ata_port *ap) 1657 1815 { 1658 1816 int i, cnt = 0; ··· 1836 1678 struct ata_eh_context *ehc = &ap->eh_context; 1837 1679 int i; 1838 1680 1681 + /* skip if all possible devices are suspended */ 1682 + for (i = 0; i < ata_port_max_devices(ap); i++) { 1683 + struct ata_device *dev = &ap->device[i]; 1684 + 1685 + if (ata_dev_absent(dev) || ata_dev_ready(dev)) 1686 + break; 1687 + } 1688 + 1689 + if (i == ata_port_max_devices(ap)) 1690 + return 1; 1691 + 1692 + /* always thaw frozen port and recover failed devices */ 1839 1693 if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap)) 1840 1694 return 0; 1841 1695 ··· 1922 1752 if (ap->pflags & ATA_PFLAG_UNLOADING) 1923 1753 goto out; 1924 1754 1755 + /* prep for resume */ 1756 + ata_eh_prep_resume(ap); 1757 + 1925 1758 /* skip EH if possible. */ 1926 1759 if (ata_eh_skip_recovery(ap)) 1927 1760 ehc->i.action = 0; ··· 1952 1779 if (rc) 1953 1780 goto dev_fail; 1954 1781 1782 + /* resume devices */ 1783 + rc = ata_eh_resume(ap, &dev); 1784 + if (rc) 1785 + goto dev_fail; 1786 + 1955 1787 /* configure transfer mode if the port has been reset */ 1956 1788 if (ehc->i.flags & ATA_EHI_DID_RESET) { 1957 1789 rc = ata_set_mode(ap, &dev); ··· 1965 1787 goto dev_fail; 1966 1788 } 1967 1789 } 1790 + 1791 + /* suspend devices */ 1792 + rc = ata_eh_suspend(ap, &dev); 1793 + if (rc) 1794 + goto dev_fail; 1968 1795 1969 1796 goto out; 1970 1797
+11 -1
include/linux/libata.h
··· 131 131 ATA_DFLAG_CFG_MASK = (1 << 8) - 1, 132 132 133 133 ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */ 134 + ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */ 134 135 ATA_DFLAG_INIT_MASK = (1 << 16) - 1, 135 136 136 137 ATA_DFLAG_DETACH = (1 << 16), ··· 254 253 ATA_EH_REVALIDATE = (1 << 0), 255 254 ATA_EH_SOFTRESET = (1 << 1), 256 255 ATA_EH_HARDRESET = (1 << 2), 256 + ATA_EH_SUSPEND = (1 << 3), 257 + ATA_EH_RESUME = (1 << 4), 258 + ATA_EH_PM_FREEZE = (1 << 5), 257 259 258 260 ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, 259 - ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, 261 + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_SUSPEND | 262 + ATA_EH_RESUME | ATA_EH_PM_FREEZE, 260 263 261 264 /* ata_eh_info->flags */ 262 265 ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ ··· 947 942 static inline unsigned int ata_dev_absent(const struct ata_device *dev) 948 943 { 949 944 return ata_class_absent(dev->class); 945 + } 946 + 947 + static inline unsigned int ata_dev_ready(const struct ata_device *dev) 948 + { 949 + return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED); 950 950 } 951 951 952 952 /*