summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2015-03-25 13:06:42 +0200
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:59:42 -0700
commit1ff884ade9d2afe84d6abc8bb4c556a5573c71c8 (patch)
treeac98efcf8417112a5fb8498cdbe83a90e7d86925
parenta34d2fc0f33dc939c719b6480649b081224bf3b6 (diff)
scsi: ufs: add debugfs options for fault injection capability
This change adds a few debugfs options for the UFS fault injection framework. "err_inj_scenario" entry - to enable/disable error scenarios. "err_inj_codes" entry - to control specific error codes for a specific error scenario. usage: echo 0x5 > /sys/kernel/debug/ufshcd0/err_inj_scenario as 0x5 is b0101, it sets bits #0 and #2 of err_inj_scenario_mask. echo "2, 0x7" > /sys/kernel/debug/ufshcd0/err_inj_codes sets error codes b0111 for error scenario #2 Change-Id: I0c58886a1ffac4dc85d8827bf69d650082a03fc5 Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> [subhashj@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-rw-r--r--drivers/scsi/ufs/ufs-debugfs.c126
-rw-r--r--drivers/scsi/ufs/ufshcd.h3
2 files changed, 120 insertions, 9 deletions
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 1fe5e532b30d..41fedb433087 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -205,7 +205,8 @@ static int inject_cmd_hang_tm(struct ufs_hba *hba)
return 1;
}
-void ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status)
+static void
+ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status)
{
u8 ocs_err;
static const u32 errors[] = {
@@ -273,6 +274,9 @@ void ufsdbg_error_inject_dispatcher(struct ufs_hba *hba,
if (!hba || !ret_value)
goto out;
+ if (!(hba->debugfs_files.err_inj_scenario_mask & (1 << usecase)))
+ goto out;
+
switch (usecase) {
case ERR_INJECT_INTR:
ufsdbg_fail_request(hba, ret_value);
@@ -307,27 +311,131 @@ out:
return;
}
+static int ufsdbg_error_injection_mask_read(struct seq_file *file, void *data)
+{
+ struct ufs_hba *hba = (struct ufs_hba *)file->private;
+ enum ufsdbg_err_inject_scenario err_case;
+
+ seq_puts(file, "echo \"x, y\" > /sys/kernel/debug/.../err_inj_codes\n");
+ seq_puts(file, "for error scenario x, enable error codes bitwise y\n\n");
+ seq_puts(file, "example: echo \"2, 0x6\" > /sys/kernel/debug/.../err_inj_codes\n");
+ seq_puts(file, "for error scenario ERR_INJECT_HIBERN8_EXIT_ERR (error scenario#2)\n");
+ seq_puts(file, "enable error codes 0100b and 0010b (0110b)\n\n");
+ seq_printf(file, "%-40s %-20s %-17s %-15s %-15s\n",
+ "Error Scenario:", "Error-Scenario#",
+ "Bit[#]", "STATUS", "Enabled Err Codes");
+
+ for (err_case = 0; err_case < ERR_INJECT_MAX_ERR_SCENARIOS;
+ ++err_case) {
+ seq_printf(file, "%-40s %-20d 0x%-15x %-15s 0x%-15x\n",
+ err_scen_arr[err_case].name,
+ err_case,
+ (1 << err_case),
+ hba->debugfs_files.err_inj_scenario_mask &
+ (1 << err_case) ? "ENABLE" : "DISABLE",
+ err_scen_arr[err_case].err_code_mask);
+ }
+
+ return 0;
+}
+
+static
+int ufsdbg_err_code_open(struct inode *inode, struct file *file)
+{
+ return single_open(file,
+ ufsdbg_error_injection_mask_read, inode->i_private);
+}
+
+static ssize_t ufsdbg_err_code_write(struct file *file,
+ const char __user *ubuf, size_t cnt,
+ loff_t *ppos)
+{
+#define ERROR_CODE_CONTROL_BUF 20
+ struct ufs_hba *hba = file->f_mapping->host->i_private;
+ char buf[ERROR_CODE_CONTROL_BUF] = {0};
+ int ret;
+ int err_code_mask = 0;
+ int err_scen = 0;
+
+ ret = simple_write_to_buffer(buf, ERROR_CODE_CONTROL_BUF,
+ ppos, ubuf, cnt);
+
+ if (sscanf(buf, "%d,%d", &err_scen, &err_code_mask) != 2) {
+ dev_err(hba->dev, "%s: invalid number of arguments\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (err_scen >= ERR_INJECT_MAX_ERR_SCENARIOS) {
+ dev_err(hba->dev, "%s: invalid number error scenario\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ err_scen_arr[err_scen].err_code_mask = err_code_mask;
+ return cnt;
+}
+
+static const struct file_operations ufsdbg_err_code_ops = {
+ .open = ufsdbg_err_code_open,
+ .read = seq_read,
+ .write = ufsdbg_err_code_write,
+};
+
static void ufsdbg_setup_fault_injection(struct ufs_hba *hba)
{
+ struct dentry *fault_dir;
+
hba->debugfs_files.fail_attr = fail_default_attr;
if (fail_request)
setup_fault_attr(&hba->debugfs_files.fail_attr, fail_request);
- /* suppress dump stack everytime failure is injected */
+ /* suppress dump stack every time failure is injected */
hba->debugfs_files.fail_attr.verbose = 0;
- if (IS_ERR(fault_create_debugfs_attr("inject_fault",
+ fault_dir = fault_create_debugfs_attr("inject_fault",
hba->debugfs_files.debugfs_root,
- &hba->debugfs_files.fail_attr)))
- dev_err(hba->dev, "%s: failed to create debugfs entry\n",
+ &hba->debugfs_files.fail_attr);
+
+ if (IS_ERR(fault_dir)) {
+ dev_err(hba->dev, "%s: failed to create debugfs entry for fault injection\n",
+ __func__);
+ return;
+ }
+
+ hba->debugfs_files.err_inj_scenario =
+ debugfs_create_u32("err_inj_scenario",
+ S_IRUGO | S_IWUGO,
+ hba->debugfs_files.debugfs_root,
+ &hba->debugfs_files.err_inj_scenario_mask);
+
+ if (!hba->debugfs_files.err_inj_scenario) {
+ dev_err(hba->dev,
+ "%s: Could not create debugfs entry for err_scenario",
__func__);
+ goto fail_err_inj_scenario;
+ }
+
+ hba->debugfs_files.err_inj_codes =
+ debugfs_create_file("err_inj_codes", S_IRUSR | S_IWUSR,
+ hba->debugfs_files.debugfs_root, hba,
+ &ufsdbg_err_code_ops);
+ if (!hba->debugfs_files.err_inj_codes) {
+ dev_err(hba->dev,
+ "%s: failed create error_codes debugfs entry\n",
+ __func__);
+ goto fail_err_inj_codes;
+ }
+
+ return;
+
+fail_err_inj_codes:
+ debugfs_remove(hba->debugfs_files.err_inj_scenario);
+fail_err_inj_scenario:
+ debugfs_remove_recursive(fault_dir);
}
#else
-void ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status)
-{
-}
-
static void ufsdbg_setup_fault_injection(struct ufs_hba *hba)
{
}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 7a4e606168a4..486f8d09ec90 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -477,6 +477,9 @@ struct debugfs_files {
u32 dme_local_attr_id;
u32 dme_peer_attr_id;
#ifdef CONFIG_UFS_FAULT_INJECTION
+ struct dentry *err_inj_codes;
+ struct dentry *err_inj_scenario;
+ u32 err_inj_scenario_mask;
struct fault_attr fail_attr;
#endif
bool is_sys_suspended;