diff options
| -rw-r--r-- | drivers/scsi/hosts.c | 10 | ||||
| -rw-r--r-- | drivers/scsi/scsi_error.c | 16 | ||||
| -rw-r--r-- | drivers/scsi/scsi_pm.c | 110 | ||||
| -rw-r--r-- | drivers/scsi/scsi_priv.h | 14 | ||||
| -rw-r--r-- | drivers/scsi/scsi_scan.c | 24 | ||||
| -rw-r--r-- | drivers/scsi/scsi_sysfs.c | 20 | ||||
| -rw-r--r-- | drivers/scsi/sg.c | 10 | ||||
| -rw-r--r-- | include/scsi/scsi_device.h | 8 |
8 files changed, 201 insertions, 11 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index a2b1414da288..8a8f803439e1 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/completion.h> | 32 | #include <linux/completion.h> |
| 33 | #include <linux/transport_class.h> | 33 | #include <linux/transport_class.h> |
| 34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
| 35 | #include <linux/pm_runtime.h> | ||
| 35 | 36 | ||
| 36 | #include <scsi/scsi_device.h> | 37 | #include <scsi/scsi_device.h> |
| 37 | #include <scsi/scsi_host.h> | 38 | #include <scsi/scsi_host.h> |
| @@ -156,6 +157,7 @@ EXPORT_SYMBOL(scsi_host_set_state); | |||
| 156 | void scsi_remove_host(struct Scsi_Host *shost) | 157 | void scsi_remove_host(struct Scsi_Host *shost) |
| 157 | { | 158 | { |
| 158 | unsigned long flags; | 159 | unsigned long flags; |
| 160 | |||
| 159 | mutex_lock(&shost->scan_mutex); | 161 | mutex_lock(&shost->scan_mutex); |
| 160 | spin_lock_irqsave(shost->host_lock, flags); | 162 | spin_lock_irqsave(shost->host_lock, flags); |
| 161 | if (scsi_host_set_state(shost, SHOST_CANCEL)) | 163 | if (scsi_host_set_state(shost, SHOST_CANCEL)) |
| @@ -165,6 +167,8 @@ void scsi_remove_host(struct Scsi_Host *shost) | |||
| 165 | return; | 167 | return; |
| 166 | } | 168 | } |
| 167 | spin_unlock_irqrestore(shost->host_lock, flags); | 169 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 170 | |||
| 171 | scsi_autopm_get_host(shost); | ||
| 168 | scsi_forget_host(shost); | 172 | scsi_forget_host(shost); |
| 169 | mutex_unlock(&shost->scan_mutex); | 173 | mutex_unlock(&shost->scan_mutex); |
| 170 | scsi_proc_host_rm(shost); | 174 | scsi_proc_host_rm(shost); |
| @@ -216,12 +220,14 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, | |||
| 216 | shost->shost_gendev.parent = dev ? dev : &platform_bus; | 220 | shost->shost_gendev.parent = dev ? dev : &platform_bus; |
| 217 | shost->dma_dev = dma_dev; | 221 | shost->dma_dev = dma_dev; |
| 218 | 222 | ||
| 219 | device_enable_async_suspend(&shost->shost_gendev); | ||
| 220 | |||
| 221 | error = device_add(&shost->shost_gendev); | 223 | error = device_add(&shost->shost_gendev); |
| 222 | if (error) | 224 | if (error) |
| 223 | goto out; | 225 | goto out; |
| 224 | 226 | ||
| 227 | pm_runtime_set_active(&shost->shost_gendev); | ||
| 228 | pm_runtime_enable(&shost->shost_gendev); | ||
| 229 | device_enable_async_suspend(&shost->shost_gendev); | ||
| 230 | |||
| 225 | scsi_host_set_state(shost, SHOST_RUNNING); | 231 | scsi_host_set_state(shost, SHOST_RUNNING); |
| 226 | get_device(shost->shost_gendev.parent); | 232 | get_device(shost->shost_gendev.parent); |
| 227 | 233 | ||
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) | |||
| 1885 | int | 1894 | int |
| 1886 | scsi_reset_provider(struct scsi_device *dev, int flag) | 1895 | scsi_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 | } |
| 1952 | EXPORT_SYMBOL(scsi_reset_provider); | 1966 | EXPORT_SYMBOL(scsi_reset_provider); |
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index cd83758ce0a2..d70e91ae60af 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c | |||
| @@ -59,6 +59,12 @@ static int scsi_bus_resume_common(struct device *dev) | |||
| 59 | 59 | ||
| 60 | if (scsi_is_sdev_device(dev)) | 60 | if (scsi_is_sdev_device(dev)) |
| 61 | err = scsi_dev_type_resume(dev); | 61 | err = scsi_dev_type_resume(dev); |
| 62 | |||
| 63 | if (err == 0) { | ||
| 64 | pm_runtime_disable(dev); | ||
| 65 | pm_runtime_set_active(dev); | ||
| 66 | pm_runtime_enable(dev); | ||
| 67 | } | ||
| 62 | return err; | 68 | return err; |
| 63 | } | 69 | } |
| 64 | 70 | ||
| @@ -86,6 +92,107 @@ static int scsi_bus_poweroff(struct device *dev) | |||
| 86 | 92 | ||
| 87 | #endif /* CONFIG_PM_SLEEP */ | 93 | #endif /* CONFIG_PM_SLEEP */ |
| 88 | 94 | ||
| 95 | #ifdef CONFIG_PM_RUNTIME | ||
| 96 | |||
| 97 | static int scsi_runtime_suspend(struct device *dev) | ||
| 98 | { | ||
| 99 | int err = 0; | ||
| 100 | |||
| 101 | dev_dbg(dev, "scsi_runtime_suspend\n"); | ||
| 102 | if (scsi_is_sdev_device(dev)) { | ||
| 103 | err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND); | ||
| 104 | if (err == -EAGAIN) | ||
| 105 | pm_schedule_suspend(dev, jiffies_to_msecs( | ||
| 106 | round_jiffies_up_relative(HZ/10))); | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Insert hooks here for targets, hosts, and transport classes */ | ||
| 110 | |||
| 111 | return err; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int scsi_runtime_resume(struct device *dev) | ||
| 115 | { | ||
| 116 | int err = 0; | ||
| 117 | |||
| 118 | dev_dbg(dev, "scsi_runtime_resume\n"); | ||
| 119 | if (scsi_is_sdev_device(dev)) | ||
| 120 | err = scsi_dev_type_resume(dev); | ||
| 121 | |||
| 122 | /* Insert hooks here for targets, hosts, and transport classes */ | ||
| 123 | |||
| 124 | return err; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int scsi_runtime_idle(struct device *dev) | ||
| 128 | { | ||
| 129 | int err; | ||
| 130 | |||
| 131 | dev_dbg(dev, "scsi_runtime_idle\n"); | ||
| 132 | |||
| 133 | /* Insert hooks here for targets, hosts, and transport classes */ | ||
| 134 | |||
| 135 | if (scsi_is_sdev_device(dev)) | ||
| 136 | err = pm_schedule_suspend(dev, 100); | ||
| 137 | else | ||
| 138 | err = pm_runtime_suspend(dev); | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | int scsi_autopm_get_device(struct scsi_device *sdev) | ||
| 143 | { | ||
| 144 | int err; | ||
| 145 | |||
| 146 | err = pm_runtime_get_sync(&sdev->sdev_gendev); | ||
| 147 | if (err < 0) | ||
| 148 | pm_runtime_put_sync(&sdev->sdev_gendev); | ||
| 149 | else if (err > 0) | ||
| 150 | err = 0; | ||
| 151 | return err; | ||
| 152 | } | ||
| 153 | EXPORT_SYMBOL_GPL(scsi_autopm_get_device); | ||
| 154 | |||
| 155 | void scsi_autopm_put_device(struct scsi_device *sdev) | ||
| 156 | { | ||
| 157 | pm_runtime_put_sync(&sdev->sdev_gendev); | ||
| 158 | } | ||
| 159 | EXPORT_SYMBOL_GPL(scsi_autopm_put_device); | ||
| 160 | |||
| 161 | void scsi_autopm_get_target(struct scsi_target *starget) | ||
| 162 | { | ||
| 163 | pm_runtime_get_sync(&starget->dev); | ||
| 164 | } | ||
| 165 | |||
| 166 | void scsi_autopm_put_target(struct scsi_target *starget) | ||
| 167 | { | ||
| 168 | pm_runtime_put_sync(&starget->dev); | ||
| 169 | } | ||
| 170 | |||
| 171 | int scsi_autopm_get_host(struct Scsi_Host *shost) | ||
| 172 | { | ||
| 173 | int err; | ||
| 174 | |||
| 175 | err = pm_runtime_get_sync(&shost->shost_gendev); | ||
| 176 | if (err < 0) | ||
| 177 | pm_runtime_put_sync(&shost->shost_gendev); | ||
| 178 | else if (err > 0) | ||
| 179 | err = 0; | ||
| 180 | return err; | ||
| 181 | } | ||
| 182 | |||
| 183 | void scsi_autopm_put_host(struct Scsi_Host *shost) | ||
| 184 | { | ||
| 185 | pm_runtime_put_sync(&shost->shost_gendev); | ||
| 186 | } | ||
| 187 | |||
| 188 | #else | ||
| 189 | |||
| 190 | #define scsi_runtime_suspend NULL | ||
| 191 | #define scsi_runtime_resume NULL | ||
| 192 | #define scsi_runtime_idle NULL | ||
| 193 | |||
| 194 | #endif /* CONFIG_PM_RUNTIME */ | ||
| 195 | |||
| 89 | const struct dev_pm_ops scsi_bus_pm_ops = { | 196 | const struct dev_pm_ops scsi_bus_pm_ops = { |
| 90 | .suspend = scsi_bus_suspend, | 197 | .suspend = scsi_bus_suspend, |
| 91 | .resume = scsi_bus_resume_common, | 198 | .resume = scsi_bus_resume_common, |
| @@ -93,4 +200,7 @@ const struct dev_pm_ops scsi_bus_pm_ops = { | |||
| 93 | .thaw = scsi_bus_resume_common, | 200 | .thaw = scsi_bus_resume_common, |
| 94 | .poweroff = scsi_bus_poweroff, | 201 | .poweroff = scsi_bus_poweroff, |
| 95 | .restore = scsi_bus_resume_common, | 202 | .restore = scsi_bus_resume_common, |
| 203 | .runtime_suspend = scsi_runtime_suspend, | ||
| 204 | .runtime_resume = scsi_runtime_resume, | ||
| 205 | .runtime_idle = scsi_runtime_idle, | ||
| 96 | }; | 206 | }; |
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index dddacc732550..026295e2c539 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
| @@ -7,6 +7,7 @@ struct request_queue; | |||
| 7 | struct request; | 7 | struct request; |
| 8 | struct scsi_cmnd; | 8 | struct scsi_cmnd; |
| 9 | struct scsi_device; | 9 | struct scsi_device; |
| 10 | struct scsi_target; | ||
| 10 | struct scsi_host_template; | 11 | struct scsi_host_template; |
| 11 | struct Scsi_Host; | 12 | struct Scsi_Host; |
| 12 | struct scsi_nl_hdr; | 13 | struct scsi_nl_hdr; |
| @@ -147,9 +148,20 @@ static inline void scsi_netlink_exit(void) {} | |||
| 147 | /* scsi_pm.c */ | 148 | /* scsi_pm.c */ |
| 148 | #ifdef CONFIG_PM_OPS | 149 | #ifdef CONFIG_PM_OPS |
| 149 | extern const struct dev_pm_ops scsi_bus_pm_ops; | 150 | extern const struct dev_pm_ops scsi_bus_pm_ops; |
| 150 | #else | 151 | #else /* CONFIG_PM_OPS */ |
| 151 | #define scsi_bus_pm_ops (*NULL) | 152 | #define scsi_bus_pm_ops (*NULL) |
| 152 | #endif | 153 | #endif |
| 154 | #ifdef CONFIG_PM_RUNTIME | ||
| 155 | extern void scsi_autopm_get_target(struct scsi_target *); | ||
| 156 | extern void scsi_autopm_put_target(struct scsi_target *); | ||
| 157 | extern int scsi_autopm_get_host(struct Scsi_Host *); | ||
| 158 | extern void scsi_autopm_put_host(struct Scsi_Host *); | ||
| 159 | #else | ||
| 160 | static inline void scsi_autopm_get_target(struct scsi_target *t) {} | ||
| 161 | static inline void scsi_autopm_put_target(struct scsi_target *t) {} | ||
| 162 | static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; } | ||
| 163 | static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} | ||
| 164 | #endif /* CONFIG_PM_RUNTIME */ | ||
| 153 | 165 | ||
| 154 | /* | 166 | /* |
| 155 | * internal scsi timeout functions: for use by mid-layer and transport | 167 | * internal scsi timeout functions: for use by mid-layer and transport |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 1c027a97d8b9..3d0a1e6e9c48 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
| @@ -1513,14 +1513,18 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, | |||
| 1513 | starget = scsi_alloc_target(parent, channel, id); | 1513 | starget = scsi_alloc_target(parent, channel, id); |
| 1514 | if (!starget) | 1514 | if (!starget) |
| 1515 | return ERR_PTR(-ENOMEM); | 1515 | return ERR_PTR(-ENOMEM); |
| 1516 | scsi_autopm_get_target(starget); | ||
| 1516 | 1517 | ||
| 1517 | mutex_lock(&shost->scan_mutex); | 1518 | mutex_lock(&shost->scan_mutex); |
| 1518 | if (!shost->async_scan) | 1519 | if (!shost->async_scan) |
| 1519 | scsi_complete_async_scans(); | 1520 | scsi_complete_async_scans(); |
| 1520 | 1521 | ||
| 1521 | if (scsi_host_scan_allowed(shost)) | 1522 | if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { |
| 1522 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); | 1523 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); |
| 1524 | scsi_autopm_put_host(shost); | ||
| 1525 | } | ||
| 1523 | mutex_unlock(&shost->scan_mutex); | 1526 | mutex_unlock(&shost->scan_mutex); |
| 1527 | scsi_autopm_put_target(starget); | ||
| 1524 | scsi_target_reap(starget); | 1528 | scsi_target_reap(starget); |
| 1525 | put_device(&starget->dev); | 1529 | put_device(&starget->dev); |
| 1526 | 1530 | ||
| @@ -1574,6 +1578,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, | |||
| 1574 | starget = scsi_alloc_target(parent, channel, id); | 1578 | starget = scsi_alloc_target(parent, channel, id); |
| 1575 | if (!starget) | 1579 | if (!starget) |
| 1576 | return; | 1580 | return; |
| 1581 | scsi_autopm_get_target(starget); | ||
| 1577 | 1582 | ||
| 1578 | if (lun != SCAN_WILD_CARD) { | 1583 | if (lun != SCAN_WILD_CARD) { |
| 1579 | /* | 1584 | /* |
| @@ -1599,6 +1604,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, | |||
| 1599 | } | 1604 | } |
| 1600 | 1605 | ||
| 1601 | out_reap: | 1606 | out_reap: |
| 1607 | scsi_autopm_put_target(starget); | ||
| 1602 | /* now determine if the target has any children at all | 1608 | /* now determine if the target has any children at all |
| 1603 | * and if not, nuke it */ | 1609 | * and if not, nuke it */ |
| 1604 | scsi_target_reap(starget); | 1610 | scsi_target_reap(starget); |
| @@ -1633,8 +1639,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel, | |||
| 1633 | if (!shost->async_scan) | 1639 | if (!shost->async_scan) |
| 1634 | scsi_complete_async_scans(); | 1640 | scsi_complete_async_scans(); |
| 1635 | 1641 | ||
| 1636 | if (scsi_host_scan_allowed(shost)) | 1642 | if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { |
| 1637 | __scsi_scan_target(parent, channel, id, lun, rescan); | 1643 | __scsi_scan_target(parent, channel, id, lun, rescan); |
| 1644 | scsi_autopm_put_host(shost); | ||
| 1645 | } | ||
| 1638 | mutex_unlock(&shost->scan_mutex); | 1646 | mutex_unlock(&shost->scan_mutex); |
| 1639 | } | 1647 | } |
| 1640 | EXPORT_SYMBOL(scsi_scan_target); | 1648 | EXPORT_SYMBOL(scsi_scan_target); |
| @@ -1686,7 +1694,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
| 1686 | if (!shost->async_scan) | 1694 | if (!shost->async_scan) |
| 1687 | scsi_complete_async_scans(); | 1695 | scsi_complete_async_scans(); |
| 1688 | 1696 | ||
| 1689 | if (scsi_host_scan_allowed(shost)) { | 1697 | if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { |
| 1690 | if (channel == SCAN_WILD_CARD) | 1698 | if (channel == SCAN_WILD_CARD) |
| 1691 | for (channel = 0; channel <= shost->max_channel; | 1699 | for (channel = 0; channel <= shost->max_channel; |
| 1692 | channel++) | 1700 | channel++) |
| @@ -1694,6 +1702,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, | |||
| 1694 | rescan); | 1702 | rescan); |
| 1695 | else | 1703 | else |
| 1696 | scsi_scan_channel(shost, channel, id, lun, rescan); | 1704 | scsi_scan_channel(shost, channel, id, lun, rescan); |
| 1705 | scsi_autopm_put_host(shost); | ||
| 1697 | } | 1706 | } |
| 1698 | mutex_unlock(&shost->scan_mutex); | 1707 | mutex_unlock(&shost->scan_mutex); |
| 1699 | 1708 | ||
| @@ -1831,8 +1840,11 @@ static void do_scsi_scan_host(struct Scsi_Host *shost) | |||
| 1831 | static int do_scan_async(void *_data) | 1840 | static int do_scan_async(void *_data) |
| 1832 | { | 1841 | { |
| 1833 | struct async_scan_data *data = _data; | 1842 | struct async_scan_data *data = _data; |
| 1834 | do_scsi_scan_host(data->shost); | 1843 | struct Scsi_Host *shost = data->shost; |
| 1844 | |||
| 1845 | do_scsi_scan_host(shost); | ||
| 1835 | scsi_finish_async_scan(data); | 1846 | scsi_finish_async_scan(data); |
| 1847 | scsi_autopm_put_host(shost); | ||
| 1836 | return 0; | 1848 | return 0; |
| 1837 | } | 1849 | } |
| 1838 | 1850 | ||
| @@ -1847,16 +1859,20 @@ void scsi_scan_host(struct Scsi_Host *shost) | |||
| 1847 | 1859 | ||
| 1848 | if (strncmp(scsi_scan_type, "none", 4) == 0) | 1860 | if (strncmp(scsi_scan_type, "none", 4) == 0) |
| 1849 | return; | 1861 | return; |
| 1862 | if (scsi_autopm_get_host(shost) < 0) | ||
| 1863 | return; | ||
| 1850 | 1864 | ||
| 1851 | data = scsi_prep_async_scan(shost); | 1865 | data = scsi_prep_async_scan(shost); |
| 1852 | if (!data) { | 1866 | if (!data) { |
| 1853 | do_scsi_scan_host(shost); | 1867 | do_scsi_scan_host(shost); |
| 1868 | scsi_autopm_put_host(shost); | ||
| 1854 | return; | 1869 | return; |
| 1855 | } | 1870 | } |
| 1856 | 1871 | ||
| 1857 | p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); | 1872 | p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); |
| 1858 | if (IS_ERR(p)) | 1873 | if (IS_ERR(p)) |
| 1859 | do_scan_async(data); | 1874 | do_scan_async(data); |
| 1875 | /* scsi_autopm_put_host(shost) is called in do_scan_async() */ | ||
| 1860 | } | 1876 | } |
| 1861 | EXPORT_SYMBOL(scsi_scan_host); | 1877 | EXPORT_SYMBOL(scsi_scan_host); |
| 1862 | 1878 | ||
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 5f85f8e831f3..562fb3bce261 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| 12 | #include <linux/blkdev.h> | 12 | #include <linux/blkdev.h> |
| 13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
| 14 | #include <linux/pm_runtime.h> | ||
| 14 | 15 | ||
| 15 | #include <scsi/scsi.h> | 16 | #include <scsi/scsi.h> |
| 16 | #include <scsi/scsi_device.h> | 17 | #include <scsi/scsi_device.h> |
| @@ -802,8 +803,6 @@ static int scsi_target_add(struct scsi_target *starget) | |||
| 802 | if (starget->state != STARGET_CREATED) | 803 | if (starget->state != STARGET_CREATED) |
| 803 | return 0; | 804 | return 0; |
| 804 | 805 | ||
| 805 | device_enable_async_suspend(&starget->dev); | ||
| 806 | |||
| 807 | error = device_add(&starget->dev); | 806 | error = device_add(&starget->dev); |
| 808 | if (error) { | 807 | if (error) { |
| 809 | dev_err(&starget->dev, "target device_add failed, error %d\n", error); | 808 | dev_err(&starget->dev, "target device_add failed, error %d\n", error); |
| @@ -812,6 +811,10 @@ static int scsi_target_add(struct scsi_target *starget) | |||
| 812 | transport_add_device(&starget->dev); | 811 | transport_add_device(&starget->dev); |
| 813 | starget->state = STARGET_RUNNING; | 812 | starget->state = STARGET_RUNNING; |
| 814 | 813 | ||
| 814 | pm_runtime_set_active(&starget->dev); | ||
| 815 | pm_runtime_enable(&starget->dev); | ||
| 816 | device_enable_async_suspend(&starget->dev); | ||
| 817 | |||
| 815 | return 0; | 818 | return 0; |
| 816 | } | 819 | } |
| 817 | 820 | ||
| @@ -841,7 +844,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
| 841 | return error; | 844 | return error; |
| 842 | 845 | ||
| 843 | transport_configure_device(&starget->dev); | 846 | transport_configure_device(&starget->dev); |
| 847 | |||
| 844 | device_enable_async_suspend(&sdev->sdev_gendev); | 848 | device_enable_async_suspend(&sdev->sdev_gendev); |
| 849 | scsi_autopm_get_target(starget); | ||
| 850 | pm_runtime_set_active(&sdev->sdev_gendev); | ||
| 851 | pm_runtime_forbid(&sdev->sdev_gendev); | ||
| 852 | pm_runtime_enable(&sdev->sdev_gendev); | ||
| 853 | scsi_autopm_put_target(starget); | ||
| 854 | |||
| 855 | /* The following call will keep sdev active indefinitely, until | ||
| 856 | * its driver does a corresponding scsi_autopm_pm_device(). Only | ||
| 857 | * drivers supporting autosuspend will do this. | ||
| 858 | */ | ||
| 859 | scsi_autopm_get_device(sdev); | ||
| 860 | |||
| 845 | error = device_add(&sdev->sdev_gendev); | 861 | error = device_add(&sdev->sdev_gendev); |
| 846 | if (error) { | 862 | if (error) { |
| 847 | printk(KERN_INFO "error 1\n"); | 863 | printk(KERN_INFO "error 1\n"); |
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index d4549092400c..2968c6b83ddb 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
| @@ -245,6 +245,10 @@ sg_open(struct inode *inode, struct file *filp) | |||
| 245 | if (retval) | 245 | if (retval) |
| 246 | goto sg_put; | 246 | goto sg_put; |
| 247 | 247 | ||
| 248 | retval = scsi_autopm_get_device(sdp->device); | ||
| 249 | if (retval) | ||
| 250 | goto sdp_put; | ||
| 251 | |||
| 248 | if (!((flags & O_NONBLOCK) || | 252 | if (!((flags & O_NONBLOCK) || |
| 249 | scsi_block_when_processing_errors(sdp->device))) { | 253 | scsi_block_when_processing_errors(sdp->device))) { |
| 250 | retval = -ENXIO; | 254 | retval = -ENXIO; |
| @@ -302,8 +306,11 @@ sg_open(struct inode *inode, struct file *filp) | |||
| 302 | } | 306 | } |
| 303 | retval = 0; | 307 | retval = 0; |
| 304 | error_out: | 308 | error_out: |
| 305 | if (retval) | 309 | if (retval) { |
| 310 | scsi_autopm_put_device(sdp->device); | ||
| 311 | sdp_put: | ||
| 306 | scsi_device_put(sdp->device); | 312 | scsi_device_put(sdp->device); |
| 313 | } | ||
| 307 | sg_put: | 314 | sg_put: |
| 308 | if (sdp) | 315 | if (sdp) |
| 309 | sg_put_dev(sdp); | 316 | sg_put_dev(sdp); |
| @@ -327,6 +334,7 @@ sg_release(struct inode *inode, struct file *filp) | |||
| 327 | sdp->exclude = 0; | 334 | sdp->exclude = 0; |
| 328 | wake_up_interruptible(&sdp->o_excl_wait); | 335 | wake_up_interruptible(&sdp->o_excl_wait); |
| 329 | 336 | ||
| 337 | scsi_autopm_put_device(sdp->device); | ||
| 330 | kref_put(&sfp->f_ref, sg_remove_sfp); | 338 | kref_put(&sfp->f_ref, sg_remove_sfp); |
| 331 | return 0; | 339 | return 0; |
| 332 | } | 340 | } |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index d80b6dbed1ca..50cb34ffef11 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
| @@ -381,6 +381,14 @@ extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, | |||
| 381 | struct scsi_sense_hdr *, int timeout, int retries, | 381 | struct scsi_sense_hdr *, int timeout, int retries, |
| 382 | int *resid); | 382 | int *resid); |
| 383 | 383 | ||
| 384 | #ifdef CONFIG_PM_RUNTIME | ||
| 385 | extern int scsi_autopm_get_device(struct scsi_device *); | ||
| 386 | extern void scsi_autopm_put_device(struct scsi_device *); | ||
| 387 | #else | ||
| 388 | static inline int scsi_autopm_get_device(struct scsi_device *d) { return 0; } | ||
| 389 | static inline void scsi_autopm_put_device(struct scsi_device *d) {} | ||
| 390 | #endif /* CONFIG_PM_RUNTIME */ | ||
| 391 | |||
| 384 | static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) | 392 | static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) |
| 385 | { | 393 | { |
| 386 | return device_reprobe(&sdev->sdev_gendev); | 394 | return device_reprobe(&sdev->sdev_gendev); |
