Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad5bf168 authored by Can Guo's avatar Can Guo
Browse files

scsi: ufs: fix task abort due to req timeout on UFS card after removal



In card removal handler, we firstly complete all the tasks reside in host's
HW queue, then remove all the scsi devices, during which scsi layer shall
flush all the requests reside in the SW queues of these scsi devices and
return only after the queues are clean. Since the UFS card is offline, UFS
driver returns DID_BAD_TARGET to scsi layer when it tries to queue any
requests into host's HW queue. Then scsi layer returns SUCCESS to its upper
layer when it sees DID_BAD_TARGET. In this way, all the requests reside in
these SW queues can be drained clean. However, when scsi layer is draining
these SW queues, if the UFS card is inserted back online, remaining
requests in the queues shall be queued into the host's HW queue. Because
the host is already stopped by now, these requests could not be served,
thus timed out and abort happens. This change add a field to track the UFS
card removal progress. If the card is inserted back before the removal is
done, we bail out without update the card's state. We may lost one or two
insertion event(s) in the case of repeatedly aggressive hot-plug while
heavy read/write access is ongoing, but it does no harm to the stability.

Change-Id: I0972269e7f546f021fc0cdf33f7e442ac4f8a1c5
Signed-off-by: default avatarCan Guo <cang@codeaurora.org>
parent 4a3d1ca8
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -8857,6 +8857,7 @@ static void ufshcd_remove_device(struct ufs_hba *hba)
	int sdev_count = 0, i;
	unsigned long flags;

	hba->card_removal_in_progress = 1;
	ufshcd_hold_all(hba);
	/* Reset the host controller */
	spin_lock_irqsave(hba->host->host_lock, flags);
@@ -8887,6 +8888,7 @@ static void ufshcd_remove_device(struct ufs_hba *hba)
	spin_unlock_irqrestore(hba->host->host_lock, flags);

	ufshcd_release_all(hba);
	hba->card_removal_in_progress = 0;
}

static void ufshcd_card_detect_handler(struct work_struct *work)
@@ -8912,9 +8914,11 @@ static int ufshcd_card_detect_notifier(struct notifier_block *nb,
{
	struct ufs_hba *hba = container_of(nb, struct ufs_hba, card_detect_nb);

	if (event)
	if (event) {
		if (hba->card_removal_in_progress)
			goto out;
		ufshcd_set_card_online(hba);
	else
	} else
		ufshcd_set_card_offline(hba);

	if (ufshcd_is_card_offline(hba) && !hba->sdev_ufs_device)
+2 −0
Original line number Diff line number Diff line
@@ -768,6 +768,7 @@ enum ufshcd_card_state {
 * @card_detect_nb: card detector notifier registered with @extcon
 * @card_detect_work: work to exectute the card detect function
 * @card_state: card state event, enum ufshcd_card_state defines possible states
 * @card_removal_in_progress: to track card removal progress
 * @vreg_info: UFS device voltage regulator information
 * @clk_list_head: UFS host controller clocks list node head
 * @pwr_info: holds current power mode
@@ -1005,6 +1006,7 @@ struct ufs_hba {
	struct notifier_block card_detect_nb;
	struct work_struct card_detect_work;
	atomic_t card_state;
	int card_removal_in_progress;

	struct ufs_pa_layer_attr pwr_info;
	struct ufs_pwr_mode_info max_pwr_info;