aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2016-03-10 10:37:09 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2016-03-14 21:04:45 -0400
commitb573d484e4ff33b60b1ef95ca30f199e749ff7c9 (patch)
treec0152a854e9af929f97643d2d37ee6025cab0017
parent596585a285a41993f26efab686e1ef20fc16a04a (diff)
scsi: ufs: add support to read device and string descriptors
This change adds support to read device descriptor and string descriptor from a UFS device Reviewed-by: Gilad Broner <gbroner@codeaurora.org> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Raviv Shvili <rshvili@codeaurora.org> Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/ufs/ufs.h1
-rw-r--r--drivers/scsi/ufs/ufshcd.c88
-rw-r--r--drivers/scsi/ufs/ufshcd.h7
3 files changed, 95 insertions, 1 deletions
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 54a16cef0367..aacb23521ef0 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -43,6 +43,7 @@
43#define GENERAL_UPIU_REQUEST_SIZE 32 43#define GENERAL_UPIU_REQUEST_SIZE 32
44#define QUERY_DESC_MAX_SIZE 255 44#define QUERY_DESC_MAX_SIZE 255
45#define QUERY_DESC_MIN_SIZE 2 45#define QUERY_DESC_MIN_SIZE 2
46#define QUERY_DESC_HDR_SIZE 2
46#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \ 47#define QUERY_OSF_SIZE (GENERAL_UPIU_REQUEST_SIZE - \
47 (sizeof(struct utp_upiu_header))) 48 (sizeof(struct utp_upiu_header)))
48 49
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 80031e6a63f5..e2ed41587f56 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -39,7 +39,7 @@
39 39
40#include <linux/async.h> 40#include <linux/async.h>
41#include <linux/devfreq.h> 41#include <linux/devfreq.h>
42 42#include <linux/nls.h>
43#include <linux/of.h> 43#include <linux/of.h>
44#include "ufshcd.h" 44#include "ufshcd.h"
45#include "unipro.h" 45#include "unipro.h"
@@ -232,6 +232,16 @@ static inline void ufshcd_disable_irq(struct ufs_hba *hba)
232 } 232 }
233} 233}
234 234
235/* replace non-printable or non-ASCII characters with spaces */
236static inline void ufshcd_remove_non_printable(char *val)
237{
238 if (!val)
239 return;
240
241 if (*val < 0x20 || *val > 0x7e)
242 *val = ' ';
243}
244
235/* 245/*
236 * ufshcd_wait_for_register - wait for register value to change 246 * ufshcd_wait_for_register - wait for register value to change
237 * @hba - per-adapter interface 247 * @hba - per-adapter interface
@@ -2021,6 +2031,82 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba,
2021 return ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size); 2031 return ufshcd_read_desc(hba, QUERY_DESC_IDN_POWER, 0, buf, size);
2022} 2032}
2023 2033
2034int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
2035{
2036 return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
2037}
2038EXPORT_SYMBOL(ufshcd_read_device_desc);
2039
2040/**
2041 * ufshcd_read_string_desc - read string descriptor
2042 * @hba: pointer to adapter instance
2043 * @desc_index: descriptor index
2044 * @buf: pointer to buffer where descriptor would be read
2045 * @size: size of buf
2046 * @ascii: if true convert from unicode to ascii characters
2047 *
2048 * Return 0 in case of success, non-zero otherwise
2049 */
2050int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
2051 u32 size, bool ascii)
2052{
2053 int err = 0;
2054
2055 err = ufshcd_read_desc(hba,
2056 QUERY_DESC_IDN_STRING, desc_index, buf, size);
2057
2058 if (err) {
2059 dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n",
2060 __func__, QUERY_REQ_RETRIES, err);
2061 goto out;
2062 }
2063
2064 if (ascii) {
2065 int desc_len;
2066 int ascii_len;
2067 int i;
2068 char *buff_ascii;
2069
2070 desc_len = buf[0];
2071 /* remove header and divide by 2 to move from UTF16 to UTF8 */
2072 ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1;
2073 if (size < ascii_len + QUERY_DESC_HDR_SIZE) {
2074 dev_err(hba->dev, "%s: buffer allocated size is too small\n",
2075 __func__);
2076 err = -ENOMEM;
2077 goto out;
2078 }
2079
2080 buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
2081 if (!buff_ascii) {
2082 err = -ENOMEM;
2083 goto out_free_buff;
2084 }
2085
2086 /*
2087 * the descriptor contains string in UTF16 format
2088 * we need to convert to utf-8 so it can be displayed
2089 */
2090 utf16s_to_utf8s((wchar_t *)&buf[QUERY_DESC_HDR_SIZE],
2091 desc_len - QUERY_DESC_HDR_SIZE,
2092 UTF16_BIG_ENDIAN, buff_ascii, ascii_len);
2093
2094 /* replace non-printable or non-ASCII characters with spaces */
2095 for (i = 0; i < ascii_len; i++)
2096 ufshcd_remove_non_printable(&buff_ascii[i]);
2097
2098 memset(buf + QUERY_DESC_HDR_SIZE, 0,
2099 size - QUERY_DESC_HDR_SIZE);
2100 memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len);
2101 buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE;
2102out_free_buff:
2103 kfree(buff_ascii);
2104 }
2105out:
2106 return err;
2107}
2108EXPORT_SYMBOL(ufshcd_read_string_desc);
2109
2024/** 2110/**
2025 * ufshcd_read_unit_desc_param - read the specified unit descriptor parameter 2111 * ufshcd_read_unit_desc_param - read the specified unit descriptor parameter
2026 * @hba: Pointer to adapter instance 2112 * @hba: Pointer to adapter instance
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index a6d35724ccdc..54e13ccb5754 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -678,6 +678,13 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
678 return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER); 678 return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
679} 679}
680 680
681int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size);
682
683#define ASCII_STD true
684
685int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
686 u32 size, bool ascii);
687
681/* Expose Query-Request API */ 688/* Expose Query-Request API */
682int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, 689int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
683 enum flag_idn idn, bool *flag_res); 690 enum flag_idn idn, bool *flag_res);