scsi: ufs: get deivce descriptor information
authorhgchu <hg.chu@samsung.com>
Fri, 12 Jan 2018 01:12:48 +0000 (10:12 +0900)
committerJaeHun Jung <jh0801.jung@samsung.com>
Tue, 8 May 2018 08:20:12 +0000 (17:20 +0900)
Change-Id: Ifcadfbdbc0e954de726d28a7a33a1c8665123e47
Signed-off-by: hgchu <hg.chu@samsung.com>
drivers/scsi/ufs/ufs.h
drivers/scsi/ufs/ufs_quirks.c [new file with mode: 0644]
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h

index 54deeb754db5fccf7d918b604916b30d8defa8e5..1ec5fe80f0b250f6085a02ce9190db74655bd09a 100644 (file)
@@ -137,10 +137,24 @@ enum flag_idn {
 
 /* Attribute idn for Query requests */
 enum attr_idn {
+       QUERY_ATTR_IDN_BOOT_LU_EN       = 0x00,
+       QUERY_ATTR_IDN_RESERVED         = 0x01,
+       QUERY_ATTR_IDN_POWER_MODE       = 0x02,
        QUERY_ATTR_IDN_ACTIVE_ICC_LVL   = 0x03,
+       QUERY_ATTR_IDN_OOO_DATA_EN      = 0x04,
        QUERY_ATTR_IDN_BKOPS_STATUS     = 0x05,
+       QUERY_ATTR_IDN_PURGE_STATUS     = 0x06,
+       QUERY_ATTR_IDN_MAX_DATA_IN      = 0x07,
+       QUERY_ATTR_IDN_MAX_DATA_OUT     = 0x08,
+       QUERY_ATTR_IDN_DYN_CAP_NEEDED   = 0x09,
+       QUERY_ATTR_IDN_REF_CLK_FREQ     = 0x0A,
+       QUERY_ATTR_IDN_CONF_DESC_LOCK   = 0x0B,
+       QUERY_ATTR_IDN_MAX_NUM_OF_RTT   = 0x0C,
        QUERY_ATTR_IDN_EE_CONTROL       = 0x0D,
        QUERY_ATTR_IDN_EE_STATUS        = 0x0E,
+       QUERY_ATTR_IDN_SECONDS_PASSED   = 0x0F,
+       QUERY_ATTR_IDN_CNTX_CONF        = 0x10,
+       QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11,
 };
 
 /* Descriptor idn for Query requests */
@@ -154,6 +168,8 @@ enum desc_idn {
        QUERY_DESC_IDN_RFU_1            = 0x6,
        QUERY_DESC_IDN_GEOMETRY         = 0x7,
        QUERY_DESC_IDN_POWER            = 0x8,
+       QUERY_DESC_IDN_HEALTH           = 0x9,
+       QUERY_DESC_IDN_RFU_2            = 0xA,
        QUERY_DESC_IDN_MAX,
 };
 
@@ -302,6 +318,15 @@ enum {
        QUERY_RESULT_GENERAL_FAILURE            = 0xFF,
 };
 
+enum health_device_desc_param {
+       HEALTH_DEVICE_DESC_PARAM_LEN    = 0x0,
+       HEALTH_DEVICE_DESC_PARAM_IDN    =0x1,
+       HEALTH_DEVICE_DESC_PARAM_INFO   =0x2,
+       HEALTH_DEVICE_DESC_PARAM_LIFETIMEA      =0x3,
+       HEALTH_DEVICE_DESC_PARAM_LIFETIMEB      =0x4,
+       HEALTH_DEVICE_DESC_PARAM_RESERVED       =0x5,
+};
+
 /* UTP Transfer Request Command Type (CT) */
 enum {
        UPIU_COMMAND_SET_TYPE_SCSI      = 0x0,
diff --git a/drivers/scsi/ufs/ufs_quirks.c b/drivers/scsi/ufs/ufs_quirks.c
new file mode 100644 (file)
index 0000000..c1c1ef0
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013-2014, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "ufshcd.h"
+#include "ufs_quirks.h"
+
+#ifndef UFS_VENDOR_ID_SAMSUNG
+#define UFS_VENDOR_ID_SAMSUNG  0x1ce
+#endif
+
+#define SERIAL_NUM_SIZE 6
+#define TOSHIBA_SERIAL_NUM_SIZE 10
+
+
+/*UN policy
+*  16 digits : mandate + serial number(6byte, hex raw data)
+*  18 digits : manid + mandate + serial number(sec, hynix : 6byte hex,
+*                                                                toshiba : 10byte + 00, ascii)
+*/
+void ufs_set_sec_unique_number(struct ufs_hba *hba, u8 *str_desc_buf, u8 *desc_buf)
+{
+       u8 manid;
+       u8 snum_buf[UFS_UN_MAX_DIGITS];
+
+       manid = hba->manufacturer_id & 0xFF;
+       memset(hba->unique_number, 0, sizeof(hba->unique_number));
+       memset(snum_buf, 0, sizeof(snum_buf));
+
+#if defined(CONFIG_UFS_UN_18DIGITS)
+
+       memcpy(snum_buf, str_desc_buf + QUERY_DESC_HDR_SIZE, SERIAL_NUM_SIZE);
+
+       sprintf(hba->unique_number, "%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+               manid,
+               desc_buf[DEVICE_DESC_PARAM_MANF_DATE], desc_buf[DEVICE_DESC_PARAM_MANF_DATE+1],
+               snum_buf[0], snum_buf[1], snum_buf[2], snum_buf[3], snum_buf[4], snum_buf[5]);
+
+       /* Null terminate the unique number string */
+       hba->unique_number[UFS_UN_18_DIGITS] = '\0';
+
+#else
+       /*default is 16 DIGITS UN*/
+       memcpy(snum_buf, str_desc_buf + QUERY_DESC_HDR_SIZE, SERIAL_NUM_SIZE);
+
+       sprintf(hba->unique_number, "%02x%02x%02x%02x%02x%02x%02x%02x",
+               desc_buf[DEVICE_DESC_PARAM_MANF_DATE], desc_buf[DEVICE_DESC_PARAM_MANF_DATE+1],
+               snum_buf[0], snum_buf[1], snum_buf[2], snum_buf[3], snum_buf[4], snum_buf[5]);
+
+       /* Null terminate the unique number string */
+       hba->unique_number[UFS_UN_16_DIGITS] = '\0';
+#endif
+}
+
+
index 81ad7ba440629ee43e6004babe97da519f0f0e4c..004f96c9f1a3367e5b2093f55e9eb01febd2e0d2 100644 (file)
@@ -44,6 +44,8 @@
 #include "ufshcd.h"
 #include "ufs_quirks.h"
 #include "unipro.h"
+#include "ufs-exynos.h"
+#include "ufs_quirks.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/ufs.h>
@@ -3090,6 +3092,25 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
                goto out;
        }
 
+       /*
+        * While reading variable size descriptors (like string descriptor),
+        * some UFS devices may report the "LENGTH" (field in "Transaction
+        * Specific fields" of Query Response UPIU) same as what was requested
+        * in Query Request UPIU instead of reporting the actual size of the
+        * variable size descriptor.
+        * Although it's safe to ignore the "LENGTH" field for variable size
+        * descriptors as we can always derive the length of the descriptor from
+        * the descriptor header fields. Hence this change impose the length
+        * match check only for fixed size descriptors (for which we always
+        * request the correct size as part of Query Request UPIU).
+        */
+       if ((desc_id != QUERY_DESC_IDN_STRING) &&
+                       (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) {
+               dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d",
+                               __func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]);
+               ret = -EINVAL;
+               goto out;
+       }
        /* Check wherher we will not copy more data, than available */
        if (is_kmalloc && param_size > buff_len)
                param_size = buff_len;
@@ -3219,6 +3240,20 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba,
                                      param_offset, param_read_buf, param_size);
 }
 
+int ufshcd_read_health_desc(struct ufs_hba *hba, u8 *buf, u32 size)
+{
+       int err = 0;
+
+       err = ufshcd_read_desc(hba,
+                              QUERY_DESC_IDN_HEALTH, 0, buf, size);
+
+       if (err)
+               dev_err(hba->dev, "%s: reading Device Health Desc failed. err = %d\n",
+                       __func__, err);
+
+       return err;
+}
+
 /**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
index 9f1a466d6122ba88a95d8ea485a19230abbec9b9..9c08f82795a2a4144744259f4e0f6161376e57c2 100644 (file)
@@ -996,4 +996,5 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
                hba->vops->dbg_register_dump(hba);
 }
 
+int ufshcd_read_health_desc(struct ufs_hba *hba, u8 *buf, u32 size);
 #endif /* End of Header */