Commit c11a1ae9 authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen

scsi: ufs: Add fault injection support

Make it easier to test the UFS error handler and abort handler.

Link: https://lore.kernel.org/r/20210722033439.26550-19-bvanassche@acm.orgAcked-by: default avatarBean Huo <beanhuo@micron.com>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 73dc3c4a
......@@ -192,3 +192,10 @@ config SCSI_UFS_HPB
L2P (logical to physical) map of UFS to host DRAM. The driver uses HPB
read command by piggybacking physical page number for bypassing FTL (flash
translation layer)'s L2P address translation.
config SCSI_UFS_FAULT_INJECTION
bool "UFS Fault Injection Support"
depends on SCSI_UFSHCD && FAULT_INJECTION
help
Enable fault injection support in the UFS driver. This makes it easier
to test the UFS error handler and abort handler.
......@@ -9,6 +9,7 @@ ufshcd-core-$(CONFIG_DEBUG_FS) += ufs-debugfs.o
ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
ufshcd-core-$(CONFIG_SCSI_UFS_CRYPTO) += ufshcd-crypto.o
ufshcd-core-$(CONFIG_SCSI_UFS_HPB) += ufshpb.o
ufshcd-core-$(CONFIG_SCSI_UFS_FAULT_INJECTION) += ufs-fault-injection.o
obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o
obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o
......
// SPDX-License-Identifier: GPL-2.0-or-later
#include <linux/kconfig.h>
#include <linux/types.h>
#include <linux/fault-inject.h>
#include <linux/module.h>
#include "ufs-fault-injection.h"
static int ufs_fault_get(char *buffer, const struct kernel_param *kp);
static int ufs_fault_set(const char *val, const struct kernel_param *kp);
static const struct kernel_param_ops ufs_fault_ops = {
.get = ufs_fault_get,
.set = ufs_fault_set,
};
enum { FAULT_INJ_STR_SIZE = 80 };
/*
* For more details about fault injection, please refer to
* Documentation/fault-injection/fault-injection.rst.
*/
static char g_trigger_eh_str[FAULT_INJ_STR_SIZE];
module_param_cb(trigger_eh, &ufs_fault_ops, g_trigger_eh_str, 0644);
MODULE_PARM_DESC(trigger_eh,
"Fault injection. trigger_eh=<interval>,<probability>,<space>,<times>");
static DECLARE_FAULT_ATTR(ufs_trigger_eh_attr);
static char g_timeout_str[FAULT_INJ_STR_SIZE];
module_param_cb(timeout, &ufs_fault_ops, g_timeout_str, 0644);
MODULE_PARM_DESC(timeout,
"Fault injection. timeout=<interval>,<probability>,<space>,<times>");
static DECLARE_FAULT_ATTR(ufs_timeout_attr);
static int ufs_fault_get(char *buffer, const struct kernel_param *kp)
{
const char *fault_str = kp->arg;
return sysfs_emit(buffer, "%s\n", fault_str);
}
static int ufs_fault_set(const char *val, const struct kernel_param *kp)
{
struct fault_attr *attr = NULL;
if (kp->arg == g_trigger_eh_str)
attr = &ufs_trigger_eh_attr;
else if (kp->arg == g_timeout_str)
attr = &ufs_timeout_attr;
if (WARN_ON_ONCE(!attr))
return -EINVAL;
if (!setup_fault_attr(attr, (char *)val))
return -EINVAL;
strlcpy(kp->arg, val, FAULT_INJ_STR_SIZE);
return 0;
}
bool ufs_trigger_eh(void)
{
return should_fail(&ufs_trigger_eh_attr, 1);
}
bool ufs_fail_completion(void)
{
return should_fail(&ufs_timeout_attr, 1);
}
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _UFS_FAULT_INJECTION_H
#define _UFS_FAULT_INJECTION_H
#include <linux/kconfig.h>
#include <linux/types.h>
#ifdef CONFIG_SCSI_UFS_FAULT_INJECTION
bool ufs_trigger_eh(void);
bool ufs_fail_completion(void);
#else
static inline bool ufs_trigger_eh(void)
{
return false;
}
static inline bool ufs_fail_completion(void)
{
return false;
}
#endif
#endif /* _UFS_FAULT_INJECTION_H */
......@@ -24,6 +24,7 @@
#include "unipro.h"
#include "ufs-sysfs.h"
#include "ufs-debugfs.h"
#include "ufs-fault-injection.h"
#include "ufs_bsg.h"
#include "ufshcd-crypto.h"
#include "ufshpb.h"
......@@ -2758,6 +2759,10 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
ufshcd_send_command(hba, tag);
out:
up_read(&hba->clk_scaling_lock);
if (ufs_trigger_eh())
scsi_schedule_eh(hba->host);
return err;
}
......@@ -5314,6 +5319,9 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba,
!(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR))
ufshcd_reset_intr_aggr(hba);
if (ufs_fail_completion())
return IRQ_HANDLED;
spin_lock_irqsave(&hba->outstanding_lock, flags);
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = ~tr_doorbell & hba->outstanding_reqs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment