162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/kconfig.h>
462306a36Sopenharmony_ci#include <linux/types.h>
562306a36Sopenharmony_ci#include <linux/fault-inject.h>
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include "ufs-fault-injection.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistatic int ufs_fault_get(char *buffer, const struct kernel_param *kp);
1062306a36Sopenharmony_cistatic int ufs_fault_set(const char *val, const struct kernel_param *kp);
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic const struct kernel_param_ops ufs_fault_ops = {
1362306a36Sopenharmony_ci	.get = ufs_fault_get,
1462306a36Sopenharmony_ci	.set = ufs_fault_set,
1562306a36Sopenharmony_ci};
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cienum { FAULT_INJ_STR_SIZE = 80 };
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * For more details about fault injection, please refer to
2162306a36Sopenharmony_ci * Documentation/fault-injection/fault-injection.rst.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_cistatic char g_trigger_eh_str[FAULT_INJ_STR_SIZE];
2462306a36Sopenharmony_cimodule_param_cb(trigger_eh, &ufs_fault_ops, g_trigger_eh_str, 0644);
2562306a36Sopenharmony_ciMODULE_PARM_DESC(trigger_eh,
2662306a36Sopenharmony_ci	"Fault injection. trigger_eh=<interval>,<probability>,<space>,<times>");
2762306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(ufs_trigger_eh_attr);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic char g_timeout_str[FAULT_INJ_STR_SIZE];
3062306a36Sopenharmony_cimodule_param_cb(timeout, &ufs_fault_ops, g_timeout_str, 0644);
3162306a36Sopenharmony_ciMODULE_PARM_DESC(timeout,
3262306a36Sopenharmony_ci	"Fault injection. timeout=<interval>,<probability>,<space>,<times>");
3362306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(ufs_timeout_attr);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int ufs_fault_get(char *buffer, const struct kernel_param *kp)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	const char *fault_str = kp->arg;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return sysfs_emit(buffer, "%s\n", fault_str);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int ufs_fault_set(const char *val, const struct kernel_param *kp)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct fault_attr *attr = NULL;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (kp->arg == g_trigger_eh_str)
4762306a36Sopenharmony_ci		attr = &ufs_trigger_eh_attr;
4862306a36Sopenharmony_ci	else if (kp->arg == g_timeout_str)
4962306a36Sopenharmony_ci		attr = &ufs_timeout_attr;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (WARN_ON_ONCE(!attr))
5262306a36Sopenharmony_ci		return -EINVAL;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (!setup_fault_attr(attr, (char *)val))
5562306a36Sopenharmony_ci		return -EINVAL;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	strscpy(kp->arg, val, FAULT_INJ_STR_SIZE);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return 0;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cibool ufs_trigger_eh(void)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	return should_fail(&ufs_trigger_eh_attr, 1);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cibool ufs_fail_completion(void)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	return should_fail(&ufs_timeout_attr, 1);
7062306a36Sopenharmony_ci}
71