scsi: ufs: core: Add L2P entry swap quirk for Micron UFS
authorBean Huo <beanhuo@micron.com>
Wed, 4 Aug 2021 18:21:27 +0000 (20:21 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 6 Aug 2021 03:21:08 +0000 (23:21 -0400)
For Micron UFS devices the L2P entry need to be byteswapped before sending
an HPB READ command to the UFS device. Add the quirk
UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ to address this.

Link: https://lore.kernel.org/r/20210804182128.458356-2-huobean@gmail.com
Reviewed-by: Avri Altman <avri.altman@wdc.com>
Signed-off-by: Bean Huo <beanhuo@micron.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/ufs/ufs_quirks.h
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshpb.c

index 07f559a..35ec9ea 100644 (file)
@@ -116,4 +116,10 @@ struct ufs_dev_fix {
  */
 #define UFS_DEVICE_QUIRK_DELAY_AFTER_LPM        (1 << 11)
 
+/*
+ * Some UFS devices require L2P entry should be swapped before being sent to the
+ * UFS device for HPB READ command.
+ */
+#define UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ (1 << 12)
+
 #endif /* UFS_QUIRKS_H_ */
index d964092..6c263e9 100644 (file)
@@ -199,7 +199,8 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
 static struct ufs_dev_fix ufs_fixups[] = {
        /* UFS cards deviations table */
        UFS_FIX(UFS_VENDOR_MICRON, UFS_ANY_MODEL,
-               UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
+               UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
+               UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ),
        UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
                UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
                UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE |
index 54e8e01..d0eb14b 100644 (file)
@@ -323,15 +323,19 @@ ufshpb_get_pos_from_lpn(struct ufshpb_lu *hpb, unsigned long lpn, int *rgn_idx,
 }
 
 static void
-ufshpb_set_hpb_read_to_upiu(struct ufshpb_lu *hpb, struct ufshcd_lrb *lrbp,
-                           u32 lpn, __be64 ppn, u8 transfer_len, int read_id)
+ufshpb_set_hpb_read_to_upiu(struct ufs_hba *hba, struct ufshpb_lu *hpb,
+                           struct ufshcd_lrb *lrbp, u32 lpn, __be64 ppn,
+                           u8 transfer_len, int read_id)
 {
        unsigned char *cdb = lrbp->cmd->cmnd;
-
+       __be64 ppn_tmp = ppn;
        cdb[0] = UFSHPB_READ;
 
+       if (hba->dev_quirks & UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ)
+               ppn_tmp = swab64(ppn);
+
        /* ppn value is stored as big-endian in the host memory */
-       memcpy(&cdb[6], &ppn, sizeof(__be64));
+       memcpy(&cdb[6], &ppn_tmp, sizeof(__be64));
        cdb[14] = transfer_len;
        cdb[15] = read_id;
 
@@ -689,7 +693,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
                }
        }
 
-       ufshpb_set_hpb_read_to_upiu(hpb, lrbp, lpn, ppn, transfer_len, read_id);
+       ufshpb_set_hpb_read_to_upiu(hba, hpb, lrbp, lpn, ppn, transfer_len,
+                                   read_id);
 
        hpb->stats.hit_cnt++;
        return 0;