scsi: ufs: Stop using the clock scaling lock in the error handler
authorBart Van Assche <bvanassche@acm.org>
Fri, 3 Dec 2021 23:19:48 +0000 (15:19 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 Jan 2023 10:48:53 +0000 (11:48 +0100)
[ Upstream commit 5675c381ea51360b4968b78f23aefda73e3de90d ]

Instead of locking and unlocking the clock scaling lock, surround the
command queueing code with an RCU reader lock and call synchronize_rcu().
This patch prepares for removal of the clock scaling lock.

Link: https://lore.kernel.org/r/20211203231950.193369-16-bvanassche@acm.org
Tested-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Bean Huo <beanhuo@micron.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Stable-dep-of: 1a5665fc8d7a ("scsi: ufs: core: WLUN suspend SSU/enter hibern8 fail recovery")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/scsi/ufs/ufshcd.c

index a428b81..6dd3416 100644 (file)
@@ -2700,6 +2700,12 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        if (!down_read_trylock(&hba->clk_scaling_lock))
                return SCSI_MLQUEUE_HOST_BUSY;
 
+       /*
+        * Allows the UFS error handler to wait for prior ufshcd_queuecommand()
+        * calls.
+        */
+       rcu_read_lock();
+
        switch (hba->ufshcd_state) {
        case UFSHCD_STATE_OPERATIONAL:
        case UFSHCD_STATE_EH_SCHEDULED_NON_FATAL:
@@ -2766,7 +2772,10 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        }
 
        ufshcd_send_command(hba, tag);
+
 out:
+       rcu_read_unlock();
+
        up_read(&hba->clk_scaling_lock);
 
        if (ufs_trigger_eh()) {
@@ -5952,8 +5961,7 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
        }
        ufshcd_scsi_block_requests(hba);
        /* Drain ufshcd_queuecommand() */
-       down_write(&hba->clk_scaling_lock);
-       up_write(&hba->clk_scaling_lock);
+       synchronize_rcu();
        cancel_work_sync(&hba->eeh_work);
 }