The ufs driver calls scsi_device_get() in ufshcd_set_dev_pwr_mode()
in order to avoid manual delete of UFS device W-LUN by holding the
reference.

But scsi_device_get() has been changed to fail when the LLD module is
in the process of being unloaded.  So it no longer doesn't work if the
module is unloaded while the device is runtime suspended.
(i.e. driver_detach -> ... pm_runtime_get_sync() ... ->
ufshcd_runtime_resume -> ufshcd_resume -> ufshcd_set_dev_pwr_mode ->
scsi_device_get -> try_module_get -> return -ENXIO)

As the reason for scsi_device_get() is to avoid manual delete of UFS
device W-LUN, this acquires shost->scan_mutex lock instead of
scsi_device_get() to work around the problem.

Signed-off-by: Akinobu Mita <[email protected]>
Cc: Vinayak Holikatti <[email protected]>
Cc: "James E.J. Bottomley" <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Dolev Raviv <[email protected]>
Cc: Sujit Reddy Thumma <[email protected]>
Cc: Akinobu Mita <[email protected]>
Cc: Subhash Jadavani <[email protected]>
Cc: Sahitya Tummala <[email protected]>
Cc: Yaniv Gardi <[email protected]>
Cc: [email protected]
---
 drivers/scsi/ufs/ufshcd.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d425816..d287207 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4792,23 +4792,19 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
        struct scsi_sense_hdr sshdr;
        struct scsi_device *sdp;
        unsigned long flags;
-       int ret;
+       int ret = 0;
 
+       mutex_lock(&hba->host->scan_mutex);
        spin_lock_irqsave(hba->host->host_lock, flags);
        sdp = hba->sdev_ufs_device;
-       if (sdp) {
-               ret = scsi_device_get(sdp);
-               if (!ret && !scsi_device_online(sdp)) {
-                       ret = -ENODEV;
-                       scsi_device_put(sdp);
-               }
-       } else {
+       if (!sdp || !scsi_device_online(sdp))
                ret = -ENODEV;
-       }
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
-       if (ret)
+       if (ret) {
+               mutex_unlock(&hba->host->scan_mutex);
                return ret;
+       }
 
        /*
         * If scsi commands fail, the scsi mid-layer schedules scsi error-
@@ -4845,7 +4841,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
        if (!ret)
                hba->curr_dev_pwr_mode = pwr_mode;
 out:
-       scsi_device_put(sdp);
+       mutex_unlock(&hba->host->scan_mutex);
        hba->host->eh_noresume = 0;
        return ret;
 }
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to