scsi: ufs: dump device descriptor info via debugfs

This change adds a debugfs capability to dump Device Descriptor
information, parsed and detailed. It helps developer to get
important information about the UFS device it handles.

Change-Id: Ia149e4c82e33755b235eb6afe52541c8b23a0708
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
This commit is contained in:
Yaniv Gardi 2013-12-08 13:58:56 +02:00 committed by David Keitel
parent 277e3a5096
commit 06a49c67f7
3 changed files with 129 additions and 0 deletions

View file

@ -20,6 +20,17 @@
#include <linux/random.h>
#include "debugfs.h"
enum field_width {
BYTE = 1,
WORD = 2,
};
struct desc_field_offset {
char *name;
int offset;
enum field_width width_byte;
};
#ifdef CONFIG_UFS_FAULT_INJECTION
#define INJECT_COMMAND_HANG (0x0)
@ -306,6 +317,79 @@ static const struct file_operations ufsdbg_host_regs_fops = {
.read = seq_read,
};
static int ufsdbg_dump_device_desc_show(struct seq_file *file, void *data)
{
int err = 0;
int buff_len = QUERY_DESC_DEVICE_MAX_SIZE;
u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
struct ufs_hba *hba = (struct ufs_hba *)file->private;
struct desc_field_offset device_desc_field_name[] = {
{"bLength", 0x00, BYTE},
{"bDescriptorType", 0x01, BYTE},
{"bDevice", 0x02, BYTE},
{"bDeviceClass", 0x03, BYTE},
{"bDeviceSubClass", 0x04, BYTE},
{"bProtocol", 0x05, BYTE},
{"bNumberLU", 0x06, BYTE},
{"bNumberWLU", 0x07, BYTE},
{"bBootEnable", 0x08, BYTE},
{"bDescrAccessEn", 0x09, BYTE},
{"bInitPowerMode", 0x0A, BYTE},
{"bHighPriorityLUN", 0x0B, BYTE},
{"bSecureRemovalType", 0x0C, BYTE},
{"bSecurityLU", 0x0D, BYTE},
{"Reserved", 0x0E, BYTE},
{"bInitActiveICCLevel", 0x0F, BYTE},
{"wSpecVersion", 0x10, WORD},
{"wManufactureDate", 0x12, WORD},
{"iManufactureName", 0x14, BYTE},
{"iProductName", 0x15, BYTE},
{"iSerialNumber", 0x16, BYTE},
{"iOemID", 0x17, BYTE},
{"wManufactureID", 0x18, WORD},
{"bUD0BaseOffset", 0x1A, BYTE},
{"bUDConfigPLength", 0x1B, BYTE},
{"bDeviceRTTCap", 0x1C, BYTE},
{"wPeriodicRTCUpdate", 0x1D, WORD}
};
pm_runtime_get_sync(hba->dev);
err = ufshcd_read_device_desc(hba, desc_buf, buff_len);
pm_runtime_put_sync(hba->dev);
if (!err) {
int i;
struct desc_field_offset *tmp;
for (i = 0; i < ARRAY_SIZE(device_desc_field_name); ++i) {
tmp = &device_desc_field_name[i];
if (tmp->width_byte == BYTE) {
seq_printf(file,
"Device Descriptor[Byte offset 0x%x]: %s = 0x%x\n",
tmp->offset,
tmp->name,
(u8)desc_buf[tmp->offset]);
} else if (tmp->width_byte == WORD) {
seq_printf(file,
"Device Descriptor[Byte offset 0x%x]: %s = 0x%x\n",
tmp->offset,
tmp->name,
*(u16 *)&desc_buf[tmp->offset]);
} else {
seq_printf(file,
"Device Descriptor[offset 0x%x]: %s. Wrong Width = %d",
tmp->offset, tmp->name, tmp->width_byte);
}
}
} else {
seq_printf(file, "Reading Device Descriptor failed. err = %d\n",
err);
}
return err;
}
static int ufsdbg_show_hba_show(struct seq_file *file, void *data)
{
struct ufs_hba *hba = (struct ufs_hba *)file->private;
@ -347,6 +431,17 @@ static const struct file_operations ufsdbg_show_hba_fops = {
.read = seq_read,
};
static int ufsdbg_dump_device_desc_open(struct inode *inode, struct file *file)
{
return single_open(file,
ufsdbg_dump_device_desc_show, inode->i_private);
}
static const struct file_operations ufsdbg_dump_device_desc = {
.open = ufsdbg_dump_device_desc_open,
.read = seq_read,
};
void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
if (!hba) {
@ -400,6 +495,16 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
goto err;
}
hba->debugfs_files.dump_dev_desc =
debugfs_create_file("dump_device_desc", S_IRUSR,
hba->debugfs_files.debugfs_root, hba,
&ufsdbg_dump_device_desc);
if (!hba->debugfs_files.dump_dev_desc) {
dev_err(hba->dev,
"%s: NULL dump_device_desc file, exiting", __func__);
goto err;
}
ufsdbg_setup_fault_injection(hba);
return;

View file

@ -2046,6 +2046,27 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba,
return err;
}
int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
{
int err = 0;
int retries;
for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
/* Read descriptor*/
err = ufshcd_read_desc(hba,
QUERY_DESC_IDN_DEVICE, 0, buf, size);
if (!err)
break;
dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
}
if (err)
dev_err(hba->dev, "%s: reading Device Desc failed. err = %d\n",
__func__, err);
return err;
}
/**
* ufshcd_read_unit_desc_param - read the specified unit descriptor parameter
* @hba: Pointer to adapter instance

View file

@ -346,6 +346,7 @@ struct debugfs_files {
struct dentry *tag_stats;
struct dentry *show_hba;
struct dentry *host_regs;
struct dentry *dump_dev_desc;
#ifdef CONFIG_UFS_FAULT_INJECTION
struct fault_attr fail_attr;
#endif
@ -742,6 +743,8 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
}
int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size);
/* variant specific ops structures */
#ifdef CONFIG_SCSI_UFS_MSM
extern const struct ufs_hba_variant_ops ufs_hba_msm_vops;