aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-eh.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-07-03 03:07:26 -0400
committerJeff Garzik <jeff@garzik.org>2006-07-05 22:16:28 -0400
commit02670bf379267f55a43aa57f6895689697e90eb3 (patch)
tree830b74690371e39cf8e94de678768993be743437 /drivers/scsi/libata-eh.c
parentc0b6c0377c32fe3f6a2cf1e018db6da8a3b78379 (diff)
[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>
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r--drivers/scsi/libata-eh.c185
1 files changed, 184 insertions, 1 deletions
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 */
1672static 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 */
1735static 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 */
1774static 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
1656static int ata_port_nr_enabled(struct ata_port *ap) 1814static 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: