Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73fa2450 authored by Subhash Jadavani's avatar Subhash Jadavani Committed by Kyle Yan
Browse files

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: default avatarSubhash Jadavani <subhashj@codeaurora.org>
parent a26ae43d
Loading
Loading
Loading
Loading
+46 −1
Original line number Diff line number Diff line
/* 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);
+5 −1
Original line number Diff line number Diff line
/* 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
+16 −0
Original line number Diff line number Diff line
@@ -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);

+2 −0
Original line number Diff line number Diff line
@@ -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;