scsi: ufs: retry failed query flag requests
UFS flag query requests may fail sometimes due to timeouts etc. Add a wrapper function to retry up to 10 times in case of such failure, similar to retries being made for attribute queries. Reviewed-by: Dolev Raviv <draviv@codeaurora.org> Signed-off-by: Gilad Broner <gbroner@codeaurora.org> Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
53c12d0ef6
commit
dc3c8d3a7d
@ -1660,6 +1660,29 @@ static inline void ufshcd_init_query(struct ufs_hba *hba,
|
||||
(*request)->upiu_req.selector = selector;
|
||||
}
|
||||
|
||||
static int ufshcd_query_flag_retry(struct ufs_hba *hba,
|
||||
enum query_opcode opcode, enum flag_idn idn, bool *flag_res)
|
||||
{
|
||||
int ret;
|
||||
int retries;
|
||||
|
||||
for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) {
|
||||
ret = ufshcd_query_flag(hba, opcode, idn, flag_res);
|
||||
if (ret)
|
||||
dev_dbg(hba->dev,
|
||||
"%s: failed with error %d, retries %d\n",
|
||||
__func__, ret, retries);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(hba->dev,
|
||||
"%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n",
|
||||
__func__, opcode, idn, ret, retries);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_query_flag() - API function for sending flag query requests
|
||||
* hba: per-adapter instance
|
||||
@ -1669,7 +1692,7 @@ static inline void ufshcd_init_query(struct ufs_hba *hba,
|
||||
*
|
||||
* Returns 0 for success, non-zero in case of failure
|
||||
*/
|
||||
static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
|
||||
int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
|
||||
enum flag_idn idn, bool *flag_res)
|
||||
{
|
||||
struct ufs_query_req *request = NULL;
|
||||
@ -2654,17 +2677,12 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
|
||||
*/
|
||||
static int ufshcd_complete_dev_init(struct ufs_hba *hba)
|
||||
{
|
||||
int i, retries, err = 0;
|
||||
int i;
|
||||
int err;
|
||||
bool flag_res = 1;
|
||||
|
||||
for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
|
||||
/* Set the fDeviceInit flag */
|
||||
err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
|
||||
QUERY_FLAG_IDN_FDEVICEINIT, NULL);
|
||||
if (!err || err == -ETIMEDOUT)
|
||||
break;
|
||||
dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
|
||||
}
|
||||
err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
|
||||
QUERY_FLAG_IDN_FDEVICEINIT, NULL);
|
||||
if (err) {
|
||||
dev_err(hba->dev,
|
||||
"%s setting fDeviceInit flag failed with error %d\n",
|
||||
@ -2672,18 +2690,11 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* poll for max. 100 iterations for fDeviceInit flag to clear */
|
||||
for (i = 0; i < 100 && !err && flag_res; i++) {
|
||||
for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
|
||||
err = ufshcd_query_flag(hba,
|
||||
UPIU_QUERY_OPCODE_READ_FLAG,
|
||||
QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
|
||||
if (!err || err == -ETIMEDOUT)
|
||||
break;
|
||||
dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
|
||||
err);
|
||||
}
|
||||
}
|
||||
/* poll for max. 1000 iterations for fDeviceInit flag to clear */
|
||||
for (i = 0; i < 1000 && !err && flag_res; i++)
|
||||
err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
|
||||
QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
|
||||
|
||||
if (err)
|
||||
dev_err(hba->dev,
|
||||
"%s reading fDeviceInit flag failed with error %d\n",
|
||||
@ -3430,7 +3441,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba)
|
||||
if (hba->auto_bkops_enabled)
|
||||
goto out;
|
||||
|
||||
err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
|
||||
err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
|
||||
QUERY_FLAG_IDN_BKOPS_EN, NULL);
|
||||
if (err) {
|
||||
dev_err(hba->dev, "%s: failed to enable bkops %d\n",
|
||||
@ -3479,7 +3490,7 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
|
||||
err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
|
||||
QUERY_FLAG_IDN_BKOPS_EN, NULL);
|
||||
if (err) {
|
||||
dev_err(hba->dev, "%s: failed to disable bkops %d\n",
|
||||
@ -4450,8 +4461,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
|
||||
|
||||
/* clear any previous UFS device information */
|
||||
memset(&hba->dev_info, 0, sizeof(hba->dev_info));
|
||||
if (!ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,
|
||||
QUERY_FLAG_IDN_PWR_ON_WPE, &flag))
|
||||
if (!ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
|
||||
QUERY_FLAG_IDN_PWR_ON_WPE, &flag))
|
||||
hba->dev_info.f_power_on_wp_en = flag;
|
||||
|
||||
if (!hba->is_init_prefetch)
|
||||
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* This code is based on drivers/scsi/ufs/ufshcd.h
|
||||
* Copyright (C) 2011-2013 Samsung India Software Operations
|
||||
* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Authors:
|
||||
* Santosh Yaraganavi <santosh.sy@samsung.com>
|
||||
@ -681,6 +682,9 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
|
||||
return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
|
||||
}
|
||||
|
||||
/* Expose Query-Request API */
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user