scsi: ufs: ufshpb: Properly handle max-single-cmd
authorAvri Altman <avri.altman@wdc.com>
Sun, 31 Oct 2021 12:36:54 +0000 (14:36 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 4 Nov 2021 01:51:56 +0000 (21:51 -0400)
The spec recommends that for transfer length larger than the max-single-cmd
attribute (bMAX_DATA_SIZE_FOR_HPB_SINGLE_CMD) it is possible to couple
pre-requests with the HPB-READ command.  Being a recommendation, using
pre-requests can be perceived merely as a means of optimization.  A common
practice was to send pre-requests for chunks within some interval, and
leave the READ10 untouched if larger.

Now that the pre-request flows have been removed, all the commands are
single commands.  Properly handle this attribute and do not send HPB-READ
for transfer lengths larger than max-single-cmd.

[mkp: resolve conflict]

Fixes: 09d9e4d04187 ("scsi: ufs: ufshpb: Remove HPB2.0 flows")
Link: https://lore.kernel.org/r/20211031123654.17719-1-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 3b1a90b..a86d0cc 100644 (file)
@@ -394,8 +394,6 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
        if (!ufshpb_is_supported_chunk(hpb, transfer_len))
                return 0;
 
-       WARN_ON_ONCE(transfer_len > HPB_MULTI_CHUNK_HIGH);
-
        if (hpb->is_hcm) {
                /*
                 * in host control mode, reads are the main source for
@@ -1572,7 +1570,7 @@ static void ufshpb_lu_parameter_init(struct ufs_hba *hba,
        if (ufshpb_is_legacy(hba))
                hpb->pre_req_max_tr_len = HPB_LEGACY_CHUNK_HIGH;
        else
-               hpb->pre_req_max_tr_len = HPB_MULTI_CHUNK_HIGH;
+               hpb->pre_req_max_tr_len = hpb_dev_info->max_hpb_single_cmd;
 
        hpb->lu_pinned_start = hpb_lu_info->pinned_start;
        hpb->lu_pinned_end = hpb_lu_info->num_pinned ?
@@ -2582,7 +2580,7 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
 {
        struct ufshpb_dev_info *hpb_dev_info = &hba->ufshpb_dev;
        int version, ret;
-       u32 max_hpb_single_cmd = HPB_MULTI_CHUNK_LOW;
+       int max_single_cmd;
 
        hpb_dev_info->control_mode = desc_buf[DEVICE_DESC_PARAM_HPB_CONTROL];
 
@@ -2598,18 +2596,22 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
        if (version == HPB_SUPPORT_LEGACY_VERSION)
                hpb_dev_info->is_legacy = true;
 
-       ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
-               QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_hpb_single_cmd);
-       if (ret)
-               dev_err(hba->dev, "%s: idn: read max size of single hpb cmd query request failed",
-                       __func__);
-       hpb_dev_info->max_hpb_single_cmd = max_hpb_single_cmd;
-
        /*
         * Get the number of user logical unit to check whether all
         * scsi_device finish initialization
         */
        hpb_dev_info->num_lu = desc_buf[DEVICE_DESC_PARAM_NUM_LU];
+
+       if (hpb_dev_info->is_legacy)
+               return;
+
+       ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+               QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_single_cmd);
+
+       if (ret)
+               hpb_dev_info->max_hpb_single_cmd = HPB_LEGACY_CHUNK_HIGH;
+       else
+               hpb_dev_info->max_hpb_single_cmd = min(max_single_cmd + 1, HPB_MULTI_CHUNK_HIGH);
 }
 
 void ufshpb_init(struct ufs_hba *hba)
index f15d8fd..b475dbd 100644 (file)
@@ -31,7 +31,6 @@
 
 /* hpb support chunk size */
 #define HPB_LEGACY_CHUNK_HIGH                  1
-#define HPB_MULTI_CHUNK_LOW                    7
 #define HPB_MULTI_CHUNK_HIGH                   255
 
 /* hpb vender defined opcode */