Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e763790 authored by Sujit Reddy Thumma's avatar Sujit Reddy Thumma
Browse files

scsi: ufs: Inject errors to verify error handling



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.

Change-Id: Ia63c276c5e56d677a92332b42b670300ad82af7a
Signed-off-by: default avatarSujit Reddy Thumma <sthumma@codeaurora.org>
parent 082d3f95
Loading
Loading
Loading
Loading
+140 −0
Original line number Diff line number Diff line
@@ -17,8 +17,146 @@
 *
 */

#include <linux/random.h>
#include "debugfs.h"

#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

static int ufsdbg_tag_stats_show(struct seq_file *file, void *data)
@@ -262,6 +400,8 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
		goto err;
	}

	ufsdbg_setup_fault_injection(hba);

	return;

err:
+11 −1
Original line number Diff line number Diff line
@@ -27,6 +27,16 @@
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
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)
{
}
#endif

#endif /* End of Header */
+2 −0
Original line number Diff line number Diff line
@@ -3259,6 +3259,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);
+5 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>

#include <linux/fault-inject.h>

#include "ufs.h"
#include "ufshci.h"

@@ -211,6 +213,9 @@ struct debugfs_files {
	struct dentry *tag_stats;
	struct dentry *show_hba;
	struct dentry *host_regs;
#ifdef CONFIG_UFS_FAULT_INJECTION
	struct fault_attr fail_attr;
#endif
};
#endif

+14 −0
Original line number Diff line number Diff line
@@ -1274,6 +1274,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