summaryrefslogtreecommitdiff
path: root/drivers/scsi/ufs
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2015-03-31 11:50:23 +0300
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:59:45 -0700
commit11a3ec924ee96a2f472f3485ac915430235a2610 (patch)
tree57c8dfdc041b23c4ff12f9542eaaf4ca307c3639 /drivers/scsi/ufs
parent3f8adb02aab70723ec239d901aa5f3525dc2ee08 (diff)
scsi: ufs: add debugfs to reset and restore the UFS controller
This change adds a debugfs capability to initiate a reset and restore procedure to the UFS controller by executing: echo 1 > /sys/kernel/debug/ufshcd0/reset_controller This capability is necessary for testing purposes of the the reset and restore procedure. Change-Id: I126e2d80d2ac63be6107aee29fa03dce4f56e83a Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
Diffstat (limited to 'drivers/scsi/ufs')
-rw-r--r--drivers/scsi/ufs/ufs-debugfs.c53
-rw-r--r--drivers/scsi/ufs/ufshcd.h1
2 files changed, 54 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 0df02f2e03b2..9fd019c0d808 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -1331,6 +1331,48 @@ static const struct file_operations ufsdbg_req_stats_desc = {
.write = ufsdbg_req_stats_write,
};
+
+static int ufsdbg_reset_controller_show(struct seq_file *file, void *data)
+{
+ seq_puts(file, "echo 1 > /sys/kernel/debug/.../reset_controller\n");
+ seq_puts(file, "resets the UFS controller and restores its operational state\n\n");
+
+ return 0;
+}
+
+static int ufsdbg_reset_controller_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ufsdbg_reset_controller_show,
+ inode->i_private);
+}
+
+static ssize_t ufsdbg_reset_controller_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ struct ufs_hba *hba = filp->f_mapping->host->i_private;
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ /*
+ * simulating a dummy error in order to "convince"
+ * eh_work to actually reset the controller
+ */
+ hba->saved_err |= INT_FATAL_ERRORS;
+ hba->silence_err_logs = true;
+ schedule_work(&hba->eh_work);
+
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return cnt;
+}
+
+static const struct file_operations ufsdbg_reset_controller = {
+ .open = ufsdbg_reset_controller_open,
+ .read = seq_read,
+ .write = ufsdbg_reset_controller_write,
+};
+
void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
char root_name[sizeof("ufshcd00")];
@@ -1463,6 +1505,17 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
goto err;
}
+ hba->debugfs_files.reset_controller =
+ debugfs_create_file("reset_controller", S_IRUSR | S_IWUSR,
+ hba->debugfs_files.debugfs_root, hba,
+ &ufsdbg_reset_controller);
+ if (!hba->debugfs_files.reset_controller) {
+ dev_err(hba->dev,
+ "%s: failed create reset_controller debugfs entry",
+ __func__);
+ goto err;
+ }
+
ufsdbg_setup_fault_injection(hba);
if (hba->vops && hba->vops->add_debugfs)
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 486f8d09ec90..58126491f624 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -476,6 +476,7 @@ struct debugfs_files {
struct dentry *req_stats;
u32 dme_local_attr_id;
u32 dme_peer_attr_id;
+ struct dentry *reset_controller;
#ifdef CONFIG_UFS_FAULT_INJECTION
struct dentry *err_inj_codes;
struct dentry *err_inj_scenario;