From 3f8adb02aab70723ec239d901aa5f3525dc2ee08 Mon Sep 17 00:00:00 2001 From: Yaniv Gardi Date: Wed, 25 Mar 2015 17:59:05 +0200 Subject: [PATCH] scsi: ufs: add additional error injection scenarios This change adds the following additional error scenarios: - power mode change error - link start-up error - send UIC command error - get/set DME command error (to host and device) - send invalid query (flag/attribute/descriptor) Change-Id: I440519c385a5da269b85ed2cdad66565ed3e6d7e Signed-off-by: Yaniv Gardi [subhashj@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Subhash Jadavani --- drivers/scsi/ufs/ufs-debugfs.c | 80 ++++++++++++++++++++++++++-------- drivers/scsi/ufs/ufs-debugfs.h | 8 ++-- drivers/scsi/ufs/ufshcd.c | 22 +++++++++- 3 files changed, 86 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c index 3f05d2e6c6c1..0df02f2e03b2 100644 --- a/drivers/scsi/ufs/ufs-debugfs.c +++ b/drivers/scsi/ufs/ufs-debugfs.c @@ -67,12 +67,46 @@ struct ufsdbg_err_scenario { u32 num_err_codes; }; +/* + * the following static arrays are aggregation of possible errors + * that might occur during the relevant error scenario + */ static const int err_inject_intr_err_codes[] = { CONTROLLER_FATAL_ERROR, SYSTEM_BUS_FATAL_ERROR, INJECT_COMMAND_HANG, }; +static const int err_inject_pwr_change_err_codes[] = { + -EIO, + -ETIMEDOUT, + -1, + PWR_REMOTE, + PWR_BUSY, + PWR_ERROR_CAP, + PWR_FATAL_ERROR, +}; + +static const int err_inject_link_startup_err_codes[] = { + -EIO, + -ETIMEDOUT, +}; + +static const int err_inject_uic_err_codes[] = { + -EIO, + -ETIMEDOUT, +}; + +static const int err_inject_dme_attr_err_codes[] = { + /* an invalid DME attribute for host and device */ + 0x1600, +}; + +static const int err_inject_query_err_codes[] = { + /* an invalid idn for flag/attribute/descriptor query request */ + 0xFF, +}; + static struct ufsdbg_err_scenario err_scen_arr[] = { { "ERR_INJECT_INTR", @@ -93,34 +127,34 @@ static struct ufsdbg_err_scenario err_scen_arr[] = { 0, }, { - "ERR_INJECT_GEAR_CHANGE", + "ERR_INJECT_PWR_CHANGE", ERR_CODES_ALL_ENABLED, - NULL, - 0, + err_inject_pwr_change_err_codes, + ARRAY_SIZE(err_inject_pwr_change_err_codes), }, { "ERR_INJECT_LINK_STARTUP", ERR_CODES_ALL_ENABLED, - NULL, - 0, + err_inject_link_startup_err_codes, + ARRAY_SIZE(err_inject_link_startup_err_codes), + }, + { + "ERR_INJECT_UIC", + ERR_CODES_ALL_ENABLED, + err_inject_uic_err_codes, + ARRAY_SIZE(err_inject_uic_err_codes), }, { "ERR_INJECT_DME_ATTR", ERR_CODES_ALL_ENABLED, - NULL, - 0, - }, - { - "ERR_INJECT_DME_PEER_ATTR", - ERR_CODES_ALL_ENABLED, - NULL, - 0, + err_inject_dme_attr_err_codes, + ARRAY_SIZE(err_inject_dme_attr_err_codes), }, { "ERR_INJECT_QUERY", ERR_CODES_ALL_ENABLED, - NULL, - 0, + err_inject_query_err_codes, + ARRAY_SIZE(err_inject_query_err_codes), }, { "ERR_INJECT_RUNTIME_PM", @@ -264,7 +298,7 @@ ufsdbg_find_err_code(enum ufsdbg_err_inject_scenario usecase, int *ret) void ufsdbg_error_inject_dispatcher(struct ufs_hba *hba, enum ufsdbg_err_inject_scenario usecase, - int *ret_value) + int success_value, int *ret_value) { int opt_ret = 0; @@ -280,16 +314,24 @@ void ufsdbg_error_inject_dispatcher(struct ufs_hba *hba, if (!should_fail(&hba->debugfs_files.fail_attr, 1)) goto out; + /* if an error already occurred/injected */ + if (*ret_value != success_value) + goto out; + switch (usecase) { case ERR_INJECT_INTR: - ufsdbg_intr_fail_request(hba, &opt_ret); + /* an error already occurred */ + if (*ret_value & UFSHCD_ERROR_MASK) + goto out; + + ufsdbg_intr_fail_request(hba, (u32 *)&opt_ret); /* fall through */ case ERR_INJECT_HIBERN8_ENTER: case ERR_INJECT_HIBERN8_EXIT: - case ERR_INJECT_GEAR_CHANGE: + case ERR_INJECT_PWR_CHANGE: case ERR_INJECT_LINK_STARTUP: + case ERR_INJECT_UIC: case ERR_INJECT_DME_ATTR: - case ERR_INJECT_DME_PEER_ATTR: case ERR_INJECT_QUERY: case ERR_INJECT_RUNTIME_PM: case ERR_INJECT_SYSTEM_PM: diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h index 95b582d16c39..6aaa2a407a5f 100644 --- a/drivers/scsi/ufs/ufs-debugfs.h +++ b/drivers/scsi/ufs/ufs-debugfs.h @@ -27,10 +27,10 @@ enum ufsdbg_err_inject_scenario { ERR_INJECT_INTR, ERR_INJECT_HIBERN8_ENTER, ERR_INJECT_HIBERN8_EXIT, - ERR_INJECT_GEAR_CHANGE, + ERR_INJECT_PWR_CHANGE, ERR_INJECT_LINK_STARTUP, + ERR_INJECT_UIC, ERR_INJECT_DME_ATTR, - ERR_INJECT_DME_PEER_ATTR, ERR_INJECT_QUERY, ERR_INJECT_RUNTIME_PM, ERR_INJECT_SYSTEM_PM, @@ -60,11 +60,11 @@ static inline void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, #ifdef CONFIG_UFS_FAULT_INJECTION void ufsdbg_error_inject_dispatcher(struct ufs_hba *hba, enum ufsdbg_err_inject_scenario err_scenario, - int *ret_value); + int success_value, int *ret_value); #else static inline void ufsdbg_error_inject_dispatcher(struct ufs_hba *hba, enum ufsdbg_err_inject_scenario err_scenario, - int *ret_value) + int success_value, int *ret_value) { } #endif diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index dea629abf830..e24c3421db3c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2199,6 +2199,10 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) ufshcd_save_tstamp_of_last_dme_cmd(hba); mutex_unlock(&hba->uic_cmd_mutex); ufshcd_release_all(hba); + + ufsdbg_error_inject_dispatcher(hba, + ERR_INJECT_UIC, 0, &ret); + return ret; } @@ -2861,6 +2865,9 @@ static inline void ufshcd_init_query(struct ufs_hba *hba, struct ufs_query_req **request, struct ufs_query_res **response, enum query_opcode opcode, u8 idn, u8 index, u8 selector) { + ufsdbg_error_inject_dispatcher(hba, + ERR_INJECT_QUERY, idn, (int *)&idn); + *request = &hba->dev_cmd.query.request; *response = &hba->dev_cmd.query.response; memset(*request, 0, sizeof(struct ufs_query_req)); @@ -3624,6 +3631,9 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, int ret; int retries = UFS_UIC_COMMAND_RETRIES; + ufsdbg_error_inject_dispatcher(hba, + ERR_INJECT_DME_ATTR, attr_sel, &attr_sel); + uic_cmd.command = peer ? UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET; uic_cmd.argument1 = attr_sel; @@ -3695,6 +3705,10 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, uic_cmd.command = peer ? UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; + + ufsdbg_error_inject_dispatcher(hba, + ERR_INJECT_DME_ATTR, attr_sel, &attr_sel); + uic_cmd.argument1 = attr_sel; do { @@ -4114,6 +4128,9 @@ int ufshcd_change_power_mode(struct ufs_hba *hba, sizeof(struct ufs_pa_layer_attr)); } + ufsdbg_error_inject_dispatcher(hba, + ERR_INJECT_PWR_CHANGE, 0, &ret); + return ret; } @@ -4430,6 +4447,9 @@ static int ufshcd_link_startup(struct ufs_hba *hba) ret = ufshcd_make_hba_operational(hba); out: + ufsdbg_error_inject_dispatcher(hba, + ERR_INJECT_LINK_STARTUP, 0, &ret); + if (ret) dev_err(hba->dev, "link startup failed %d\n", ret); return ret; @@ -5669,7 +5689,7 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) bool crypto_engine_err = false; ufsdbg_error_inject_dispatcher(hba, - ERR_INJECT_INTR, &intr_status); + ERR_INJECT_INTR, intr_status, &intr_status); if (hba->vops && hba->vops->crypto_engine_eh) crypto_engine_err = hba->vops->crypto_engine_eh(hba);