Re: [PATCH v3 4/4] scsi: ufs: inject errors to verify error handling

From: Dov Levenglick
Date: Mon Feb 23 2015 - 04:11:18 EST


> From: Sujit Reddy Thumma <sthumma@xxxxxxxxxxxxxx>
>
> Use fault-injection framework to simulate error conditions
> in the controller and verify error handling mechanisms
> implemented in UFS host controller driver.
>
> This is used only during development and hence
> guarded by CONFIG_UFS_FAULT_INJECTION debug config option.
>
> Signed-off-by: Sujit Reddy Thumma <sthumma@xxxxxxxxxxxxxx>
> ---
> drivers/scsi/ufs/ufs-debugfs.c | 140
> +++++++++++++++++++++++++++++++++++++++++
> drivers/scsi/ufs/ufs-debugfs.h | 4 ++
> drivers/scsi/ufs/ufshcd.c | 2 +
> drivers/scsi/ufs/ufshcd.h | 5 ++
> lib/Kconfig.debug | 14 +++++
> 5 files changed, 165 insertions(+)
>
> diff --git a/drivers/scsi/ufs/ufs-debugfs.c
> b/drivers/scsi/ufs/ufs-debugfs.c
> index d1eb4f8..53dcb00 100644
> --- a/drivers/scsi/ufs/ufs-debugfs.c
> +++ b/drivers/scsi/ufs/ufs-debugfs.c
> @@ -17,6 +17,7 @@
> *
> */
>
> +#include <linux/random.h>
> #include "ufs-debugfs.h"
> #include "unipro.h"
>
> @@ -41,6 +42,143 @@ struct desc_field_offset {
> } while (0)
> #define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */
>
> +#ifdef CONFIG_UFS_FAULT_INJECTION
> +
> +#define INJECT_COMMAND_HANG (0x0)
> +
> +static DECLARE_FAULT_ATTR(fail_default_attr);
> +static char *fail_request;
> +module_param(fail_request, charp, 0);
> +
> +static bool inject_fatal_err_tr(struct ufs_hba *hba, u8 ocs_err)
> +{
> + int tag;
> +
> + tag = find_first_bit(&hba->outstanding_reqs, hba->nutrs);
> + if (tag == hba->nutrs)
> + return 0;
> +
> + ufshcd_writel(hba, ~(1 << tag), REG_UTP_TRANSFER_REQ_LIST_CLEAR);
> + (&hba->lrb[tag])->utr_descriptor_ptr->header.dword_2 =
> +
> cpu_to_be32(ocs_err);
> +
> + /* fatal error injected */
> + return 1;
> +}
> +
> +static bool inject_fatal_err_tm(struct ufs_hba *hba, u8 ocs_err)
> +{
> + int tag;
> +
> + tag = find_first_bit(&hba->outstanding_tasks, hba->nutmrs);
> + if (tag == hba->nutmrs)
> + return 0;
> +
> + ufshcd_writel(hba, ~(1 << tag), REG_UTP_TASK_REQ_LIST_CLEAR);
> + (&hba->utmrdl_base_addr[tag])->header.dword_2 =
> + cpu_to_be32(ocs_err);
> +
> + /* fatal error injected */
> + return 1;
> +}
> +
> +static bool inject_cmd_hang_tr(struct ufs_hba *hba)
> +{
> + int tag;
> +
> + tag = find_first_bit(&hba->outstanding_reqs, hba->nutrs);
> + if (tag == hba->nutrs)
> + return 0;
> +
> + __clear_bit(tag, &hba->outstanding_reqs);
> + hba->lrb[tag].cmd = NULL;
> + __clear_bit(tag, &hba->lrb_in_use);
> +
> + /* command hang injected */
> + return 1;
> +}
> +
> +static int inject_cmd_hang_tm(struct ufs_hba *hba)
> +{
> + int tag;
> +
> + tag = find_first_bit(&hba->outstanding_tasks, hba->nutmrs);
> + if (tag == hba->nutmrs)
> + return 0;
> +
> + __clear_bit(tag, &hba->outstanding_tasks);
> + __clear_bit(tag, &hba->tm_slots_in_use);
> +
> + /* command hang injected */
> + return 1;
> +}
> +
> +void ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status)
> +{
> + u8 ocs_err;
> + static const u32 errors[] = {
> + CONTROLLER_FATAL_ERROR,
> + SYSTEM_BUS_FATAL_ERROR,
> + INJECT_COMMAND_HANG,
> + };
> +
> + if (!should_fail(&hba->debugfs_files.fail_attr, 1))
> + goto out;
> +
> + *intr_status = errors[prandom_u32() % ARRAY_SIZE(errors)];
> + dev_info(hba->dev, "%s: fault-inject error: 0x%x\n",
> + __func__, *intr_status);
> +
> + switch (*intr_status) {
> + case CONTROLLER_FATAL_ERROR: /* fall through */
> + ocs_err = OCS_FATAL_ERROR;
> + goto set_ocs;
> + case SYSTEM_BUS_FATAL_ERROR:
> + ocs_err = OCS_INVALID_CMD_TABLE_ATTR;
> +set_ocs:
> + if (!inject_fatal_err_tr(hba, ocs_err))
> + if (!inject_fatal_err_tm(hba, ocs_err))
> + *intr_status = 0;
> + break;
> + case INJECT_COMMAND_HANG:
> + if (!inject_cmd_hang_tr(hba))
> + inject_cmd_hang_tm(hba);
> + break;
> + default:
> + BUG();
> + /* some configurations ignore panics caused by BUG() */
> + break;
> + }
> +out:
> + return;
> +}
> +
> +static void ufsdbg_setup_fault_injection(struct ufs_hba *hba)
> +{
> + 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 */
> + hba->debugfs_files.fail_attr.verbose = 0;
> +
> + if (IS_ERR(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",
> + __func__);
> +}
> +#else
> +void ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status)
> +{
> +}
> +
> +static void ufsdbg_setup_fault_injection(struct ufs_hba *hba)
> +{
> +}
> +#endif /* CONFIG_UFS_FAULT_INJECTION */
> +
> #define BUFF_LINE_CAPACITY 16
> #define TAB_CHARS 8
>
> @@ -885,6 +1023,8 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
> goto err;
> }
>
> + ufsdbg_setup_fault_injection(hba);
> +
> return;
>
> err:
> diff --git a/drivers/scsi/ufs/ufs-debugfs.h
> b/drivers/scsi/ufs/ufs-debugfs.h
> index 7ed308d..54c68f4 100644
> --- a/drivers/scsi/ufs/ufs-debugfs.h
> +++ b/drivers/scsi/ufs/ufs-debugfs.h
> @@ -26,6 +26,7 @@
> #ifdef CONFIG_DEBUG_FS
> void ufsdbg_add_debugfs(struct ufs_hba *hba);
> void ufsdbg_remove_debugfs(struct ufs_hba *hba);
> +void ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status);
> #else
> static inline void ufsdbg_add_debugfs(struct ufs_hba *hba)
> {
> @@ -33,6 +34,9 @@ static inline void ufsdbg_add_debugfs(struct ufs_hba
> *hba)
> static inline void ufsdbg_remove_debugfs(struct ufs_hba *hba)
> {
> }
> +static inline void ufsdbg_fail_request(struct ufs_hba *hba, u32
> *intr_status)
> +{
> +}
> #endif
>
> #endif /* End of Header */
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index ae934f2..99c1a81 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -4003,6 +4003,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
> */
> static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
> {
> + ufsdbg_fail_request(hba, &intr_status);
> +
> hba->errors = UFSHCD_ERROR_MASK & intr_status;
> if (hba->errors)
> ufshcd_check_errors(hba);
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index d9eb2ca..b065295 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -64,6 +64,8 @@
> #include <scsi/scsi_dbg.h>
> #include <scsi/scsi_eh.h>
>
> +#include <linux/fault-inject.h>
> +
> #include "ufs.h"
> #include "ufshci.h"
>
> @@ -283,6 +285,9 @@ struct debugfs_files {
> struct dentry *dme_peer_read;
> u32 dme_local_attr_id;
> u32 dme_peer_attr_id;
> +#ifdef CONFIG_UFS_FAULT_INJECTION
> + struct fault_attr fail_attr;
> +#endif
> };
>
> /* tag stats statistics types */
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 5f2ce61..3fc79e7 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -1432,6 +1432,20 @@ config FAIL_MMC_REQUEST
> and to test how the mmc host driver handles retries from
> the block device.
>
> +config UFS_FAULT_INJECTION
> + bool "Fault-injection capability for UFS IO"
> + select DEBUG_FS
> + depends on FAULT_INJECTION && SCSI_UFSHCD
> + help
> + Provide fault-injection capability for UFS IO.
> + This will make the UFS host controller driver to randomly
> + abort ongoing commands in the host controller, update OCS
> + field according to the injected fatal error and can also
> + forcefully hang the command indefinitely till upper layer
> + timeout occurs. This is useful to test error handling in
> + the UFS contoller driver and test how the driver handles
> + the retries from block/SCSI mid layer.
> +
> config FAULT_INJECTION_DEBUG_FS
> bool "Debugfs entries for fault-injection capabilities"
> depends on FAULT_INJECTION && SYSFS && DEBUG_FS
> --
> Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


Reviewed-by: Dov Levenglick <dovl@xxxxxxxxxxxxxx>

QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/