Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: ufs: core: Make fault injection dynamically configurable per HBA

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>

authored by

Akinobu Mita and committed by
Martin K. Petersen
045da307 edbc78a1

+32 -10
+15 -4
drivers/ufs/core/ufs-fault-injection.c
··· 4 4 #include <linux/types.h> 5 5 #include <linux/fault-inject.h> 6 6 #include <linux/module.h> 7 + #include <ufs/ufshcd.h> 7 8 #include "ufs-fault-injection.h" 8 9 9 10 static int ufs_fault_get(char *buffer, const struct kernel_param *kp); ··· 60 59 return 0; 61 60 } 62 61 63 - bool ufs_trigger_eh(void) 62 + void ufs_fault_inject_hba_init(struct ufs_hba *hba) 64 63 { 65 - return should_fail(&ufs_trigger_eh_attr, 1); 64 + hba->trigger_eh_attr = ufs_trigger_eh_attr; 65 + hba->timeout_attr = ufs_timeout_attr; 66 + #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS 67 + fault_create_debugfs_attr("trigger_eh_inject", hba->debugfs_root, &hba->trigger_eh_attr); 68 + fault_create_debugfs_attr("timeout_inject", hba->debugfs_root, &hba->timeout_attr); 69 + #endif 66 70 } 67 71 68 - bool ufs_fail_completion(void) 72 + bool ufs_trigger_eh(struct ufs_hba *hba) 69 73 { 70 - return should_fail(&ufs_timeout_attr, 1); 74 + return should_fail(&hba->trigger_eh_attr, 1); 75 + } 76 + 77 + bool ufs_fail_completion(struct ufs_hba *hba) 78 + { 79 + return should_fail(&hba->timeout_attr, 1); 71 80 }
+9 -4
drivers/ufs/core/ufs-fault-injection.h
··· 7 7 #include <linux/types.h> 8 8 9 9 #ifdef CONFIG_SCSI_UFS_FAULT_INJECTION 10 - bool ufs_trigger_eh(void); 11 - bool ufs_fail_completion(void); 10 + void ufs_fault_inject_hba_init(struct ufs_hba *hba); 11 + bool ufs_trigger_eh(struct ufs_hba *hba); 12 + bool ufs_fail_completion(struct ufs_hba *hba); 12 13 #else 13 - static inline bool ufs_trigger_eh(void) 14 + static inline void ufs_fault_inject_hba_init(struct ufs_hba *hba) 15 + { 16 + } 17 + 18 + static inline bool ufs_trigger_eh(struct ufs_hba *hba) 14 19 { 15 20 return false; 16 21 } 17 22 18 - static inline bool ufs_fail_completion(void) 23 + static inline bool ufs_fail_completion(struct ufs_hba *hba) 19 24 { 20 25 return false; 21 26 }
+3 -2
drivers/ufs/core/ufshcd.c
··· 2992 2992 ufshcd_send_command(hba, tag, hwq); 2993 2993 2994 2994 out: 2995 - if (ufs_trigger_eh()) { 2995 + if (ufs_trigger_eh(hba)) { 2996 2996 unsigned long flags; 2997 2997 2998 2998 spin_lock_irqsave(hba->host->host_lock, flags); ··· 5649 5649 !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR)) 5650 5650 ufshcd_reset_intr_aggr(hba); 5651 5651 5652 - if (ufs_fail_completion()) 5652 + if (ufs_fail_completion(hba)) 5653 5653 return IRQ_HANDLED; 5654 5654 5655 5655 /* ··· 9348 9348 goto out_disable_vreg; 9349 9349 9350 9350 ufs_debugfs_hba_init(hba); 9351 + ufs_fault_inject_hba_init(hba); 9351 9352 9352 9353 hba->is_powered = true; 9353 9354 goto out;
+5
include/ufs/ufshcd.h
··· 16 16 #include <linux/blk-crypto-profile.h> 17 17 #include <linux/blk-mq.h> 18 18 #include <linux/devfreq.h> 19 + #include <linux/fault-inject.h> 19 20 #include <linux/msi.h> 20 21 #include <linux/pm_runtime.h> 21 22 #include <linux/dma-direction.h> ··· 1058 1057 struct dentry *debugfs_root; 1059 1058 struct delayed_work debugfs_ee_work; 1060 1059 u32 debugfs_ee_rate_limit_ms; 1060 + #endif 1061 + #ifdef CONFIG_SCSI_UFS_FAULT_INJECTION 1062 + struct fault_attr trigger_eh_attr; 1063 + struct fault_attr timeout_attr; 1061 1064 #endif 1062 1065 u32 luns_avail; 1063 1066 unsigned int nr_hw_queues;