This patch fix failure to read the string descriptor.
In kernel v4.9.100,we encountered the following error info:
[3.141326] ufshcd-hi3660 ff3b0000.ufs: ufshcd_read_desc_param: Failed reading descriptor. desc_id 0 param_offset 0 buff_len 31 ret 0 [3.141331] ufshcd-hi3660 ff3b0000.ufs: ufs_get_device_info: Failed reading Device Desc. err = -22 [3.141336] ufshcd-hi3660 ff3b0000.ufs: ufs_advertise_fixup_device: Failed getting device info. err = -22 [3.145923] ufs final power mode: gear = 3, lane = 2, pwr = 1, rate = 2 [3.145927] ufshcd-hi3660 ff3b0000.ufs: set TX_EQUALIZER 3.5db [3.157229] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane0 = 0x1 [3.157716] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane1 = 0x1 [3.190446] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.227484] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.263496] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.299509] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.335528] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.371501] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.407493] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.443501] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.479491] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11
If failed to read device desc, card_data->wmanufacturerid and card_data->model will not get the correct value, meaning that hba->dev_quirks will no longer work. And some ufs device's quirks handling will even cause ufs can't work. In fact, our hikey960 board using Hynix ufs device failed to initialize on v4.9 because a quirk of the hynix device was not handled.
We test with hikey960 & hikey970 boards in aosp-master hikey-linaro-4.9 (v4.9.100), this patch can solve the above problem perfectly.
[3.223550] ufs final power mode: gear = 3, lane = 2, pwr = 1, rate = 2 [3.223565] ufshcd-hi3660 ff3b0000.ufs: set TX_EQUALIZER 3.5db [3.223609] ufs flash device must set VS_DebugSaveConfigTime 0x10 [3.226218] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane0 = 0x1 [3.226247] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane1 = 0x1 [3.226400] ufshcd-hi3660 ff3b0000.ufs: ufshcd_find_max_sup_active_icc_level: Regulator capability was not set, actvIccLevel=0 [3.232847] scsi 0:0:0:49488: Well-known LUN SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.321453] scsi 0:0:0:49456: Well-known LUN SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.383820] scsi 0:0:0:49476: Well-known LUN SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.447615] scsi 0:0:0:0: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.503504] sd 0:0:0:0: [sda] 1024 4096-byte logical blocks: (4.19 MB/4.00 MiB) [3.503863] sd 0:0:0:0: [sda] Write Protect is off [3.503867] sd 0:0:0:0: [sda] Mode Sense: 00 32 00 10 [3.503963] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.504017] scsi 0:0:0:1: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.505615] sd 0:0:0:0: [sda] Attached SCSI disk [3.547425] sd 0:0:0:1: [sdb] 1024 4096-byte logical blocks: (4.19 MB/4.00 MiB) [3.547768] scsi 0:0:0:2: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.548003] sd 0:0:0:1: [sdb] Write Protect is off [3.548005] sd 0:0:0:1: [sdb] Mode Sense: 00 32 00 10 [3.548428] sd 0:0:0:1: [sdb] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.553383] sd 0:0:0:1: [sdb] Attached SCSI disk [3.591547] sd 0:0:0:2: [sdc] 2048 4096-byte logical blocks: (8.39 MB/8.00 MiB) [3.592056] scsi 0:0:0:3: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.593336] sd 0:0:0:2: [sdc] Write Protect is off [3.593340] sd 0:0:0:2: [sdc] Mode Sense: 00 32 00 10 [3.593638] sd 0:0:0:2: [sdc] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.596473] Alternate GPT is invalid, using primary GPT. [3.596480] sdc: sdc1 [3.597069] random: fast init done [3.597168] sd 0:0:0:2: [sdc] Attached SCSI disk [3.644460] sd 0:0:0:3: [sdd] 7805952 4096-byte logical blocks: (32.0 GB/29.8 GiB) [3.644867] sd 0:0:0:3: [sdd] Write Protect is off [3.644869] sd 0:0:0:3: [sdd] Mode Sense: 00 32 00 10 [3.644992] sd 0:0:0:3: [sdd] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.646506] Alternate GPT is invalid, using primary GPT. [3.646518] sdd: sdd1 sdd2 sdd3 sdd4 sdd5 sdd6 sdd7 sdd8 sdd9 sdd10 sdd11 sdd12 sdd13 [3.647956] sd 0:0:0:3: [sdd] Attached SCSI disk
We hope merge this patch to 4.9-stable to avoid other similar problems.
Potomski, MichalX (1): scsi: ufs: Factor out ufshcd_read_desc_param
Tomas Winkler (1): scsi: ufs: refactor device descriptor reading
subhashj@codeaurora.org (1): scsi: ufs: fix failure to read the string descriptor
drivers/scsi/ufs/ufs.h | 34 +++--- drivers/scsi/ufs/ufs_quirks.h | 28 +---- drivers/scsi/ufs/ufshcd.c | 272 +++++++++++++++++++++++++++++++----------- drivers/scsi/ufs/ufshcd.h | 16 +++ 4 files changed, 246 insertions(+), 104 deletions(-)
From: "subhashj@codeaurora.org" subhashj@codeaurora.org
[ Upstream commit bde44bb665d049468b6a1a2fa7d666434de4f83f ]
While reading variable size descriptors (like string descriptor), some UFS devices may report the "LENGTH" (field in "Transaction Specific fields" of Query Response UPIU) same as what was requested in Query Request UPIU instead of reporting the actual size of the variable size descriptor. Although it's safe to ignore the "LENGTH" field for variable size descriptors as we can always derive the length of the descriptor from the descriptor header fields. Hence this change impose the length match check only for fixed size descriptors (for which we always request the correct size as part of Query Request UPIU).
[Wei Li: Slight tweaks to get the cherry-pick to apply,resolved collisions.]
Reviewed-by: Venkat Gopalakrishnan venkatg@codeaurora.org Signed-off-by: Subhash Jadavani subhashj@codeaurora.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Li Wei liwei213@huawei.com --- drivers/scsi/ufs/ufshcd.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 98a7111dd53f..a4fee1e4fdda 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2086,15 +2086,38 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba, desc_id, desc_index, 0, desc_buf, &buff_len);
- if (ret || (buff_len < ufs_query_desc_max_size[desc_id]) || - (desc_buf[QUERY_DESC_LENGTH_OFFSET] != - ufs_query_desc_max_size[desc_id]) - || (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id)) { - dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d param_offset %d buff_len %d ret %d", - __func__, desc_id, param_offset, buff_len, ret); - if (!ret) - ret = -EINVAL; + if (ret) { + dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", + __func__, desc_id, desc_index, param_offset, ret); + + goto out; + } + + /* Sanity check */ + if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { + dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header", + __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); + ret = -EINVAL; + goto out; + }
+ /* + * While reading variable size descriptors (like string descriptor), + * some UFS devices may report the "LENGTH" (field in "Transaction + * Specific fields" of Query Response UPIU) same as what was requested + * in Query Request UPIU instead of reporting the actual size of the + * variable size descriptor. + * Although it's safe to ignore the "LENGTH" field for variable size + * descriptors as we can always derive the length of the descriptor from + * the descriptor header fields. Hence this change impose the length + * match check only for fixed size descriptors (for which we always + * request the correct size as part of Query Request UPIU). + */ + if ((desc_id != QUERY_DESC_IDN_STRING) && + (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) { + dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d", + __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]); + ret = -EINVAL; goto out; }
From: Tomas Winkler tomas.winkler@intel.com
[ Upstream commit 93fdd5ac64bbe80dac6416f048405362d7ef0945 ]
Pull device descriptor reading out of ufs quirk so it can be used also for other purposes.
Revamp the fixup setup:
1. Rename ufs_device_info to ufs_dev_desc as very similar name ufs_dev_info is already in use.
2. Make the handlers static as they are not used out of the ufshdc.c file.
[mkp: applied by hand]
Signed-off-by: Tomas Winkler tomas.winkler@intel.com Reviewed-by: Subhash Jadavani subhashj@codeaurora.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Li Wei liwei213@huawei.com --- drivers/scsi/ufs/ufs.h | 12 ++++++++++++ drivers/scsi/ufs/ufs_quirks.h | 28 ++++++---------------------- drivers/scsi/ufs/ufshcd.c | 40 +++++++++++++++++++--------------------- 3 files changed, 37 insertions(+), 43 deletions(-)
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 845b874e2977..377ba30c2258 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -522,4 +522,16 @@ struct ufs_dev_info { bool is_lu_power_on_wp; };
+#define MAX_MODEL_LEN 16 +/** + * ufs_dev_desc - ufs device details from the device descriptor + * + * @wmanufacturerid: card details + * @model: card model + */ +struct ufs_dev_desc { + u16 wmanufacturerid; + char model[MAX_MODEL_LEN + 1]; +}; + #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 08b799d4efcc..71f73d1d1ad1 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -21,41 +21,28 @@ #define UFS_ANY_VENDOR 0xFFFF #define UFS_ANY_MODEL "ANY_MODEL"
-#define MAX_MODEL_LEN 16 - #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD
-/** - * ufs_device_info - ufs device details - * @wmanufacturerid: card details - * @model: card model - */ -struct ufs_device_info { - u16 wmanufacturerid; - char model[MAX_MODEL_LEN + 1]; -}; - /** * ufs_dev_fix - ufs device quirk info * @card: ufs card details * @quirk: device quirk */ struct ufs_dev_fix { - struct ufs_device_info card; + struct ufs_dev_desc card; unsigned int quirk; };
#define END_FIX { { 0 }, 0 }
/* add specific device quirk */ -#define UFS_FIX(_vendor, _model, _quirk) \ - { \ - .card.wmanufacturerid = (_vendor),\ - .card.model = (_model), \ - .quirk = (_quirk), \ - } +#define UFS_FIX(_vendor, _model, _quirk) { \ + .card.wmanufacturerid = (_vendor),\ + .card.model = (_model), \ + .quirk = (_quirk), \ +}
/* * If UFS device is having issue in processing LCC (Line Control @@ -144,7 +131,4 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8)
-struct ufs_hba; -void ufs_advertise_fixup_device(struct ufs_hba *hba); - #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index a4fee1e4fdda..50aa1a5726b8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4906,8 +4906,8 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) return ret; }
-static int ufs_get_device_info(struct ufs_hba *hba, - struct ufs_device_info *card_data) +static int ufs_get_device_desc(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { int err; u8 model_index; @@ -4926,7 +4926,7 @@ static int ufs_get_device_info(struct ufs_hba *hba, * getting vendor (manufacturerID) and Bank Index in big endian * format */ - card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; @@ -4940,36 +4940,26 @@ static int ufs_get_device_info(struct ufs_hba *hba, }
str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; - strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), + strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN));
/* Null terminate the model string */ - card_data->model[MAX_MODEL_LEN] = '\0'; + dev_desc->model[MAX_MODEL_LEN] = '\0';
out: return err; }
-void ufs_advertise_fixup_device(struct ufs_hba *hba) +static void ufs_fixup_device_setup(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) { - int err; struct ufs_dev_fix *f; - struct ufs_device_info card_data; - - card_data.wmanufacturerid = 0; - - err = ufs_get_device_info(hba, &card_data); - if (err) { - dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", - __func__, err); - return; - }
for (f = ufs_fixups; f->quirk; f++) { - if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || - (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && - (STR_PRFX_EQUAL(f->card.model, card_data.model) || + if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid || + f->card.wmanufacturerid == UFS_ANY_VENDOR) && + (STR_PRFX_EQUAL(f->card.model, dev_desc->model) || !strcmp(f->card.model, UFS_ANY_MODEL))) hba->dev_quirks |= f->quirk; } @@ -5147,6 +5137,7 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) */ static int ufshcd_probe_hba(struct ufs_hba *hba) { + struct ufs_dev_desc card = {0}; int ret;
ret = ufshcd_link_startup(hba); @@ -5170,7 +5161,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out;
- ufs_advertise_fixup_device(hba); + ret = ufs_get_device_desc(hba, &card); + if (ret) { + dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", + __func__, ret); + goto out; + } + + ufs_fixup_device_setup(hba, &card); ufshcd_tune_unipro_params(hba);
ret = ufshcd_set_vccq_rail_unused(hba,
From: "Potomski, MichalX" michalx.potomski@intel.com
[ Upstream commit a4b0e8a4e92b1baa860e744847fbdb84a50a5071 ]
Since in UFS 2.1 specification some of the descriptor lengths differs from 2.0 specification and some devices, which are reporting spec version 2.0 have different descriptor lengths we can not rely on hardcoded values taken from 2.0 specification. This patch introduces reading these lengths per each device from descriptor headers at probe time to ensure their correctness.
[Wei Li: Slight tweaks to get the cherry-pick to apply,resolved collisions]
Signed-off-by: Michal' Potomski michalx.potomski@intel.com Reviewed-by: Subhash Jadavani subhashj@codeaurora.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Li Wei liwei213@huawei.com --- drivers/scsi/ufs/ufs.h | 22 ++--- drivers/scsi/ufs/ufshcd.c | 231 ++++++++++++++++++++++++++++++++++------------ drivers/scsi/ufs/ufshcd.h | 16 ++++ 3 files changed, 197 insertions(+), 72 deletions(-)
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 377ba30c2258..5bb2316f60bf 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -145,7 +145,7 @@ enum attr_idn { /* Descriptor idn for Query requests */ enum desc_idn { QUERY_DESC_IDN_DEVICE = 0x0, - QUERY_DESC_IDN_CONFIGURAION = 0x1, + QUERY_DESC_IDN_CONFIGURATION = 0x1, QUERY_DESC_IDN_UNIT = 0x2, QUERY_DESC_IDN_RFU_0 = 0x3, QUERY_DESC_IDN_INTERCONNECT = 0x4, @@ -161,19 +161,13 @@ enum desc_header_offset { QUERY_DESC_DESC_TYPE_OFFSET = 0x01, };
-enum ufs_desc_max_size { - QUERY_DESC_DEVICE_MAX_SIZE = 0x1F, - QUERY_DESC_CONFIGURAION_MAX_SIZE = 0x90, - QUERY_DESC_UNIT_MAX_SIZE = 0x23, - QUERY_DESC_INTERCONNECT_MAX_SIZE = 0x06, - /* - * Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes - * of descriptor header. - */ - QUERY_DESC_STRING_MAX_SIZE = 0xFE, - QUERY_DESC_GEOMETRY_MAX_SIZE = 0x44, - QUERY_DESC_POWER_MAX_SIZE = 0x62, - QUERY_DESC_RFU_MAX_SIZE = 0x00, +enum ufs_desc_def_size { + QUERY_DESC_DEVICE_DEF_SIZE = 0x40, + QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, + QUERY_DESC_UNIT_DEF_SIZE = 0x23, + QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, + QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, + QUERY_DESC_POWER_DEF_SIZE = 0x62, };
/* Unit descriptor parameters offsets in bytes*/ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 50aa1a5726b8..86a3110c6d75 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -98,19 +98,6 @@ _ret; \ })
-static u32 ufs_query_desc_max_size[] = { - QUERY_DESC_DEVICE_MAX_SIZE, - QUERY_DESC_CONFIGURAION_MAX_SIZE, - QUERY_DESC_UNIT_MAX_SIZE, - QUERY_DESC_RFU_MAX_SIZE, - QUERY_DESC_INTERCONNECT_MAX_SIZE, - QUERY_DESC_STRING_MAX_SIZE, - QUERY_DESC_RFU_MAX_SIZE, - QUERY_DESC_GEOMETRY_MAX_SIZE, - QUERY_DESC_POWER_MAX_SIZE, - QUERY_DESC_RFU_MAX_SIZE, -}; - enum { UFSHCD_MAX_CHANNEL = 0, UFSHCD_MAX_ID = 1, @@ -1961,7 +1948,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, goto out; }
- if (*buf_len <= QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { + if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", __func__, *buf_len); err = -EINVAL; @@ -2040,6 +2027,92 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba, } EXPORT_SYMBOL(ufshcd_query_descriptor_retry);
+/** + * ufshcd_read_desc_length - read the specified descriptor length from header + * @hba: Pointer to adapter instance + * @desc_id: descriptor idn value + * @desc_index: descriptor index + * @desc_length: pointer to variable to read the length of descriptor + * + * Return 0 in case of success, non-zero otherwise + */ +static int ufshcd_read_desc_length(struct ufs_hba *hba, + enum desc_idn desc_id, + int desc_index, + int *desc_length) +{ + int ret; + u8 header[QUERY_DESC_HDR_SIZE]; + int header_len = QUERY_DESC_HDR_SIZE; + + if (desc_id >= QUERY_DESC_IDN_MAX) + return -EINVAL; + + ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, + desc_id, desc_index, 0, header, + &header_len); + + if (ret) { + dev_err(hba->dev, "%s: Failed to get descriptor header id %d", + __func__, desc_id); + return ret; + } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { + dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch", + __func__, header[QUERY_DESC_DESC_TYPE_OFFSET], + desc_id); + ret = -EINVAL; + } + + *desc_length = header[QUERY_DESC_LENGTH_OFFSET]; + return ret; + +} + +/** + * ufshcd_map_desc_id_to_length - map descriptor IDN to its length + * @hba: Pointer to adapter instance + * @desc_id: descriptor idn value + * @desc_len: mapped desc length (out) + * + * Return 0 in case of success, non-zero otherwise + */ +int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, + enum desc_idn desc_id, int *desc_len) +{ + switch (desc_id) { + case QUERY_DESC_IDN_DEVICE: + *desc_len = hba->desc_size.dev_desc; + break; + case QUERY_DESC_IDN_POWER: + *desc_len = hba->desc_size.pwr_desc; + break; + case QUERY_DESC_IDN_GEOMETRY: + *desc_len = hba->desc_size.geom_desc; + break; + case QUERY_DESC_IDN_CONFIGURATION: + *desc_len = hba->desc_size.conf_desc; + break; + case QUERY_DESC_IDN_UNIT: + *desc_len = hba->desc_size.unit_desc; + break; + case QUERY_DESC_IDN_INTERCONNECT: + *desc_len = hba->desc_size.interc_desc; + break; + case QUERY_DESC_IDN_STRING: + *desc_len = QUERY_DESC_MAX_SIZE; + break; + case QUERY_DESC_IDN_RFU_0: + case QUERY_DESC_IDN_RFU_1: + *desc_len = 0; + break; + default: + *desc_len = 0; + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL(ufshcd_map_desc_id_to_length); + /** * ufshcd_read_desc_param - read the specified descriptor parameter * @hba: Pointer to adapter instance @@ -2054,42 +2127,49 @@ EXPORT_SYMBOL(ufshcd_query_descriptor_retry); static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, int desc_index, - u32 param_offset, + u8 param_offset, u8 *param_read_buf, - u32 param_size) + u8 param_size) { int ret; u8 *desc_buf; - u32 buff_len; + int buff_len; bool is_kmalloc = true;
- /* safety checks */ - if (desc_id >= QUERY_DESC_IDN_MAX) + /* Safety check */ + if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) return -EINVAL;
- buff_len = ufs_query_desc_max_size[desc_id]; - if ((param_offset + param_size) > buff_len) - return -EINVAL; + /* Get the max length of descriptor from structure filled up at probe + * time. + */ + ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);
- if (!param_offset && (param_size == buff_len)) { - /* memory space already available to hold full descriptor */ - desc_buf = param_read_buf; - is_kmalloc = false; - } else { - /* allocate memory to hold full descriptor */ + /* Sanity checks */ + if (ret || !buff_len) { + dev_err(hba->dev, "%s: Failed to get full descriptor length", + __func__); + return ret; + } + + /* Check whether we need temp memory */ + if (param_offset != 0 || param_size < buff_len) { desc_buf = kmalloc(buff_len, GFP_KERNEL); if (!desc_buf) return -ENOMEM; + } else { + desc_buf = param_read_buf; + is_kmalloc = false; }
+ /* Request for full descriptor */ ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, - desc_id, desc_index, 0, desc_buf, - &buff_len); + desc_id, desc_index, 0, + desc_buf, &buff_len);
if (ret) { dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d", __func__, desc_id, desc_index, param_offset, ret); - goto out; }
@@ -2101,25 +2181,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba, goto out; }
- /* - * While reading variable size descriptors (like string descriptor), - * some UFS devices may report the "LENGTH" (field in "Transaction - * Specific fields" of Query Response UPIU) same as what was requested - * in Query Request UPIU instead of reporting the actual size of the - * variable size descriptor. - * Although it's safe to ignore the "LENGTH" field for variable size - * descriptors as we can always derive the length of the descriptor from - * the descriptor header fields. Hence this change impose the length - * match check only for fixed size descriptors (for which we always - * request the correct size as part of Query Request UPIU). - */ - if ((desc_id != QUERY_DESC_IDN_STRING) && - (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) { - dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d", - __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]); - ret = -EINVAL; - goto out; - } + /* Check wherher we will not copy more data, than available */ + if (is_kmalloc && param_size > buff_len) + param_size = buff_len;
if (is_kmalloc) memcpy(param_read_buf, &desc_buf[param_offset], param_size); @@ -4812,8 +4876,8 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba, static void ufshcd_init_icc_levels(struct ufs_hba *hba) { int ret; - int buff_len = QUERY_DESC_POWER_MAX_SIZE; - u8 desc_buf[QUERY_DESC_POWER_MAX_SIZE]; + int buff_len = hba->desc_size.pwr_desc; + u8 desc_buf[hba->desc_size.pwr_desc];
ret = ufshcd_read_power_desc(hba, desc_buf, buff_len); if (ret) { @@ -4911,11 +4975,10 @@ static int ufs_get_device_desc(struct ufs_hba *hba, { int err; u8 model_index; - u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1] = {0}; - u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; + u8 str_desc_buf[QUERY_DESC_MAX_SIZE + 1] = {0}; + u8 desc_buf[hba->desc_size.dev_desc];
- err = ufshcd_read_device_desc(hba, desc_buf, - QUERY_DESC_DEVICE_MAX_SIZE); + err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc); if (err) { dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", __func__, err); @@ -4932,14 +4995,14 @@ static int ufs_get_device_desc(struct ufs_hba *hba, model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, - QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); + QUERY_DESC_MAX_SIZE, ASCII_STD); if (err) { dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", __func__, err); goto out; }
- str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; + str_desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); @@ -5129,6 +5192,51 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) ufshcd_vops_apply_dev_quirks(hba); }
+static void ufshcd_init_desc_sizes(struct ufs_hba *hba) +{ + int err; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0, + &hba->desc_size.dev_desc); + if (err) + hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0, + &hba->desc_size.pwr_desc); + if (err) + hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0, + &hba->desc_size.interc_desc); + if (err) + hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0, + &hba->desc_size.conf_desc); + if (err) + hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0, + &hba->desc_size.unit_desc); + if (err) + hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0, + &hba->desc_size.geom_desc); + if (err) + hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; +} + +static void ufshcd_def_desc_sizes(struct ufs_hba *hba) +{ + hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; + hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; + hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; + hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; + hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; + hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; +} + /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance @@ -5161,6 +5269,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out;
+ /* Init check for device descriptor sizes */ + ufshcd_init_desc_sizes(hba); + ret = ufs_get_device_desc(hba, &card); if (ret) { dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", @@ -5194,6 +5305,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
/* set the state as operational after switching to desired gear */ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; + /* * If we are in error handling context or in power management callbacks * context, no need to scan the host @@ -6570,6 +6682,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->mmio_base = mmio_base; hba->irq = irq;
+ /* Set descriptor lengths to specification defaults */ + ufshcd_def_desc_sizes(hba); + err = ufshcd_hba_init(hba); if (err) goto out_error; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index f2170d5058a8..6dbd2e176333 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -205,6 +205,15 @@ struct ufs_dev_cmd { struct ufs_query query; };
+struct ufs_desc_size { + int dev_desc; + int pwr_desc; + int geom_desc; + int interc_desc; + int unit_desc; + int conf_desc; +}; + /** * struct ufs_clk_info - UFS clock related info * @list: list headed by hba->clk_list_head @@ -388,6 +397,7 @@ struct ufs_init_prefetch { * @clk_list_head: UFS host controller clocks list node head * @pwr_info: holds current power mode * @max_pwr_info: keeps the device max valid pwm + * @desc_size: descriptor sizes reported by device * @urgent_bkops_lvl: keeps track of urgent bkops level for device * @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for * device is known or not. @@ -563,6 +573,8 @@ struct ufs_hba {
enum bkops_status urgent_bkops_lvl; bool is_urgent_bkops_lvl_checked; + + struct ufs_desc_size desc_size; };
/* Returns true if clocks can be gated. Otherwise false */ @@ -736,6 +748,10 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); + +int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, + int *desc_length); + u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);
/* Wrapper functions for safely calling variant operations */
On Fri, Jun 01, 2018 at 01:57:31PM +0800, Li Wei wrote:
This patch fix failure to read the string descriptor.
In kernel v4.9.100,we encountered the following error info:
[3.141326] ufshcd-hi3660 ff3b0000.ufs: ufshcd_read_desc_param: Failed reading descriptor. desc_id 0 param_offset 0 buff_len 31 ret 0 [3.141331] ufshcd-hi3660 ff3b0000.ufs: ufs_get_device_info: Failed reading Device Desc. err = -22 [3.141336] ufshcd-hi3660 ff3b0000.ufs: ufs_advertise_fixup_device: Failed getting device info. err = -22 [3.145923] ufs final power mode: gear = 3, lane = 2, pwr = 1, rate = 2 [3.145927] ufshcd-hi3660 ff3b0000.ufs: set TX_EQUALIZER 3.5db [3.157229] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane0 = 0x1 [3.157716] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane1 = 0x1 [3.190446] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.227484] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.263496] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.299509] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.335528] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.371501] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.407493] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.443501] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11 [3.479491] ufshcd-hi3660 ff3b0000.ufs: ufshcd_query_flag: Sending flag query for idn 3 failed, err = -11
If failed to read device desc, card_data->wmanufacturerid and card_data->model will not get the correct value, meaning that hba->dev_quirks will no longer work. And some ufs device's quirks handling will even cause ufs can't work. In fact, our hikey960 board using Hynix ufs device failed to initialize on v4.9 because a quirk of the hynix device was not handled.
We test with hikey960 & hikey970 boards in aosp-master hikey-linaro-4.9 (v4.9.100), this patch can solve the above problem perfectly.
[3.223550] ufs final power mode: gear = 3, lane = 2, pwr = 1, rate = 2 [3.223565] ufshcd-hi3660 ff3b0000.ufs: set TX_EQUALIZER 3.5db [3.223609] ufs flash device must set VS_DebugSaveConfigTime 0x10 [3.226218] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane0 = 0x1 [3.226247] ufshcd-hi3660 ff3b0000.ufs: check TX_EQUALIZER DB value lane1 = 0x1 [3.226400] ufshcd-hi3660 ff3b0000.ufs: ufshcd_find_max_sup_active_icc_level: Regulator capability was not set, actvIccLevel=0 [3.232847] scsi 0:0:0:49488: Well-known LUN SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.321453] scsi 0:0:0:49456: Well-known LUN SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.383820] scsi 0:0:0:49476: Well-known LUN SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.447615] scsi 0:0:0:0: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.503504] sd 0:0:0:0: [sda] 1024 4096-byte logical blocks: (4.19 MB/4.00 MiB) [3.503863] sd 0:0:0:0: [sda] Write Protect is off [3.503867] sd 0:0:0:0: [sda] Mode Sense: 00 32 00 10 [3.503963] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.504017] scsi 0:0:0:1: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.505615] sd 0:0:0:0: [sda] Attached SCSI disk [3.547425] sd 0:0:0:1: [sdb] 1024 4096-byte logical blocks: (4.19 MB/4.00 MiB) [3.547768] scsi 0:0:0:2: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.548003] sd 0:0:0:1: [sdb] Write Protect is off [3.548005] sd 0:0:0:1: [sdb] Mode Sense: 00 32 00 10 [3.548428] sd 0:0:0:1: [sdb] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.553383] sd 0:0:0:1: [sdb] Attached SCSI disk [3.591547] sd 0:0:0:2: [sdc] 2048 4096-byte logical blocks: (8.39 MB/8.00 MiB) [3.592056] scsi 0:0:0:3: Direct-Access SKhynix H28U62301AMR H109 PQ: 0 ANSI: 6 [3.593336] sd 0:0:0:2: [sdc] Write Protect is off [3.593340] sd 0:0:0:2: [sdc] Mode Sense: 00 32 00 10 [3.593638] sd 0:0:0:2: [sdc] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.596473] Alternate GPT is invalid, using primary GPT. [3.596480] sdc: sdc1 [3.597069] random: fast init done [3.597168] sd 0:0:0:2: [sdc] Attached SCSI disk [3.644460] sd 0:0:0:3: [sdd] 7805952 4096-byte logical blocks: (32.0 GB/29.8 GiB) [3.644867] sd 0:0:0:3: [sdd] Write Protect is off [3.644869] sd 0:0:0:3: [sdd] Mode Sense: 00 32 00 10 [3.644992] sd 0:0:0:3: [sdd] Write cache: enabled, read cache: enabled, supports DPO and FUA [3.646506] Alternate GPT is invalid, using primary GPT. [3.646518] sdd: sdd1 sdd2 sdd3 sdd4 sdd5 sdd6 sdd7 sdd8 sdd9 sdd10 sdd11 sdd12 sdd13 [3.647956] sd 0:0:0:3: [sdd] Attached SCSI disk
We hope merge this patch to 4.9-stable to avoid other similar problems.
All now queued up, thanks for the backports.
greg k-h
linux-stable-mirror@lists.linaro.org