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 19 static 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 35 static 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 48 static int 49 scsi_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 68 static int 69 scsi_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 84 static 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 97 static 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 103 static 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 109 static 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 115 static 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 121 static 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 127 static 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 147 static 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 166 static 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 180 static 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 195 int 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 } 206 EXPORT_SYMBOL_GPL(scsi_autopm_get_device); 207 208 void scsi_autopm_put_device(struct scsi_device *sdev) 209 { 210 pm_runtime_put_sync(&sdev->sdev_gendev); 211 } 212 EXPORT_SYMBOL_GPL(scsi_autopm_put_device); 213 214 void scsi_autopm_get_target(struct scsi_target *starget) 215 { 216 pm_runtime_get_sync(&starget->dev); 217 } 218 219 void scsi_autopm_put_target(struct scsi_target *starget) 220 { 221 pm_runtime_put_sync(&starget->dev); 222 } 223 224 int 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 236 void 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 249 const 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 }; 261