Add ioctl and debug utilities to UFS driver
Subsystems (5)
v2 cover Add ioctl and debug utilities to UFS driver
Changes from V1:
- Renamed debugfs.* to ufs-debugfs.*
- Added host controller instance number to ufs debug-fs entry name.
- Removed FTRACE_EVENT_ENABLED macro as it was redundant.
Dolev Raviv (1):
scsi: ufs: add ioctl interface for query request
Gilad Broner (1):
scsi: ufs: add trace events and dump prints for debug
Lee Susman (1):
scsi: ufs: add debugfs for ufs
Sujit Reddy Thumma (1):
scsi: ufs: inject errors to verify error handling
drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ufs-debugfs.c | 1042 ++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-debugfs.h | 42 ++ drivers/scsi/ufs/ufs-qcom.c | 53 ++ drivers/scsi/ufs/ufs.h | 53 +- drivers/scsi/ufs/ufshcd.c | 964 +++++++++++++++++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 115 +++++ drivers/scsi/ufs/ufshci.h | 3 + include/trace/events/ufs.h | 227 +++++++++ include/uapi/scsi/Kbuild | 1 + include/uapi/scsi/ufs/Kbuild | 3 + include/uapi/scsi/ufs/ioctl.h | 57 +++ include/uapi/scsi/ufs/ufs.h | 66 +++ lib/Kconfig.debug | 14 + 14 files changed, 2557 insertions(+), 84 deletions(-) create mode 100644 drivers/scsi/ufs/ufs-debugfs.c create mode 100644 drivers/scsi/ufs/ufs-debugfs.h create mode 100644 include/trace/events/ufs.h create mode 100644 include/uapi/scsi/ufs/Kbuild create mode 100644 include/uapi/scsi/ufs/ioctl.h create mode 100644 include/uapi/scsi/ufs/ufs.h
Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 1/4 scsi: ufs: add ioctl interface for query request
From: Dolev Raviv <[email protected]>
This patch exposes the ioctl interface for UFS driver via SCSI device ioctl interface. As of now UFS driver would provide the ioctl for query interface to connected UFS device.
--- drivers/scsi/ufs/ufs.h | 53 +++------- drivers/scsi/ufs/ufshcd.c | 225 +++++++++++++++++++++++++++++++++++++++++- include/uapi/scsi/Kbuild | 1 + include/uapi/scsi/ufs/Kbuild | 3 + include/uapi/scsi/ufs/ioctl.h | 57 +++++++++++ include/uapi/scsi/ufs/ufs.h | 66 +++++++++++++ 6 files changed, 361 insertions(+), 44 deletions(-) create mode 100644 include/uapi/scsi/ufs/Kbuild create mode 100644 include/uapi/scsi/ufs/ioctl.h create mode 100644 include/uapi/scsi/ufs/ufs.h
drivers/scsi/ufs/ufs.h +11 -42
@@ -38,6 +38,7 @@#include <linux/mutex.h> #include <linux/types.h> +#include <scsi/ufs/ufs.h> #define MAX_CDB_SIZE 16#define GENERAL_UPIU_REQUEST_SIZE 32
@@ -71,6 +72,16 @@ enum { UFS_UPIU_RPMB_WLUN = 0xC4, }; +/** +* ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor +* @lun: LU number to check +* @return: true if the lun has a matching unit descriptor, false otherwise +*/ +static inline bool ufs_is_valid_unit_desc_lun (u8 lun) +{ +return (lun ==UFS_UPIU_RPMB_WLUN || (lun <UFS_UPIU_MAX_GENERAL_LUN )); +} +/* * UFS Protocol Information Unit related definitions */
@@ -126,35 +137,6 @@ enum { UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81, }; -/* Flag idn for Query Requests*/ -enum flag_idn { -QUERY_FLAG_IDN_FDEVICEINIT =0x01 , -QUERY_FLAG_IDN_PWR_ON_WPE =0x03 , -QUERY_FLAG_IDN_BKOPS_EN =0x04 , -}; - -/* Attribute idn for Query requests */ -enum attr_idn { -QUERY_ATTR_IDN_ACTIVE_ICC_LVL =0x03 , -QUERY_ATTR_IDN_BKOPS_STATUS =0x05 , -QUERY_ATTR_IDN_EE_CONTROL =0x0D , -QUERY_ATTR_IDN_EE_STATUS =0x0E , -}; - -/* Descriptor idn for Query requests */ -enum desc_idn { -QUERY_DESC_IDN_DEVICE =0x0 , -QUERY_DESC_IDN_CONFIGURAION =0x1 , -QUERY_DESC_IDN_UNIT =0x2 , -QUERY_DESC_IDN_RFU_0 =0x3 , -QUERY_DESC_IDN_INTERCONNECT =0x4 , -QUERY_DESC_IDN_STRING =0x5 , -QUERY_DESC_IDN_RFU_1 =0x6 , -QUERY_DESC_IDN_GEOMETRY =0x7 , -QUERY_DESC_IDN_POWER =0x8 , -QUERY_DESC_IDN_MAX , -}; -enum desc_header_offset {QUERY_DESC_LENGTH_OFFSET =0x00 ,QUERY_DESC_DESC_TYPE_OFFSET =0x01 ,
@@ -247,19 +229,6 @@ enum bkops_status { BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL, }; -/* UTP QUERY Transaction Specific Fields OpCode */ -enum query_opcode { -UPIU_QUERY_OPCODE_NOP =0x0 , -UPIU_QUERY_OPCODE_READ_DESC =0x1 , -UPIU_QUERY_OPCODE_WRITE_DESC =0x2 , -UPIU_QUERY_OPCODE_READ_ATTR =0x3 , -UPIU_QUERY_OPCODE_WRITE_ATTR =0x4 , -UPIU_QUERY_OPCODE_READ_FLAG =0x5 , -UPIU_QUERY_OPCODE_SET_FLAG =0x6 , -UPIU_QUERY_OPCODE_CLEAR_FLAG =0x7 , -UPIU_QUERY_OPCODE_TOGGLE_FLAG =0x8 , -}; -/* Query response result code */ enum {QUERY_RESULT_SUCCESS =0x00 ,
drivers/scsi/ufs/ufshcd.c +223 -2
261 lines not on this page · raw message
include/uapi/scsi/Kbuild +1 -0
@@ -1,5 +1,6 @@ # UAPI Header export list header-y += fc/ +header-y += ufs/ header-y += scsi_bsg_fc.h header-y += scsi_netlink.h header-y += scsi_netlink_fc.h
include/uapi/scsi/ufs/Kbuild new file +3 -0
@@ -0,0 +1,3 @@ +# UAPI Header export list +header-y += ioctl.h +header-y += ufs.h
include/uapi/scsi/ufs/ioctl.h new file +57 -0
57 lines not on this page · raw message
include/uapi/scsi/ufs/ufs.h new file +66 -0
66 lines not on this page · raw message
Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 2/4 scsi: ufs: add debugfs for ufs
In reply to Gilad BronerFrom: Lee Susman <[email protected]>
Adding debugfs capability for ufshcd.
debugfs attributes introduced in this patch:
- View driver/controller runtime data
- Command tag statistics for performance analisis
- Dump device descriptor info
- Track recoverable errors statistics during runtime
- Change UFS power mode during runtime
entry a string in the format 'GGLLMM' where:
G - selected gear
L - number of lanes
M - power mode
(1=fast mode, 2=slow mode, 4=fast-auto mode,
5=slow-auto mode)
First letter is for RX, second is for TX.
- Get/set DME attributes
--- drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ufs-debugfs.c | 902 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-debugfs.h | 32 ++ drivers/scsi/ufs/ufshcd.c | 230 ++++++++++- drivers/scsi/ufs/ufshcd.h | 65 +++ drivers/scsi/ufs/ufshci.h | 2 + 6 files changed, 1220 insertions(+), 12 deletions(-) create mode 100644 drivers/scsi/ufs/ufs-debugfs.c create mode 100644 drivers/scsi/ufs/ufs-debugfs.h
drivers/scsi/ufs/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o +obj-$(CONFIG_DEBUG_FS) += ufs-debugfs.o
drivers/scsi/ufs/ufs-debugfs.c new file +902 -0
902 lines not on this page · raw message
drivers/scsi/ufs/ufs-debugfs.h new file +32 -0
@@ -0,0 +1,32 @@ +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* UFS debugfs - add debugfs interface to the ufshcd. +* This is currently used for statistics collection and exporting from the +* UFS driver. +* This infrastructure can be used for debugging or direct tweaking +* of the driver from userspace. +* +*/ + +#ifndef _UFS_DEBUGFS_H +#define _UFS_DEBUGFS_H + +#include <linux/debugfs.h> +#include "ufshcd.h" + +#ifdef CONFIG_DEBUG_FS +void ufsdbg_add_debugfs (struct ufs_hba *hba); + +void ufsdbg_remove_debugfs (struct ufs_hba *hba); +#endif + +#endif /* End of Header */
drivers/scsi/ufs/ufshcd.c +218 -12
400 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.h +65 -0
99 lines not on this page · raw message
drivers/scsi/ufs/ufshci.h +2 -0
@@ -72,6 +72,8 @@ enum {REG_UIC_COMMAND_ARG_1 =0x94 ,REG_UIC_COMMAND_ARG_2 =0x98 ,REG_UIC_COMMAND_ARG_3 =0x9C , + + UFSHCI_REG_SPACE_SIZE = 0xA0, };/* Controller capability masks */
Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v2 2/4] scsi: ufs: add debugfs for ufs
2015-02-10 22:58 GMT+09:00 Gilad Broner <[email protected]>:
Quoted 10 lines
drivers/scsi/ufs/ufshcd.c +2
-0@@ -5760,6 +5963,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)async_schedule (ufshcd_async_scan, hba); +UFSDBG_ADD_DEBUGFS (hba); +return 0 ; out_remove_scsi_host:
drivers/scsi/ufs/ufshcd.c exit_gating: · line 5980
Quoted 7 lines
drivers/scsi/ufs/ufshcd.c +1
-0@@ -5769,6 +5974,7 @@ exit_gating: out_disable: hba->is_irq_enabled = false;scsi_host_put (host); +UFSDBG_REMOVE_DEBUGFS (hba);ufshcd_hba_exit (hba); out_error:return err;
UFSDBG_REMOVE_DEBUGFS() is not called in the driver unloading path. So ufs debugfs directory is not removed when unloading driver. It should be called in ufshcd_remove().
BTW, do we really need UFSDBG_ADD_DEBUGFS() and UFSDBG_REMOVE_DEBUGFS() macros?
We can use static inline functions in ufs-debugfs.h when !CONFIG_DEBUG_FS.
#ifdef CONFIG_DEBUG_FS
void ufsdbg_add_debugfs(struct ufs_hba *hba);
void ufsdbg_remove_debugfs(struct ufs_hba *hba); #else
static inline void ufsdbg_add_debugfs(struct ufs_hba *hba) {
}
static inline void ufsdbg_remove_debugfs(struct ufs_hba *hba) {
}
#endif
Re: [PATCH v2 2/4] scsi: ufs: add debugfs for ufs
Quoted 17 lines
UFSDBG_REMOVE_DEBUGFS()is not called in the driver unloading path. So ufs debugfs directory is not removed when unloading driver. It should be called inufshcd_remove().BTW, do we really need
UFSDBG_ADD_DEBUGFS()andUFSDBG_REMOVE_DEBUGFS()macros?
We can use static inline functions inufs-debugfs.hwhen !CONFIG_DEBUG_FS.#ifdef
CONFIG_DEBUG_FS
voidufsdbg_add_debugfs(struct ufs_hba *hba);void
ufsdbg_remove_debugfs(struct ufs_hba *hba); #else
static inline voidufsdbg_add_debugfs(struct ufs_hba *hba){
}
Quoted 5 lines
static inline void
ufsdbg_remove_debugfs(struct ufs_hba *hba){
}
#endif
Thanks, I will fix the above two points and upload another patch.
Gilad.
Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 3/4 scsi: ufs: add trace events and dump prints for debug
In reply to Gilad BronerAdd trace events to driver to allow monitoring and profilig of activities such as PM suspend/resume, hibernate enter/exit, clock gating and clock scaling up/down.
In addition, add UFS host controller register dumps to provide detailed information in case of errors to assist in analysis of issues.
--- drivers/scsi/ufs/ufs-qcom.c | 53 +++++ drivers/scsi/ufs/ufshcd.c | 509 +++++++++++++++++++++++++++++++++++++++++--- drivers/scsi/ufs/ufshcd.h | 49 ++++- drivers/scsi/ufs/ufshci.h | 1 + include/trace/events/ufs.h | 227 ++++++++++++++++++++ 5 files changed, 808 insertions(+), 31 deletions(-) create mode 100644 include/trace/events/ufs.h
drivers/scsi/ufs/ufs-qcom.c +53 -0
@@ -30,6 +30,14 @@ static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, const char *speed_mode);static int ufs_qcom_set_bus_vote (struct ufs_qcom_host *host,int vote); +static void ufs_qcom_dump_regs (struct ufs_hba *hba,int offset,int len, +char *prefix) +{ +print_hex_dump (KERN_ERR , prefix, + len >4 ?DUMP_PREFIX_OFFSET :DUMP_PREFIX_NONE , +16 ,4 , hba->mmio_base + offset, len *4 , false); +} +static int ufs_qcom_get_connected_tx_lanes (struct ufs_hba *hba,u32 *tx_lanes) {int err =0 ;
@@ -983,6 +991,50 @@ void ufs_qcom_clk_scale_notify(struct ufs_hba *hba) dev_req_params->hs_rate); } +static void ufs_qcom_print_hw_debug_reg_all (struct ufs_hba *hba) +{ +u32 reg; + +ufs_qcom_dump_regs (hba,UFS_UFS_DBG_RD_REG_OCSC ,44 , +"UFS_UFS_DBG_RD_REG_OCSC " ); + + reg =ufshcd_readl (hba,REG_UFS_CFG1 ); + reg |=UFS_BIT (17 ); +ufshcd_writel (hba, reg,REG_UFS_CFG1 ); + +ufs_qcom_dump_regs (hba,UFS_UFS_DBG_RD_EDTL_RAM ,32 , +"UFS_UFS_DBG_RD_EDTL_RAM " ); +ufs_qcom_dump_regs (hba,UFS_UFS_DBG_RD_DESC_RAM ,128 , +"UFS_UFS_DBG_RD_DESC_RAM " ); +ufs_qcom_dump_regs (hba,UFS_UFS_DBG_RD_PRDT_RAM ,64 , +"UFS_UFS_DBG_RD_PRDT_RAM " ); + +ufshcd_writel (hba, (reg & ~UFS_BIT (17 )),REG_UFS_CFG1 ); + +ufs_qcom_dump_regs (hba,UFS_DBG_RD_REG_UAWM ,4 , +"UFS_DBG_RD_REG_UAWM " ); +ufs_qcom_dump_regs (hba,UFS_DBG_RD_REG_UARM ,4 , +"UFS_DBG_RD_REG_UARM " ); +ufs_qcom_dump_regs (hba,UFS_DBG_RD_REG_TXUC ,48 , +"UFS_DBG_RD_REG_TXUC " ); +ufs_qcom_dump_regs (hba,UFS_DBG_RD_REG_RXUC ,27 , +"UFS_DBG_RD_REG_RXUC " ); +ufs_qcom_dump_regs (hba,UFS_DBG_RD_REG_DFC ,19 , +"UFS_DBG_RD_REG_DFC " ); +ufs_qcom_dump_regs (hba,UFS_DBG_RD_REG_TRLUT ,34 , +"UFS_DBG_RD_REG_TRLUT " ); +ufs_qcom_dump_regs (hba,UFS_DBG_RD_REG_TMRLUT ,9 , +"UFS_DBG_RD_REG_TMRLUT " ); +} + +static void ufs_qcom_dump_dbg_regs (struct ufs_hba *hba) +{ +ufs_qcom_dump_regs (hba,REG_UFS_SYS1CLK_1US ,5 , +"REG_UFS_SYS1CLK_1US " ); + +ufs_qcom_print_hw_debug_reg_all (hba); +} +/** * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations *
@@ -1000,5 +1052,6 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .pwr_change_notify = ufs_qcom_pwr_change_notify, .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, + .dbg_register_dump = ufs_qcom_dump_dbg_regs, };EXPORT_SYMBOL (ufs_hba_qcom_vops);
drivers/scsi/ufs/ufshcd.c +480 -29
919 lines not on this page · raw message
drivers/scsi/ufs/ufshcd.h +47 -2
95 lines not on this page · raw message
drivers/scsi/ufs/ufshci.h +1 -0
@@ -166,6 +166,7 @@ enum {/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */ #define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31)#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F +#define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK 0xF/* UECDL - Host UIC Error Code Data Link Layer 3Ch */ #define UIC_DATA_LINK_LAYER_ERROR UFS_BIT(31)
include/trace/events/ufs.h new file +227 -0
227 lines not on this page · raw message
Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Steven Rostedt
maintainerRe: [PATCH v2 3/4] scsi: ufs: add trace events and dump prints for debug
On Tue, 10 Feb 2015 15:58:54 +0200
Gilad Broner <[email protected]> wrote:
I really hate large patches like this. So much to dig through.
Quoted 27 lines
drivers/scsi/ufs/ufshcd.h +26
-1-#ifdef CONFIG_DEBUG_FS +#define UIC_ERR_REG_HIST_LENGTH 8 +/** +* struct ufs_uic_err_reg_hist - keeps history of uic errors +* @pos: index to indicate cyclic buffer position +* @reg: cyclic buffer for registers value +* @tstamp: cyclic buffer for time stamp +*/ +struct ufs_uic_err_reg_hist { +int pos; +u32 reg[UIC_ERR_REG_HIST_LENGTH ]; +ktime_t tstamp[UIC_ERR_REG_HIST_LENGTH ]; +}; + +/** +* struct ufs_stats - keeps usage/err statistics +* @enabled: enable tagstats for debugfs +* @tag_stats: pointer to tag statistic counters +* @q_depth: current amount of busy slots +* @err_stats: counters to keep track of various errors +* @hibern8_exit_cnt: Counter to keep track of number of exits, +* reset this after link-startup. +* @last_hibern8_exit_tstamp: Set time after the hibern8 exit. +* Clear after the first successful command completion. +* @pa_err: tracks pa-uic errors +* @dl_err: tracks dl-uic errors +* @nl_err: tracks nl-uic errors
drivers/scsi/ufs/ufshcd.h struct ufs_dev_cmd { · line 263
Quoted 10 lines
drivers/scsi/ufs/ufshcd.h +5
-0+* @tl_err: tracks tl-uic errors +* @dme_err: tracks dme errors +*/ struct ufs_stats { +#ifdef CONFIG_DEBUG_FS bool enabled;u64 **tag_stats;int q_depth;int err_stats[UFS_ERR_MAX ]; +#endif
Can any of the tracepoint code be called that references these when CONFIG_DEBUG_FS is not set? Because soon (possibly even this merge window), tracing will no longer depend on DEBUG_FS, because it will have its own filesystem.
-- Steve
Re: [PATCH v2 3/4] scsi: ufs: add trace events and dump prints for debug
Quoted 4 lines
Quoted 4 lines
struct
ufs_stats{drivers/scsi/ufs/ufshcd.h +1
-0+#ifdef CONFIG_DEBUG_FS bool enabled;u64 **tag_stats;
Quoted 8 lines
drivers/scsi/ufs/ufshcd.h struct ufs_dev_cmd { · line 263
Quoted 3 lines
drivers/scsi/ufs/ufshcd.h +1
-0int q_depth;int err_stats[UFS_ERR_MAX ]; +#endif Can any of the tracepoint code be called that references these when
CONFIG_DEBUG_FSis not set? Because soon (possibly even this merge window), tracing will no longer depend onDEBUG_FS, because it will have its own filesystem.
Thanks for the update about this dependency.
None of these are used for the tracepoints, so I don't expect any problems.
Gilad.
Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 4/4 scsi: ufs: inject errors to verify error handling
In reply to Gilad BronerFrom: Sujit Reddy Thumma <[email protected]>
Use fault-injection framework to simulate error conditions in the controller and verify error handling mechanisms implemented in UFS host controller driver.
This is used only during development and hence guarded by CONFIG_UFS_FAULT_INJECTION debug config option.
--- drivers/scsi/ufs/ufs-debugfs.c | 140 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-debugfs.h | 12 +++- drivers/scsi/ufs/ufshcd.c | 2 + drivers/scsi/ufs/ufshcd.h | 5 ++ lib/Kconfig.debug | 14 +++++ 5 files changed, 172 insertions(+), 1 deletion(-)
drivers/scsi/ufs/ufs-debugfs.c +140 -0
@@ -17,6 +17,7 @@* */ +#include <linux/random.h> #include "ufs-debugfs.h" #include "unipro.h"
@@ -41,6 +42,143 @@ struct desc_field_offset { } while (0)#define DOORBELL_CLR_TOUT_US (1000 * 1000)/* 1 sec */ +#ifdef CONFIG_UFS_FAULT_INJECTION + +#define INJECT_COMMAND_HANG (0x0) + +static DECLARE_FAULT_ATTR (fail_default_attr); +static char *fail_request; +module_param (fail_request, charp,0 ); + +static bool inject_fatal_err_tr (struct ufs_hba *hba,u8 ocs_err) +{ +int tag; + + tag =find_first_bit (&hba->outstanding_reqs, hba->nutrs); +if (tag == hba->nutrs) +return 0 ; + +ufshcd_writel (hba, ~(1 << tag),REG_UTP_TRANSFER_REQ_LIST_CLEAR ); + (&hba->lrb[tag])->utr_descriptor_ptr->header.dword_2 = +cpu_to_be32 (ocs_err); + +/* fatal error injected */ +return 1 ; +} + +static bool inject_fatal_err_tm (struct ufs_hba *hba,u8 ocs_err) +{ +int tag; + + tag =find_first_bit (&hba->outstanding_tasks, hba->nutmrs); +if (tag == hba->nutmrs) +return 0 ; + +ufshcd_writel (hba, ~(1 << tag),REG_UTP_TASK_REQ_LIST_CLEAR ); + (&hba->utmrdl_base_addr[tag])->header.dword_2 = +cpu_to_be32 (ocs_err); + +/* fatal error injected */ +return 1 ; +} + +static bool inject_cmd_hang_tr (struct ufs_hba *hba) +{ +int tag; + + tag =find_first_bit (&hba->outstanding_reqs, hba->nutrs); +if (tag == hba->nutrs) +return 0 ; + +__clear_bit (tag, &hba->outstanding_reqs); + hba->lrb[tag].cmd =NULL ; +__clear_bit (tag, &hba->lrb_in_use); + +/* command hang injected */ +return 1 ; +} + +static int inject_cmd_hang_tm (struct ufs_hba *hba) +{ +int tag; + + tag =find_first_bit (&hba->outstanding_tasks, hba->nutmrs); +if (tag == hba->nutmrs) +return 0 ; + +__clear_bit (tag, &hba->outstanding_tasks); +__clear_bit (tag, &hba->tm_slots_in_use); + +/* command hang injected */ +return 1 ; +} + +void ufsdbg_fail_request (struct ufs_hba *hba,u32 *intr_status) +{ +u8 ocs_err; +static const u32 errors[] = { +CONTROLLER_FATAL_ERROR , +SYSTEM_BUS_FATAL_ERROR , +INJECT_COMMAND_HANG , + }; + +if (!should_fail (&hba->debugfs_files.fail_attr,1 )) + goto out; + + *intr_status = errors[prandom_u32 () %ARRAY_SIZE (errors)]; +dev_info (hba->dev,"%s: fault-inject error: 0x%x\n" , + __func__, *intr_status); + +switch (*intr_status) { +case CONTROLLER_FATAL_ERROR :/* fall through */ + ocs_err =OCS_FATAL_ERROR ; + goto set_ocs; +case SYSTEM_BUS_FATAL_ERROR : + ocs_err =OCS_INVALID_CMD_TABLE_ATTR ; +set_ocs: +if (!inject_fatal_err_tr (hba, ocs_err)) +if (!inject_fatal_err_tm (hba, ocs_err)) + *intr_status =0 ; +break ; +case INJECT_COMMAND_HANG : +if (!inject_cmd_hang_tr (hba)) +inject_cmd_hang_tm (hba); +break ; +default : +BUG (); +/* some configurations ignore panics caused by BUG() */ +break ; + } +out: +return ; +} + +static void ufsdbg_setup_fault_injection (struct ufs_hba *hba) +{ + hba->debugfs_files.fail_attr = fail_default_attr; + +if (fail_request) +setup_fault_attr (&hba->debugfs_files.fail_attr, fail_request); + +/* suppress dump stack everytime failure is injected */ + hba->debugfs_files.fail_attr.verbose =0 ; + +if (IS_ERR (fault_create_debugfs_attr ("inject_fault" , + hba->debugfs_files.debugfs_root, + &hba->debugfs_files.fail_attr))) +dev_err (hba->dev,"%s: failed to create debugfs entry\n" , + __func__); +} +#else +void ufsdbg_fail_request (struct ufs_hba *hba,u32 *intr_status) +{ +} + +static void ufsdbg_setup_fault_injection (struct ufs_hba *hba) +{ +} +#endif /* CONFIG_UFS_FAULT_INJECTION */ +#define BUFF_LINE_CAPACITY 16#define TAB_CHARS 8
@@ -885,6 +1023,8 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba) goto err; } +ufsdbg_setup_fault_injection (hba); +return ; err:
drivers/scsi/ufs/ufs-debugfs.h +11 -1
@@ -27,6 +27,16 @@void ufsdbg_add_debugfs (struct ufs_hba *hba);void ufsdbg_remove_debugfs (struct ufs_hba *hba); +void ufsdbg_fail_request (struct ufs_hba *hba,u32 *intr_status); +#else +void ufsdbg_add_debugfs (struct ufs_hba *hba) +{ +} +void ufsdbg_remove_debugfs (struct ufs_hba *hba) +{ +} +void ufsdbg_fail_request (struct ufs_hba *hba,u32 *intr_status) +{ +}#endif -#endif /* End of Header */
drivers/scsi/ufs/ufshcd.c +2 -0
@@ -4009,6 +4009,8 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)*/ static void ufshcd_sl_intr (struct ufs_hba *hba,u32 intr_status) { +ufsdbg_fail_request (hba, &intr_status); + hba->errors =UFSHCD_ERROR_MASK & intr_status;if (hba->errors)ufshcd_check_errors (hba);
drivers/scsi/ufs/ufshcd.h +5 -0
@@ -64,6 +64,8 @@#include <scsi/scsi_dbg.h> #include <scsi/scsi_eh.h> +#include <linux/fault-inject.h> +#include "ufs.h" #include "ufshci.h"
@@ -283,6 +285,9 @@ struct debugfs_files {struct dentry *dme_peer_read;u32 dme_local_attr_id;u32 dme_peer_attr_id; +#ifdef CONFIG_UFS_FAULT_INJECTION +struct fault_attr fail_attr; +#endif };/* tag stats statistics types */
lib/Kconfig.debug +14 -0
@@ -1432,6 +1432,20 @@ config FAIL_MMC_REQUEST and to test how the mmc host driver handles retries from the block device. +config UFS_FAULT_INJECTION + bool "Fault-injection capability for UFS IO" + select DEBUG_FS + depends on FAULT_INJECTION && SCSI_UFSHCD + help + Provide fault-injection capability for UFS IO. + This will make the UFS host controller driver to randomly + abort ongoing commands in the host controller, update OCS + field according to the injected fatal error and can also + forcefully hang the command indefinitely till upper layer + timeout occurs. This is useful to test error handling in + the UFS contoller driver and test how the driver handles + the retries from block/SCSI mid layer. + config FAULT_INJECTION_DEBUG_FS bool "Debugfs entries for fault-injection capabilities" depends on FAULT_INJECTION && SYSFS && DEBUG_FS
Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project