Merge tag 'vboxsf-v6.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/hansg...
[linux-block.git] / drivers / scsi / scsi_scan.c
index 8d06475de17a33a26921a1ff70c57f759986973f..ffd7e7e72933c52255e06acfaa967f2ea4b8b64e 100644 (file)
@@ -1642,6 +1642,40 @@ int scsi_add_device(struct Scsi_Host *host, uint channel,
 }
 EXPORT_SYMBOL(scsi_add_device);
 
+int scsi_resume_device(struct scsi_device *sdev)
+{
+       struct device *dev = &sdev->sdev_gendev;
+       int ret = 0;
+
+       device_lock(dev);
+
+       /*
+        * Bail out if the device or its queue are not running. Otherwise,
+        * the rescan may block waiting for commands to be executed, with us
+        * holding the device lock. This can result in a potential deadlock
+        * in the power management core code when system resume is on-going.
+        */
+       if (sdev->sdev_state != SDEV_RUNNING ||
+           blk_queue_pm_only(sdev->request_queue)) {
+               ret = -EWOULDBLOCK;
+               goto unlock;
+       }
+
+       if (dev->driver && try_module_get(dev->driver->owner)) {
+               struct scsi_driver *drv = to_scsi_driver(dev->driver);
+
+               if (drv->resume)
+                       ret = drv->resume(dev);
+               module_put(dev->driver->owner);
+       }
+
+unlock:
+       device_unlock(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL(scsi_resume_device);
+
 int scsi_rescan_device(struct scsi_device *sdev)
 {
        struct device *dev = &sdev->sdev_gendev;