scsi: ufs: ufshpb: Add HPB dev reset response
authorAvri Altman <avri.altman@wdc.com>
Mon, 12 Jul 2021 09:50:34 +0000 (12:50 +0300)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sun, 1 Aug 2021 20:05:15 +0000 (16:05 -0400)
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>
drivers/scsi/ufs/ufshpb.c
drivers/scsi/ufs/ufshpb.h

index e71fe6e..8b03f34 100644 (file)
@@ -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);
 }
 
index 0204e4f..43a95c6 100644 (file)
@@ -127,6 +127,7 @@ struct ufshpb_region {
        struct list_head list_lru_rgn;
        unsigned long rgn_flags;
 #define RGN_FLAG_DIRTY 0
+#define RGN_FLAG_UPDATE 1
 
        /* region reads - for host mode */
        spinlock_t rgn_lock;