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:
parent
277e3a5096
commit
06a49c67f7
3 changed files with 129 additions and 0 deletions
|
@ -20,6 +20,17 @@
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include "debugfs.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
|
#ifdef CONFIG_UFS_FAULT_INJECTION
|
||||||
|
|
||||||
#define INJECT_COMMAND_HANG (0x0)
|
#define INJECT_COMMAND_HANG (0x0)
|
||||||
|
@ -306,6 +317,79 @@ static const struct file_operations ufsdbg_host_regs_fops = {
|
||||||
.read = seq_read,
|
.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)
|
static int ufsdbg_show_hba_show(struct seq_file *file, void *data)
|
||||||
{
|
{
|
||||||
struct ufs_hba *hba = (struct ufs_hba *)file->private;
|
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,
|
.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)
|
void ufsdbg_add_debugfs(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
if (!hba) {
|
if (!hba) {
|
||||||
|
@ -400,6 +495,16 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
|
||||||
goto err;
|
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);
|
ufsdbg_setup_fault_injection(hba);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2046,6 +2046,27 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba,
|
||||||
return err;
|
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
|
* ufshcd_read_unit_desc_param - read the specified unit descriptor parameter
|
||||||
* @hba: Pointer to adapter instance
|
* @hba: Pointer to adapter instance
|
||||||
|
|
|
@ -346,6 +346,7 @@ struct debugfs_files {
|
||||||
struct dentry *tag_stats;
|
struct dentry *tag_stats;
|
||||||
struct dentry *show_hba;
|
struct dentry *show_hba;
|
||||||
struct dentry *host_regs;
|
struct dentry *host_regs;
|
||||||
|
struct dentry *dump_dev_desc;
|
||||||
#ifdef CONFIG_UFS_FAULT_INJECTION
|
#ifdef CONFIG_UFS_FAULT_INJECTION
|
||||||
struct fault_attr fail_attr;
|
struct fault_attr fail_attr;
|
||||||
#endif
|
#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);
|
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 */
|
/* variant specific ops structures */
|
||||||
#ifdef CONFIG_SCSI_UFS_MSM
|
#ifdef CONFIG_SCSI_UFS_MSM
|
||||||
extern const struct ufs_hba_variant_ops ufs_hba_msm_vops;
|
extern const struct ufs_hba_variant_ops ufs_hba_msm_vops;
|
||||||
|
|
Loading…
Add table
Reference in a new issue