diff options
author | Tejun Heo <htejun@gmail.com> | 2007-05-04 15:27:47 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-05-11 18:01:03 -0400 |
commit | 9666f4009c22f6520ac3fb8a19c9e32ab973e828 (patch) | |
tree | eaac13cd5890af6298e5576a48c29891f0890bd1 /drivers/ata/libata-eh.c | |
parent | 0a3fd051c7036ef71b58863f8e5da7c3dabd9d3f (diff) |
libata: reimplement suspend/resume support using sdev->manage_start_stop
Reimplement suspend/resume support using sdev->manage_start_stop.
* Device suspend/resume is now SCSI layer's responsibility and the
code is simplified a lot.
* DPM is dropped. This also simplifies code a lot. Suspend/resume
status is port-wide now.
* ata_scsi_device_suspend/resume() and ata_dev_ready() removed.
* Resume now has to wait for disk to spin up before proceeding. I
couldn't find easy way out as libata is in EH waiting for the
disk to be ready and sd is waiting for EH to complete to issue
START_STOP.
* sdev->manage_start_stop is set to 1 in ata_scsi_slave_config().
This fixes spindown on shutdown and suspend-to-disk.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r-- | drivers/ata/libata-eh.c | 237 |
1 files changed, 4 insertions, 233 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 8256655ce7d9..412d6049afa3 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -77,29 +77,12 @@ static void ata_eh_finish(struct ata_port *ap); | |||
77 | #ifdef CONFIG_PM | 77 | #ifdef CONFIG_PM |
78 | static void ata_eh_handle_port_suspend(struct ata_port *ap); | 78 | static void ata_eh_handle_port_suspend(struct ata_port *ap); |
79 | static void ata_eh_handle_port_resume(struct ata_port *ap); | 79 | static void ata_eh_handle_port_resume(struct ata_port *ap); |
80 | static int ata_eh_suspend(struct ata_port *ap, | ||
81 | struct ata_device **r_failed_dev); | ||
82 | static void ata_eh_prep_resume(struct ata_port *ap); | ||
83 | static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev); | ||
84 | #else /* CONFIG_PM */ | 80 | #else /* CONFIG_PM */ |
85 | static void ata_eh_handle_port_suspend(struct ata_port *ap) | 81 | static void ata_eh_handle_port_suspend(struct ata_port *ap) |
86 | { } | 82 | { } |
87 | 83 | ||
88 | static void ata_eh_handle_port_resume(struct ata_port *ap) | 84 | static void ata_eh_handle_port_resume(struct ata_port *ap) |
89 | { } | 85 | { } |
90 | |||
91 | static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void ata_eh_prep_resume(struct ata_port *ap) | ||
97 | { } | ||
98 | |||
99 | static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
100 | { | ||
101 | return 0; | ||
102 | } | ||
103 | #endif /* CONFIG_PM */ | 86 | #endif /* CONFIG_PM */ |
104 | 87 | ||
105 | static void ata_ering_record(struct ata_ering *ering, int is_io, | 88 | static void ata_ering_record(struct ata_ering *ering, int is_io, |
@@ -1791,7 +1774,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1791 | if (ehc->i.flags & ATA_EHI_DID_RESET) | 1774 | if (ehc->i.flags & ATA_EHI_DID_RESET) |
1792 | readid_flags |= ATA_READID_POSTRESET; | 1775 | readid_flags |= ATA_READID_POSTRESET; |
1793 | 1776 | ||
1794 | if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { | 1777 | if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { |
1795 | if (ata_port_offline(ap)) { | 1778 | if (ata_port_offline(ap)) { |
1796 | rc = -EIO; | 1779 | rc = -EIO; |
1797 | goto err; | 1780 | goto err; |
@@ -1872,166 +1855,6 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1872 | return rc; | 1855 | return rc; |
1873 | } | 1856 | } |
1874 | 1857 | ||
1875 | #ifdef CONFIG_PM | ||
1876 | /** | ||
1877 | * ata_eh_suspend - handle suspend EH action | ||
1878 | * @ap: target host port | ||
1879 | * @r_failed_dev: result parameter to indicate failing device | ||
1880 | * | ||
1881 | * Handle suspend EH action. Disk devices are spinned down and | ||
1882 | * other types of devices are just marked suspended. Once | ||
1883 | * suspended, no EH action to the device is allowed until it is | ||
1884 | * resumed. | ||
1885 | * | ||
1886 | * LOCKING: | ||
1887 | * Kernel thread context (may sleep). | ||
1888 | * | ||
1889 | * RETURNS: | ||
1890 | * 0 on success, -errno otherwise | ||
1891 | */ | ||
1892 | static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
1893 | { | ||
1894 | struct ata_device *dev; | ||
1895 | int i, rc = 0; | ||
1896 | |||
1897 | DPRINTK("ENTER\n"); | ||
1898 | |||
1899 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
1900 | unsigned long flags; | ||
1901 | unsigned int action, err_mask; | ||
1902 | |||
1903 | dev = &ap->device[i]; | ||
1904 | action = ata_eh_dev_action(dev); | ||
1905 | |||
1906 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND)) | ||
1907 | continue; | ||
1908 | |||
1909 | WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED); | ||
1910 | |||
1911 | ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND); | ||
1912 | |||
1913 | if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { | ||
1914 | /* flush cache */ | ||
1915 | rc = ata_flush_cache(dev); | ||
1916 | if (rc) | ||
1917 | break; | ||
1918 | |||
1919 | /* spin down */ | ||
1920 | err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); | ||
1921 | if (err_mask) { | ||
1922 | ata_dev_printk(dev, KERN_ERR, "failed to " | ||
1923 | "spin down (err_mask=0x%x)\n", | ||
1924 | err_mask); | ||
1925 | rc = -EIO; | ||
1926 | break; | ||
1927 | } | ||
1928 | } | ||
1929 | |||
1930 | spin_lock_irqsave(ap->lock, flags); | ||
1931 | dev->flags |= ATA_DFLAG_SUSPENDED; | ||
1932 | spin_unlock_irqrestore(ap->lock, flags); | ||
1933 | |||
1934 | ata_eh_done(ap, dev, ATA_EH_SUSPEND); | ||
1935 | } | ||
1936 | |||
1937 | if (rc) | ||
1938 | *r_failed_dev = dev; | ||
1939 | |||
1940 | DPRINTK("EXIT\n"); | ||
1941 | return rc; | ||
1942 | } | ||
1943 | |||
1944 | /** | ||
1945 | * ata_eh_prep_resume - prep for resume EH action | ||
1946 | * @ap: target host port | ||
1947 | * | ||
1948 | * Clear SUSPENDED in preparation for scheduled resume actions. | ||
1949 | * This allows other parts of EH to access the devices being | ||
1950 | * resumed. | ||
1951 | * | ||
1952 | * LOCKING: | ||
1953 | * Kernel thread context (may sleep). | ||
1954 | */ | ||
1955 | static void ata_eh_prep_resume(struct ata_port *ap) | ||
1956 | { | ||
1957 | struct ata_device *dev; | ||
1958 | unsigned long flags; | ||
1959 | int i; | ||
1960 | |||
1961 | DPRINTK("ENTER\n"); | ||
1962 | |||
1963 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
1964 | unsigned int action; | ||
1965 | |||
1966 | dev = &ap->device[i]; | ||
1967 | action = ata_eh_dev_action(dev); | ||
1968 | |||
1969 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) | ||
1970 | continue; | ||
1971 | |||
1972 | spin_lock_irqsave(ap->lock, flags); | ||
1973 | dev->flags &= ~ATA_DFLAG_SUSPENDED; | ||
1974 | spin_unlock_irqrestore(ap->lock, flags); | ||
1975 | } | ||
1976 | |||
1977 | DPRINTK("EXIT\n"); | ||
1978 | } | ||
1979 | |||
1980 | /** | ||
1981 | * ata_eh_resume - handle resume EH action | ||
1982 | * @ap: target host port | ||
1983 | * @r_failed_dev: result parameter to indicate failing device | ||
1984 | * | ||
1985 | * Handle resume EH action. Target devices are already reset and | ||
1986 | * revalidated. Spinning up is the only operation left. | ||
1987 | * | ||
1988 | * LOCKING: | ||
1989 | * Kernel thread context (may sleep). | ||
1990 | * | ||
1991 | * RETURNS: | ||
1992 | * 0 on success, -errno otherwise | ||
1993 | */ | ||
1994 | static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
1995 | { | ||
1996 | struct ata_device *dev; | ||
1997 | int i, rc = 0; | ||
1998 | |||
1999 | DPRINTK("ENTER\n"); | ||
2000 | |||
2001 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
2002 | unsigned int action, err_mask; | ||
2003 | |||
2004 | dev = &ap->device[i]; | ||
2005 | action = ata_eh_dev_action(dev); | ||
2006 | |||
2007 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) | ||
2008 | continue; | ||
2009 | |||
2010 | ata_eh_about_to_do(ap, dev, ATA_EH_RESUME); | ||
2011 | |||
2012 | if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { | ||
2013 | err_mask = ata_do_simple_cmd(dev, | ||
2014 | ATA_CMD_IDLEIMMEDIATE); | ||
2015 | if (err_mask) { | ||
2016 | ata_dev_printk(dev, KERN_ERR, "failed to " | ||
2017 | "spin up (err_mask=0x%x)\n", | ||
2018 | err_mask); | ||
2019 | rc = -EIO; | ||
2020 | break; | ||
2021 | } | ||
2022 | } | ||
2023 | |||
2024 | ata_eh_done(ap, dev, ATA_EH_RESUME); | ||
2025 | } | ||
2026 | |||
2027 | if (rc) | ||
2028 | *r_failed_dev = dev; | ||
2029 | |||
2030 | DPRINTK("EXIT\n"); | ||
2031 | return 0; | ||
2032 | } | ||
2033 | #endif /* CONFIG_PM */ | ||
2034 | |||
2035 | static int ata_port_nr_enabled(struct ata_port *ap) | 1858 | static int ata_port_nr_enabled(struct ata_port *ap) |
2036 | { | 1859 | { |
2037 | int i, cnt = 0; | 1860 | int i, cnt = 0; |
@@ -2057,17 +1880,6 @@ static int ata_eh_skip_recovery(struct ata_port *ap) | |||
2057 | struct ata_eh_context *ehc = &ap->eh_context; | 1880 | struct ata_eh_context *ehc = &ap->eh_context; |
2058 | int i; | 1881 | int i; |
2059 | 1882 | ||
2060 | /* skip if all possible devices are suspended */ | ||
2061 | for (i = 0; i < ata_port_max_devices(ap); i++) { | ||
2062 | struct ata_device *dev = &ap->device[i]; | ||
2063 | |||
2064 | if (!(dev->flags & ATA_DFLAG_SUSPENDED)) | ||
2065 | break; | ||
2066 | } | ||
2067 | |||
2068 | if (i == ata_port_max_devices(ap)) | ||
2069 | return 1; | ||
2070 | |||
2071 | /* thaw frozen port, resume link and recover failed devices */ | 1883 | /* thaw frozen port, resume link and recover failed devices */ |
2072 | if ((ap->pflags & ATA_PFLAG_FROZEN) || | 1884 | if ((ap->pflags & ATA_PFLAG_FROZEN) || |
2073 | (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap)) | 1885 | (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap)) |
@@ -2147,9 +1959,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2147 | if (ap->pflags & ATA_PFLAG_UNLOADING) | 1959 | if (ap->pflags & ATA_PFLAG_UNLOADING) |
2148 | goto out; | 1960 | goto out; |
2149 | 1961 | ||
2150 | /* prep for resume */ | ||
2151 | ata_eh_prep_resume(ap); | ||
2152 | |||
2153 | /* skip EH if possible. */ | 1962 | /* skip EH if possible. */ |
2154 | if (ata_eh_skip_recovery(ap)) | 1963 | if (ata_eh_skip_recovery(ap)) |
2155 | ehc->i.action = 0; | 1964 | ehc->i.action = 0; |
@@ -2177,11 +1986,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2177 | if (rc) | 1986 | if (rc) |
2178 | goto dev_fail; | 1987 | goto dev_fail; |
2179 | 1988 | ||
2180 | /* resume devices */ | ||
2181 | rc = ata_eh_resume(ap, &dev); | ||
2182 | if (rc) | ||
2183 | goto dev_fail; | ||
2184 | |||
2185 | /* configure transfer mode if necessary */ | 1989 | /* configure transfer mode if necessary */ |
2186 | if (ehc->i.flags & ATA_EHI_SETMODE) { | 1990 | if (ehc->i.flags & ATA_EHI_SETMODE) { |
2187 | rc = ata_set_mode(ap, &dev); | 1991 | rc = ata_set_mode(ap, &dev); |
@@ -2190,11 +1994,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2190 | ehc->i.flags &= ~ATA_EHI_SETMODE; | 1994 | ehc->i.flags &= ~ATA_EHI_SETMODE; |
2191 | } | 1995 | } |
2192 | 1996 | ||
2193 | /* suspend devices */ | ||
2194 | rc = ata_eh_suspend(ap, &dev); | ||
2195 | if (rc) | ||
2196 | goto dev_fail; | ||
2197 | |||
2198 | goto out; | 1997 | goto out; |
2199 | 1998 | ||
2200 | dev_fail: | 1999 | dev_fail: |
@@ -2390,22 +2189,13 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) | |||
2390 | * | 2189 | * |
2391 | * Resume @ap. | 2190 | * Resume @ap. |
2392 | * | 2191 | * |
2393 | * This function also waits upto one second until all devices | ||
2394 | * hanging off this port requests resume EH action. This is to | ||
2395 | * prevent invoking EH and thus reset multiple times on resume. | ||
2396 | * | ||
2397 | * On DPM resume, where some of devices might not be resumed | ||
2398 | * together, this may delay port resume upto one second, but such | ||
2399 | * DPM resumes are rare and 1 sec delay isn't too bad. | ||
2400 | * | ||
2401 | * LOCKING: | 2192 | * LOCKING: |
2402 | * Kernel thread context (may sleep). | 2193 | * Kernel thread context (may sleep). |
2403 | */ | 2194 | */ |
2404 | static void ata_eh_handle_port_resume(struct ata_port *ap) | 2195 | static void ata_eh_handle_port_resume(struct ata_port *ap) |
2405 | { | 2196 | { |
2406 | unsigned long timeout; | ||
2407 | unsigned long flags; | 2197 | unsigned long flags; |
2408 | int i, rc = 0; | 2198 | int rc = 0; |
2409 | 2199 | ||
2410 | /* are we resuming? */ | 2200 | /* are we resuming? */ |
2411 | spin_lock_irqsave(ap->lock, flags); | 2201 | spin_lock_irqsave(ap->lock, flags); |
@@ -2416,31 +2206,12 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) | |||
2416 | } | 2206 | } |
2417 | spin_unlock_irqrestore(ap->lock, flags); | 2207 | spin_unlock_irqrestore(ap->lock, flags); |
2418 | 2208 | ||
2419 | /* spurious? */ | 2209 | WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED)); |
2420 | if (!(ap->pflags & ATA_PFLAG_SUSPENDED)) | ||
2421 | goto done; | ||
2422 | 2210 | ||
2423 | if (ap->ops->port_resume) | 2211 | if (ap->ops->port_resume) |
2424 | rc = ap->ops->port_resume(ap); | 2212 | rc = ap->ops->port_resume(ap); |
2425 | 2213 | ||
2426 | /* give devices time to request EH */ | 2214 | /* report result */ |
2427 | timeout = jiffies + HZ; /* 1s max */ | ||
2428 | while (1) { | ||
2429 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
2430 | struct ata_device *dev = &ap->device[i]; | ||
2431 | unsigned int action = ata_eh_dev_action(dev); | ||
2432 | |||
2433 | if ((dev->flags & ATA_DFLAG_SUSPENDED) && | ||
2434 | !(action & ATA_EH_RESUME)) | ||
2435 | break; | ||
2436 | } | ||
2437 | |||
2438 | if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout)) | ||
2439 | break; | ||
2440 | msleep(10); | ||
2441 | } | ||
2442 | |||
2443 | done: | ||
2444 | spin_lock_irqsave(ap->lock, flags); | 2215 | spin_lock_irqsave(ap->lock, flags); |
2445 | ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); | 2216 | ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); |
2446 | if (ap->pm_result) { | 2217 | if (ap->pm_result) { |