scsi: ufs: retry failed query flag requests
authorYaniv Gardi <ygardi@codeaurora.org>
Mon, 1 Feb 2016 13:02:46 +0000 (15:02 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 24 Feb 2016 02:27:02 +0000 (21:27 -0500)
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>
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h

index da08a40..87da429 100644 (file)
@@ -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)
index 2570d94..8e22e6c 100644 (file)
@@ -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);