scsi: ufs-debugfs: add error state

This change adds support to allow user space query if low level UFS driver
has encountered any error or not, this state can be read/cleared via
debugfs.

Change-Id: I867a4621315108aff17be852cfaadcfa945566a7
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
Subhash Jadavani 2016-06-10 12:33:18 -07:00 committed by Kyle Yan
parent a26ae43d87
commit 73fa24503b
4 changed files with 69 additions and 2 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2016, 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
@ -1433,6 +1433,41 @@ static const struct file_operations ufsdbg_reset_controller = {
.write = ufsdbg_reset_controller_write,
};
static int ufsdbg_clear_err_state(void *data, u64 val)
{
struct ufs_hba *hba = data;
if (!hba)
return -EINVAL;
/* clear the error state on any write attempt */
hba->debugfs_files.err_occurred = false;
return 0;
}
static int ufsdbg_read_err_state(void *data, u64 *val)
{
struct ufs_hba *hba = data;
if (!hba)
return -EINVAL;
*val = hba->debugfs_files.err_occurred ? 1 : 0;
return 0;
}
void ufsdbg_set_err_state(struct ufs_hba *hba)
{
hba->debugfs_files.err_occurred = true;
}
DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_err_state,
ufsdbg_read_err_state,
ufsdbg_clear_err_state,
"%llu\n");
void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
char root_name[sizeof("ufshcd00")];
@ -1594,6 +1629,16 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
goto err;
}
hba->debugfs_files.err_state =
debugfs_create_file("err_state", S_IRUSR | S_IWUSR,
hba->debugfs_files.debugfs_root, hba,
&ufsdbg_err_state);
if (!hba->debugfs_files.err_state) {
dev_err(hba->dev,
"%s: failed create err_state debugfs entry", __func__);
goto err;
}
ufsdbg_setup_fault_injection(hba);
ufshcd_vops_add_debugfs(hba, hba->debugfs_files.debugfs_root);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2016, 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
@ -37,6 +37,7 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba);
void ufsdbg_remove_debugfs(struct ufs_hba *hba);
void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs,
char *str, void *priv);
void ufsdbg_set_err_state(struct ufs_hba *hba);
#else
static inline void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
@ -48,6 +49,9 @@ static inline void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset,
int num_regs, char *str, void *priv)
{
}
void ufsdbg_set_err_state(struct ufs_hba *hba)
{
}
#endif
#ifdef CONFIG_UFS_FAULT_INJECTION

View file

@ -71,6 +71,7 @@ static int ufshcd_tag_req_type(struct request *rq)
static void ufshcd_update_error_stats(struct ufs_hba *hba, int type)
{
ufsdbg_set_err_state(hba);
if (type < UFS_ERR_MAX)
hba->ufs_stats.err_stats[type]++;
}
@ -2143,6 +2144,9 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
else
ret = -ETIMEDOUT;
if (ret)
ufsdbg_set_err_state(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
spin_unlock_irqrestore(hba->host->host_lock, flags);
@ -2842,6 +2846,9 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
ufshcd_outstanding_req_clear(hba, lrbp->task_tag);
}
if (err)
ufsdbg_set_err_state(hba);
return err;
}
@ -3874,6 +3881,9 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
ret = (status != PWR_OK) ? status : -1;
}
out:
if (ret)
ufsdbg_set_err_state(hba);
ufshcd_save_tstamp_of_last_dme_cmd(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
@ -4947,6 +4957,11 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
ocs == OCS_MISMATCH_DATA_BUF_SIZE);
ufshcd_print_trs(hba, 1 << lrbp->task_tag, print_prdt);
}
if ((host_byte(result) == DID_ERROR) ||
(host_byte(result) == DID_ABORT))
ufsdbg_set_err_state(hba);
return result;
}
@ -5532,6 +5547,7 @@ static void ufshcd_err_handler(struct work_struct *work)
hba = container_of(work, struct ufs_hba, eh_work);
ufsdbg_set_err_state(hba);
pm_runtime_get_sync(hba->dev);
ufshcd_hold_all(hba);

View file

@ -543,6 +543,8 @@ struct debugfs_files {
u32 dme_local_attr_id;
u32 dme_peer_attr_id;
struct dentry *reset_controller;
struct dentry *err_state;
bool err_occurred;
#ifdef CONFIG_UFS_FAULT_INJECTION
struct dentry *err_inj_scenario;
struct dentry *err_inj_stats;