mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-28 23:23:55 +08:00
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.org Acked-by: Bean Huo <beanhuo@micron.com> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
73dc3c4ac7
commit
c11a1ae9b8
@ -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
|
||||
|
70
drivers/scsi/ufs/ufs-fault-injection.c
Normal file
70
drivers/scsi/ufs/ufs-fault-injection.c
Normal file
@ -0,0 +1,70 @@
|
||||
// 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);
|
||||
}
|
24
drivers/scsi/ufs/ufs-fault-injection.h
Normal file
24
drivers/scsi/ufs/ufs-fault-injection.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* 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;
|
||||
|
Loading…
Reference in New Issue
Block a user