Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.9-rc6 260 lines 5.9 kB view raw
1/* 2 * scsi_pm.c Copyright (C) 2010 Alan Stern 3 * 4 * SCSI dynamic Power Management 5 * Initial version: Alan Stern <stern@rowland.harvard.edu> 6 */ 7 8#include <linux/pm_runtime.h> 9#include <linux/export.h> 10#include <linux/async.h> 11 12#include <scsi/scsi.h> 13#include <scsi/scsi_device.h> 14#include <scsi/scsi_driver.h> 15#include <scsi/scsi_host.h> 16 17#include "scsi_priv.h" 18 19static int scsi_dev_type_suspend(struct device *dev, int (*cb)(struct device *)) 20{ 21 int err; 22 23 err = scsi_device_quiesce(to_scsi_device(dev)); 24 if (err == 0) { 25 if (cb) { 26 err = cb(dev); 27 if (err) 28 scsi_device_resume(to_scsi_device(dev)); 29 } 30 } 31 dev_dbg(dev, "scsi suspend: %d\n", err); 32 return err; 33} 34 35static int scsi_dev_type_resume(struct device *dev, int (*cb)(struct device *)) 36{ 37 int err = 0; 38 39 if (cb) 40 err = cb(dev); 41 scsi_device_resume(to_scsi_device(dev)); 42 dev_dbg(dev, "scsi resume: %d\n", err); 43 return err; 44} 45 46#ifdef CONFIG_PM_SLEEP 47 48static int 49scsi_bus_suspend_common(struct device *dev, int (*cb)(struct device *)) 50{ 51 int err = 0; 52 53 if (scsi_is_sdev_device(dev)) { 54 /* 55 * All the high-level SCSI drivers that implement runtime 56 * PM treat runtime suspend, system suspend, and system 57 * hibernate identically. 58 */ 59 if (pm_runtime_suspended(dev)) 60 return 0; 61 62 err = scsi_dev_type_suspend(dev, cb); 63 } 64 65 return err; 66} 67 68static int 69scsi_bus_resume_common(struct device *dev, int (*cb)(struct device *)) 70{ 71 int err = 0; 72 73 if (scsi_is_sdev_device(dev)) 74 err = scsi_dev_type_resume(dev, cb); 75 76 if (err == 0) { 77 pm_runtime_disable(dev); 78 pm_runtime_set_active(dev); 79 pm_runtime_enable(dev); 80 } 81 return err; 82} 83 84static int scsi_bus_prepare(struct device *dev) 85{ 86 if (scsi_is_sdev_device(dev)) { 87 /* sd probing uses async_schedule. Wait until it finishes. */ 88 async_synchronize_full_domain(&scsi_sd_probe_domain); 89 90 } else if (scsi_is_host_device(dev)) { 91 /* Wait until async scanning is finished */ 92 scsi_complete_async_scans(); 93 } 94 return 0; 95} 96 97static int scsi_bus_suspend(struct device *dev) 98{ 99 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 100 return scsi_bus_suspend_common(dev, pm ? pm->suspend : NULL); 101} 102 103static int scsi_bus_resume(struct device *dev) 104{ 105 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 106 return scsi_bus_resume_common(dev, pm ? pm->resume : NULL); 107} 108 109static int scsi_bus_freeze(struct device *dev) 110{ 111 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 112 return scsi_bus_suspend_common(dev, pm ? pm->freeze : NULL); 113} 114 115static int scsi_bus_thaw(struct device *dev) 116{ 117 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 118 return scsi_bus_resume_common(dev, pm ? pm->thaw : NULL); 119} 120 121static int scsi_bus_poweroff(struct device *dev) 122{ 123 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 124 return scsi_bus_suspend_common(dev, pm ? pm->poweroff : NULL); 125} 126 127static int scsi_bus_restore(struct device *dev) 128{ 129 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 130 return scsi_bus_resume_common(dev, pm ? pm->restore : NULL); 131} 132 133#else /* CONFIG_PM_SLEEP */ 134 135#define scsi_bus_prepare NULL 136#define scsi_bus_suspend NULL 137#define scsi_bus_resume NULL 138#define scsi_bus_freeze NULL 139#define scsi_bus_thaw NULL 140#define scsi_bus_poweroff NULL 141#define scsi_bus_restore NULL 142 143#endif /* CONFIG_PM_SLEEP */ 144 145#ifdef CONFIG_PM_RUNTIME 146 147static int scsi_runtime_suspend(struct device *dev) 148{ 149 int err = 0; 150 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 151 152 dev_dbg(dev, "scsi_runtime_suspend\n"); 153 if (scsi_is_sdev_device(dev)) { 154 err = scsi_dev_type_suspend(dev, 155 pm ? pm->runtime_suspend : NULL); 156 if (err == -EAGAIN) 157 pm_schedule_suspend(dev, jiffies_to_msecs( 158 round_jiffies_up_relative(HZ/10))); 159 } 160 161 /* Insert hooks here for targets, hosts, and transport classes */ 162 163 return err; 164} 165 166static int scsi_runtime_resume(struct device *dev) 167{ 168 int err = 0; 169 const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; 170 171 dev_dbg(dev, "scsi_runtime_resume\n"); 172 if (scsi_is_sdev_device(dev)) 173 err = scsi_dev_type_resume(dev, pm ? pm->runtime_resume : NULL); 174 175 /* Insert hooks here for targets, hosts, and transport classes */ 176 177 return err; 178} 179 180static int scsi_runtime_idle(struct device *dev) 181{ 182 int err; 183 184 dev_dbg(dev, "scsi_runtime_idle\n"); 185 186 /* Insert hooks here for targets, hosts, and transport classes */ 187 188 if (scsi_is_sdev_device(dev)) 189 err = pm_schedule_suspend(dev, 100); 190 else 191 err = pm_runtime_suspend(dev); 192 return err; 193} 194 195int scsi_autopm_get_device(struct scsi_device *sdev) 196{ 197 int err; 198 199 err = pm_runtime_get_sync(&sdev->sdev_gendev); 200 if (err < 0 && err !=-EACCES) 201 pm_runtime_put_sync(&sdev->sdev_gendev); 202 else 203 err = 0; 204 return err; 205} 206EXPORT_SYMBOL_GPL(scsi_autopm_get_device); 207 208void scsi_autopm_put_device(struct scsi_device *sdev) 209{ 210 pm_runtime_put_sync(&sdev->sdev_gendev); 211} 212EXPORT_SYMBOL_GPL(scsi_autopm_put_device); 213 214void scsi_autopm_get_target(struct scsi_target *starget) 215{ 216 pm_runtime_get_sync(&starget->dev); 217} 218 219void scsi_autopm_put_target(struct scsi_target *starget) 220{ 221 pm_runtime_put_sync(&starget->dev); 222} 223 224int scsi_autopm_get_host(struct Scsi_Host *shost) 225{ 226 int err; 227 228 err = pm_runtime_get_sync(&shost->shost_gendev); 229 if (err < 0 && err !=-EACCES) 230 pm_runtime_put_sync(&shost->shost_gendev); 231 else 232 err = 0; 233 return err; 234} 235 236void scsi_autopm_put_host(struct Scsi_Host *shost) 237{ 238 pm_runtime_put_sync(&shost->shost_gendev); 239} 240 241#else 242 243#define scsi_runtime_suspend NULL 244#define scsi_runtime_resume NULL 245#define scsi_runtime_idle NULL 246 247#endif /* CONFIG_PM_RUNTIME */ 248 249const struct dev_pm_ops scsi_bus_pm_ops = { 250 .prepare = scsi_bus_prepare, 251 .suspend = scsi_bus_suspend, 252 .resume = scsi_bus_resume, 253 .freeze = scsi_bus_freeze, 254 .thaw = scsi_bus_thaw, 255 .poweroff = scsi_bus_poweroff, 256 .restore = scsi_bus_restore, 257 .runtime_suspend = scsi_runtime_suspend, 258 .runtime_resume = scsi_runtime_resume, 259 .runtime_idle = scsi_runtime_idle, 260};