scsi_pm.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. #include <linux/pm_runtime.h>
  8. #include <scsi/scsi.h>
  9. #include <scsi/scsi_device.h>
  10. #include <scsi/scsi_driver.h>
  11. #include <scsi/scsi_host.h>
  12. #include "scsi_priv.h"
  13. static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg)
  14. {
  15. struct device_driver *drv;
  16. int err;
  17. err = scsi_device_quiesce(to_scsi_device(dev));
  18. if (err == 0) {
  19. drv = dev->driver;
  20. if (drv && drv->suspend)
  21. err = drv->suspend(dev, msg);
  22. }
  23. dev_dbg(dev, "scsi suspend: %d\n", err);
  24. return err;
  25. }
  26. static int scsi_dev_type_resume(struct device *dev)
  27. {
  28. struct device_driver *drv;
  29. int err = 0;
  30. drv = dev->driver;
  31. if (drv && drv->resume)
  32. err = drv->resume(dev);
  33. scsi_device_resume(to_scsi_device(dev));
  34. dev_dbg(dev, "scsi resume: %d\n", err);
  35. return err;
  36. }
  37. #ifdef CONFIG_PM_SLEEP
  38. static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg)
  39. {
  40. int err = 0;
  41. if (scsi_is_sdev_device(dev))
  42. err = scsi_dev_type_suspend(dev, msg);
  43. return err;
  44. }
  45. static int scsi_bus_resume_common(struct device *dev)
  46. {
  47. int err = 0;
  48. if (scsi_is_sdev_device(dev))
  49. err = scsi_dev_type_resume(dev);
  50. if (err == 0) {
  51. pm_runtime_disable(dev);
  52. pm_runtime_set_active(dev);
  53. pm_runtime_enable(dev);
  54. }
  55. return err;
  56. }
  57. static int scsi_bus_suspend(struct device *dev)
  58. {
  59. return scsi_bus_suspend_common(dev, PMSG_SUSPEND);
  60. }
  61. static int scsi_bus_freeze(struct device *dev)
  62. {
  63. return scsi_bus_suspend_common(dev, PMSG_FREEZE);
  64. }
  65. static int scsi_bus_poweroff(struct device *dev)
  66. {
  67. return scsi_bus_suspend_common(dev, PMSG_HIBERNATE);
  68. }
  69. #else /* CONFIG_PM_SLEEP */
  70. #define scsi_bus_resume_common NULL
  71. #define scsi_bus_suspend NULL
  72. #define scsi_bus_freeze NULL
  73. #define scsi_bus_poweroff NULL
  74. #endif /* CONFIG_PM_SLEEP */
  75. #ifdef CONFIG_PM_RUNTIME
  76. static int scsi_runtime_suspend(struct device *dev)
  77. {
  78. int err = 0;
  79. dev_dbg(dev, "scsi_runtime_suspend\n");
  80. if (scsi_is_sdev_device(dev)) {
  81. err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND);
  82. if (err == -EAGAIN)
  83. pm_schedule_suspend(dev, jiffies_to_msecs(
  84. round_jiffies_up_relative(HZ/10)));
  85. }
  86. /* Insert hooks here for targets, hosts, and transport classes */
  87. return err;
  88. }
  89. static int scsi_runtime_resume(struct device *dev)
  90. {
  91. int err = 0;
  92. dev_dbg(dev, "scsi_runtime_resume\n");
  93. if (scsi_is_sdev_device(dev))
  94. err = scsi_dev_type_resume(dev);
  95. /* Insert hooks here for targets, hosts, and transport classes */
  96. return err;
  97. }
  98. static int scsi_runtime_idle(struct device *dev)
  99. {
  100. int err;
  101. dev_dbg(dev, "scsi_runtime_idle\n");
  102. /* Insert hooks here for targets, hosts, and transport classes */
  103. if (scsi_is_sdev_device(dev))
  104. err = pm_schedule_suspend(dev, 100);
  105. else
  106. err = pm_runtime_suspend(dev);
  107. return err;
  108. }
  109. int scsi_autopm_get_device(struct scsi_device *sdev)
  110. {
  111. int err;
  112. err = pm_runtime_get_sync(&sdev->sdev_gendev);
  113. if (err < 0 && err !=-EACCES)
  114. pm_runtime_put_sync(&sdev->sdev_gendev);
  115. else
  116. err = 0;
  117. return err;
  118. }
  119. EXPORT_SYMBOL_GPL(scsi_autopm_get_device);
  120. void scsi_autopm_put_device(struct scsi_device *sdev)
  121. {
  122. pm_runtime_put_sync(&sdev->sdev_gendev);
  123. }
  124. EXPORT_SYMBOL_GPL(scsi_autopm_put_device);
  125. void scsi_autopm_get_target(struct scsi_target *starget)
  126. {
  127. pm_runtime_get_sync(&starget->dev);
  128. }
  129. void scsi_autopm_put_target(struct scsi_target *starget)
  130. {
  131. pm_runtime_put_sync(&starget->dev);
  132. }
  133. int scsi_autopm_get_host(struct Scsi_Host *shost)
  134. {
  135. int err;
  136. err = pm_runtime_get_sync(&shost->shost_gendev);
  137. if (err < 0 && err !=-EACCES)
  138. pm_runtime_put_sync(&shost->shost_gendev);
  139. else
  140. err = 0;
  141. return err;
  142. }
  143. void scsi_autopm_put_host(struct Scsi_Host *shost)
  144. {
  145. pm_runtime_put_sync(&shost->shost_gendev);
  146. }
  147. #else
  148. #define scsi_runtime_suspend NULL
  149. #define scsi_runtime_resume NULL
  150. #define scsi_runtime_idle NULL
  151. #endif /* CONFIG_PM_RUNTIME */
  152. const struct dev_pm_ops scsi_bus_pm_ops = {
  153. .suspend = scsi_bus_suspend,
  154. .resume = scsi_bus_resume_common,
  155. .freeze = scsi_bus_freeze,
  156. .thaw = scsi_bus_resume_common,
  157. .poweroff = scsi_bus_poweroff,
  158. .restore = scsi_bus_resume_common,
  159. .runtime_suspend = scsi_runtime_suspend,
  160. .runtime_resume = scsi_runtime_resume,
  161. .runtime_idle = scsi_runtime_idle,
  162. };