scsi: ufs: sysfs: health descriptor
This patch introduces a sysfs group entry for the UFS health descriptor parameters. The group adds "health_descriptor" folder under the UFS driver sysfs entry (/sys/bus/platform/drivers/ufshcd/*). The parameters are shown as hexadecimal numbers. The full information about the parameters could be found at UFS specifications 2.1. Change-Id: I469c8cf579b2a660c6bfd2a1bd30d4a7f357c588 Signed-off-by: Stanislav Nijnikov <stanislav.nijnikov@wdc.com> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Git-commit: c648c2d27f168ae4faeb43f8c3074226aae3862c Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Anjana <ahari@codeaurora.org>
This commit is contained in:
committed by
Anjana
parent
5542ee997f
commit
da1dcbff75
@@ -151,8 +151,9 @@ enum ufs_desc_def_size {
|
||||
QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90,
|
||||
QUERY_DESC_UNIT_DEF_SIZE = 0x23,
|
||||
QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06,
|
||||
QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44,
|
||||
QUERY_DESC_GEOMETRY_DEF_SIZE = 0x48,
|
||||
QUERY_DESC_POWER_DEF_SIZE = 0x62,
|
||||
QUERY_DESC_HEALTH_DEF_SIZE = 0x25,
|
||||
};
|
||||
|
||||
/* Unit descriptor parameters offsets in bytes*/
|
||||
@@ -206,6 +207,15 @@ enum device_desc_param {
|
||||
DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
|
||||
};
|
||||
|
||||
/* Health descriptor parameters offsets in bytes*/
|
||||
enum health_desc_param {
|
||||
HEALTH_DESC_PARAM_LEN = 0x0,
|
||||
HEALTH_DESC_PARAM_TYPE = 0x1,
|
||||
HEALTH_DESC_PARAM_EOL_INFO = 0x2,
|
||||
HEALTH_DESC_PARAM_LIFE_TIME_EST_A = 0x3,
|
||||
HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4,
|
||||
};
|
||||
|
||||
/*
|
||||
* Logical Unit Write Protect
|
||||
* 00h: LU not write protected
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
#include <linux/nls.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "ufs_quirks.h"
|
||||
#include "unipro.h"
|
||||
@@ -4518,6 +4520,9 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba,
|
||||
case QUERY_DESC_IDN_STRING:
|
||||
*desc_len = QUERY_DESC_MAX_SIZE;
|
||||
break;
|
||||
case QUERY_DESC_IDN_HEALTH:
|
||||
*desc_len = hba->desc_size.hlth_desc;
|
||||
break;
|
||||
case QUERY_DESC_IDN_RFU_0:
|
||||
case QUERY_DESC_IDN_RFU_1:
|
||||
*desc_len = 0;
|
||||
@@ -8538,6 +8543,11 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
|
||||
&hba->desc_size.geom_desc);
|
||||
if (err)
|
||||
hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
|
||||
|
||||
err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0,
|
||||
&hba->desc_size.hlth_desc);
|
||||
if (err)
|
||||
hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
|
||||
}
|
||||
|
||||
static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
|
||||
@@ -8548,6 +8558,7 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
|
||||
hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
|
||||
hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
|
||||
hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
|
||||
hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
|
||||
}
|
||||
|
||||
static void ufshcd_apply_pm_quirks(struct ufs_hba *hba)
|
||||
@@ -10656,16 +10667,111 @@ static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba)
|
||||
dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n");
|
||||
}
|
||||
|
||||
static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
|
||||
enum desc_idn desc_id,
|
||||
u8 desc_index,
|
||||
u8 param_offset,
|
||||
u8 *sysfs_buf,
|
||||
u8 param_size)
|
||||
{
|
||||
u8 desc_buf[8] = {0};
|
||||
int ret;
|
||||
|
||||
if (param_size > 8)
|
||||
return -EINVAL;
|
||||
|
||||
pm_runtime_get_sync(hba->dev);
|
||||
ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
|
||||
param_offset, desc_buf, param_size);
|
||||
pm_runtime_put_sync(hba->dev);
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
switch (param_size) {
|
||||
case 1:
|
||||
ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%02X\n", *desc_buf);
|
||||
break;
|
||||
case 2:
|
||||
ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%04X\n",
|
||||
get_unaligned_be16(desc_buf));
|
||||
break;
|
||||
case 4:
|
||||
ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%08X\n",
|
||||
get_unaligned_be32(desc_buf));
|
||||
break;
|
||||
case 8:
|
||||
ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%016llX\n",
|
||||
get_unaligned_be64(desc_buf));
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#define UFS_DESC_PARAM(_name, _puname, _duname, _size) \
|
||||
static ssize_t _name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct ufs_hba *hba = dev_get_drvdata(dev); \
|
||||
return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \
|
||||
0, _duname##_DESC_PARAM##_puname, buf, _size); \
|
||||
} \
|
||||
static DEVICE_ATTR_RO(_name)
|
||||
|
||||
#define UFS_HEALTH_DESC_PARAM(_name, _uname, _size) \
|
||||
UFS_DESC_PARAM(_name, _uname, HEALTH, _size)
|
||||
|
||||
UFS_HEALTH_DESC_PARAM(eol_info, _EOL_INFO, 1);
|
||||
UFS_HEALTH_DESC_PARAM(life_time_estimation_a, _LIFE_TIME_EST_A, 1);
|
||||
UFS_HEALTH_DESC_PARAM(life_time_estimation_b, _LIFE_TIME_EST_B, 1);
|
||||
|
||||
static struct attribute *ufs_sysfs_health_descriptor[] = {
|
||||
&dev_attr_eol_info.attr,
|
||||
&dev_attr_life_time_estimation_a.attr,
|
||||
&dev_attr_life_time_estimation_b.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ufs_sysfs_health_descriptor_group = {
|
||||
.name = "health_descriptor",
|
||||
.attrs = ufs_sysfs_health_descriptor,
|
||||
};
|
||||
|
||||
static const struct attribute_group *ufs_sysfs_groups[] = {
|
||||
&ufs_sysfs_health_descriptor_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static void ufshcd_add_desc_sysfs_nodes(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sysfs_create_groups(&dev->kobj, ufs_sysfs_groups);
|
||||
if (ret)
|
||||
dev_err(dev,
|
||||
"%s: sysfs groups creation failed (err = %d)\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
static void ufshcd_remove_desc_sysfs_nodes(struct device *dev)
|
||||
{
|
||||
sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups);
|
||||
}
|
||||
|
||||
static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba)
|
||||
{
|
||||
ufshcd_add_rpm_lvl_sysfs_nodes(hba);
|
||||
ufshcd_add_spm_lvl_sysfs_nodes(hba);
|
||||
ufshcd_add_desc_sysfs_nodes(hba->dev);
|
||||
}
|
||||
|
||||
static inline void ufshcd_remove_sysfs_nodes(struct ufs_hba *hba)
|
||||
{
|
||||
device_remove_file(hba->dev, &hba->rpm_lvl_attr);
|
||||
device_remove_file(hba->dev, &hba->spm_lvl_attr);
|
||||
ufshcd_remove_desc_sysfs_nodes(hba->dev);
|
||||
}
|
||||
|
||||
static void __ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
|
||||
|
||||
@@ -259,6 +259,7 @@ struct ufs_desc_size {
|
||||
int interc_desc;
|
||||
int unit_desc;
|
||||
int conf_desc;
|
||||
int hlth_desc;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,7 +55,8 @@ enum desc_idn {
|
||||
QUERY_DESC_IDN_RFU_1 = 0x6,
|
||||
QUERY_DESC_IDN_GEOMETRY = 0x7,
|
||||
QUERY_DESC_IDN_POWER = 0x8,
|
||||
QUERY_DESC_IDN_RFU_2 = 0x9,
|
||||
QUERY_DESC_IDN_HEALTH = 0x9,
|
||||
QUERY_DESC_IDN_RFU_2 = 0x0A,
|
||||
QUERY_DESC_IDN_MAX,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user