scsi: ufs: core: Make fault injection dynamically configurable per HBA
authorAkinobu Mita <akinobu.mita@gmail.com>
Sat, 18 Nov 2023 12:44:43 +0000 (21:44 +0900)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 25 Nov 2023 00:23:35 +0000 (19:23 -0500)
The UFS driver has two driver-specific fault injection mechanisms
(trigger_eh and timeout). Each fault injection configuration can only be
specified by a module parameter and cannot be reconfigured without
reloading the driver. Also, each configuration is common to all HBAs.

This change adds the following subdirectories for each UFS HBA when
debugfs is enabled:

  /sys/kernel/debug/ufshcd/<HBA>/timeout_inject
  /sys/kernel/debug/ufshcd/<HBA>/trigger_eh_inject

Each fault injection attribute can be dynamically set per HBA by a
corresponding file in these directories.

This is tested with QEMU UFS devices.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Link: https://lore.kernel.org/r/20231118124443.1007116-1-akinobu.mita@gmail.com
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/core/ufs-fault-injection.c
drivers/ufs/core/ufs-fault-injection.h
drivers/ufs/core/ufshcd.c
include/ufs/ufshcd.h

index 5b1184aac585b1e2743da2efd548fb7d447c0628..1695404170790d2a41bdd5da4d91b35216fb594a 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 #include <linux/fault-inject.h>
 #include <linux/module.h>
+#include <ufs/ufshcd.h>
 #include "ufs-fault-injection.h"
 
 static int ufs_fault_get(char *buffer, const struct kernel_param *kp);
@@ -59,12 +60,22 @@ static int ufs_fault_set(const char *val, const struct kernel_param *kp)
        return 0;
 }
 
-bool ufs_trigger_eh(void)
+void ufs_fault_inject_hba_init(struct ufs_hba *hba)
 {
-       return should_fail(&ufs_trigger_eh_attr, 1);
+       hba->trigger_eh_attr = ufs_trigger_eh_attr;
+       hba->timeout_attr = ufs_timeout_attr;
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+       fault_create_debugfs_attr("trigger_eh_inject", hba->debugfs_root, &hba->trigger_eh_attr);
+       fault_create_debugfs_attr("timeout_inject", hba->debugfs_root, &hba->timeout_attr);
+#endif
 }
 
-bool ufs_fail_completion(void)
+bool ufs_trigger_eh(struct ufs_hba *hba)
 {
-       return should_fail(&ufs_timeout_attr, 1);
+       return should_fail(&hba->trigger_eh_attr, 1);
+}
+
+bool ufs_fail_completion(struct ufs_hba *hba)
+{
+       return should_fail(&hba->timeout_attr, 1);
 }
index 6d0cd8e10c87aa6ccf28da744b43bc4a7553b55c..996a35769781896d0915add48e5650626d1297ca 100644 (file)
@@ -7,15 +7,20 @@
 #include <linux/types.h>
 
 #ifdef CONFIG_SCSI_UFS_FAULT_INJECTION
-bool ufs_trigger_eh(void);
-bool ufs_fail_completion(void);
+void ufs_fault_inject_hba_init(struct ufs_hba *hba);
+bool ufs_trigger_eh(struct ufs_hba *hba);
+bool ufs_fail_completion(struct ufs_hba *hba);
 #else
-static inline bool ufs_trigger_eh(void)
+static inline void ufs_fault_inject_hba_init(struct ufs_hba *hba)
+{
+}
+
+static inline bool ufs_trigger_eh(struct ufs_hba *hba)
 {
        return false;
 }
 
-static inline bool ufs_fail_completion(void)
+static inline bool ufs_fail_completion(struct ufs_hba *hba)
 {
        return false;
 }
index 8b1031fb0a4400fd6355be140e1ef5e99afabb74..63f0ee117399127b5bae95243bf94f60bf5ee1f5 100644 (file)
@@ -2992,7 +2992,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        ufshcd_send_command(hba, tag, hwq);
 
 out:
-       if (ufs_trigger_eh()) {
+       if (ufs_trigger_eh(hba)) {
                unsigned long flags;
 
                spin_lock_irqsave(hba->host->host_lock, flags);
@@ -5649,7 +5649,7 @@ 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())
+       if (ufs_fail_completion(hba))
                return IRQ_HANDLED;
 
        /*
@@ -9348,6 +9348,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
                goto out_disable_vreg;
 
        ufs_debugfs_hba_init(hba);
+       ufs_fault_inject_hba_init(hba);
 
        hba->is_powered = true;
        goto out;
index 7f0b2c5599cdb747836fe578195d6bac405cafef..d862c8ddce032fec2b3c0046da2946641eab7748 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/blk-crypto-profile.h>
 #include <linux/blk-mq.h>
 #include <linux/devfreq.h>
+#include <linux/fault-inject.h>
 #include <linux/msi.h>
 #include <linux/pm_runtime.h>
 #include <linux/dma-direction.h>
@@ -1057,6 +1058,10 @@ struct ufs_hba {
        struct dentry *debugfs_root;
        struct delayed_work debugfs_ee_work;
        u32 debugfs_ee_rate_limit_ms;
+#endif
+#ifdef CONFIG_SCSI_UFS_FAULT_INJECTION
+       struct fault_attr trigger_eh_attr;
+       struct fault_attr timeout_attr;
 #endif
        u32 luns_avail;
        unsigned int nr_hw_queues;