summaryrefslogtreecommitdiff
path: root/drivers/scsi/ufs/ufshpb.c
diff options
context:
space:
mode:
authorAvri Altman <avri.altman@wdc.com>2021-07-12 12:50:34 +0300
committerMartin K. Petersen <martin.petersen@oracle.com>2021-08-01 16:05:15 -0400
commit67001ff171cb4ae79774cdd13dc1d00cbfdbab66 (patch)
tree10d537222c54d2bd42fe59035e3f4b533ed392c0 /drivers/scsi/ufs/ufshpb.c
parent6f4ad14f0fb9f0e6809057a46489ef3ad3a274ab (diff)
scsi: ufs: ufshpb: Add HPB dev reset response
The spec does not define what the host's recommended response is when the device sends HPB dev reset response (oper 0x2). Update all active HPB regions. Link: https://lore.kernel.org/r/20210712095039.8093-8-avri.altman@wdc.com Reviewed-by: Daejun Park <daejun7.park@samsung.com> Signed-off-by: Avri Altman <avri.altman@wdc.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/ufs/ufshpb.c')
-rw-r--r--drivers/scsi/ufs/ufshpb.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index e71fe6e31366..8b03f34897b2 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -196,7 +196,8 @@ next_srgn:
}
spin_unlock(&rgn->rgn_lock);
- if (activate) {
+ if (activate ||
+ test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
spin_lock_irqsave(&hpb->rsp_list_lock, flags);
ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
@@ -1412,6 +1413,20 @@ out:
queue_work(ufshpb_wq, &hpb->map_work);
}
+static void ufshpb_dev_reset_handler(struct ufshpb_lu *hpb)
+{
+ struct victim_select_info *lru_info = &hpb->lru_info;
+ struct ufshpb_region *rgn;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hpb->rgn_state_lock, flags);
+
+ list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
+ set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
+
+ spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
+}
+
/*
* This function will parse recommended active subregion information in sense
* data field of response UPIU with SAM_STAT_GOOD state.
@@ -1486,6 +1501,18 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
case HPB_RSP_DEV_RESET:
dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
"UFS device lost HPB information during PM.\n");
+
+ if (hpb->is_hcm) {
+ struct scsi_device *sdev;
+
+ __shost_for_each_device(sdev, hba->host) {
+ struct ufshpb_lu *h = sdev->hostdata;
+
+ if (h)
+ ufshpb_dev_reset_handler(h);
+ }
+ }
+
break;
default:
dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
@@ -1811,6 +1838,8 @@ static int ufshpb_alloc_region_tbl(struct ufs_hba *hba, struct ufshpb_lu *hpb)
} else {
rgn->rgn_state = HPB_RGN_INACTIVE;
}
+
+ rgn->rgn_flags = 0;
}
return 0;
@@ -2138,6 +2167,7 @@ static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
{
if (hpb->is_hcm)
cancel_work_sync(&hpb->ufshpb_normalization_work);
+
cancel_work_sync(&hpb->map_work);
}