aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_error.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-06-17 10:41:42 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-28 10:07:50 -0400
commitbc4f24014de58f045f169742701a6598884d93db (patch)
tree4e68ae6fa5fff179ce69b2d890b01a5fcc9c55d5 /drivers/scsi/scsi_error.c
parentdb5bd1e0b505c54ff492172ce4abc245cf6cd639 (diff)
[SCSI] implement runtime Power Management
This patch (as1398b) adds runtime PM support to the SCSI layer. Only the machanism is provided; use of it is up to the various high-level drivers, and the patch doesn't change any of them. Except for sg -- the patch expicitly prevents a device from being runtime-suspended while its sg device file is open. The implementation is simplistic. In general, hosts and targets are automatically suspended when all their children are asleep, but for them the runtime-suspend code doesn't actually do anything. (A host's runtime PM status is propagated up the device tree, though, so a runtime-PM-aware lower-level driver could power down the host adapter hardware at the appropriate times.) There are comments indicating where a transport class might be notified or some other hooks added. LUNs are runtime-suspended by calling the drivers' existing suspend handlers (and likewise for runtime-resume). Somewhat arbitrarily, the implementation delays for 100 ms before suspending an eligible LUN. This is because there typically are occasions during bootup when the same device file is opened and closed several times in quick succession. The way this all works is that the SCSI core increments a device's PM-usage count when it is registered. If a high-level driver does nothing then the device will not be eligible for runtime-suspend because of the elevated usage count. If a high-level driver wants to use runtime PM then it can call scsi_autopm_put_device() in its probe routine to decrement the usage count and scsi_autopm_get_device() in its remove routine to restore the original count. Hosts, targets, and LUNs are not suspended while they are being probed or removed, or while the error handler is running. In fact, a fairly large part of the patch consists of code to make sure that things aren't suspended at such times. [jejb: fix up compile issues in PM config variations] Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r--drivers/scsi/scsi_error.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c60cffbefa3c..2bf98469dc4c 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1775,6 +1775,14 @@ int scsi_error_handler(void *data)
1775 * what we need to do to get it up and online again (if we can). 1775 * what we need to do to get it up and online again (if we can).
1776 * If we fail, we end up taking the thing offline. 1776 * If we fail, we end up taking the thing offline.
1777 */ 1777 */
1778 if (scsi_autopm_get_host(shost) != 0) {
1779 SCSI_LOG_ERROR_RECOVERY(1,
1780 printk(KERN_ERR "Error handler scsi_eh_%d "
1781 "unable to autoresume\n",
1782 shost->host_no));
1783 continue;
1784 }
1785
1778 if (shost->transportt->eh_strategy_handler) 1786 if (shost->transportt->eh_strategy_handler)
1779 shost->transportt->eh_strategy_handler(shost); 1787 shost->transportt->eh_strategy_handler(shost);
1780 else 1788 else
@@ -1788,6 +1796,7 @@ int scsi_error_handler(void *data)
1788 * which are still online. 1796 * which are still online.
1789 */ 1797 */
1790 scsi_restart_operations(shost); 1798 scsi_restart_operations(shost);
1799 scsi_autopm_put_host(shost);
1791 set_current_state(TASK_INTERRUPTIBLE); 1800 set_current_state(TASK_INTERRUPTIBLE);
1792 } 1801 }
1793 __set_current_state(TASK_RUNNING); 1802 __set_current_state(TASK_RUNNING);
@@ -1885,12 +1894,16 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
1885int 1894int
1886scsi_reset_provider(struct scsi_device *dev, int flag) 1895scsi_reset_provider(struct scsi_device *dev, int flag)
1887{ 1896{
1888 struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL); 1897 struct scsi_cmnd *scmd;
1889 struct Scsi_Host *shost = dev->host; 1898 struct Scsi_Host *shost = dev->host;
1890 struct request req; 1899 struct request req;
1891 unsigned long flags; 1900 unsigned long flags;
1892 int rtn; 1901 int rtn;
1893 1902
1903 if (scsi_autopm_get_host(shost) < 0)
1904 return FAILED;
1905
1906 scmd = scsi_get_command(dev, GFP_KERNEL);
1894 blk_rq_init(NULL, &req); 1907 blk_rq_init(NULL, &req);
1895 scmd->request = &req; 1908 scmd->request = &req;
1896 1909
@@ -1947,6 +1960,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
1947 scsi_run_host_queues(shost); 1960 scsi_run_host_queues(shost);
1948 1961
1949 scsi_next_command(scmd); 1962 scsi_next_command(scmd);
1963 scsi_autopm_put_host(shost);
1950 return rtn; 1964 return rtn;
1951} 1965}
1952EXPORT_SYMBOL(scsi_reset_provider); 1966EXPORT_SYMBOL(scsi_reset_provider);