diff mbox

[6/7] scsi: ufs: Enable writing config descriptor

Message ID 20180529181740.195362-7-evgreen@chromium.org (mailing list archive)
State Changes Requested
Headers show

Commit Message

Evan Green May 29, 2018, 6:17 p.m. UTC
This change enables writing to fields of the config descriptor
via sysfs. It can be used to provision an unprovisioned UFS
device, or reprovision an unlocked device.

Signed-off-by: Evan Green <evgreen@chromium.org>
---
 drivers/scsi/ufs/ufs-sysfs.c | 64 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 61 insertions(+), 3 deletions(-)

Comments

Bart Van Assche June 4, 2018, 8:46 a.m. UTC | #1
On Tue, 2018-05-29 at 11:17 -0700, Evan Green wrote:
> This change enables writing to fields of the config descriptor

> via sysfs. It can be used to provision an unprovisioned UFS

> device, or reprovision an unlocked device.

> 

> Signed-off-by: Evan Green <evgreen@chromium.org>

> ---

>  drivers/scsi/ufs/ufs-sysfs.c | 64 +++++++++++++++++++++++++++++++++++++++++---

>  1 file changed, 61 insertions(+), 3 deletions(-)

> 

> diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c

> index 623c56074572..54e9f3bca9db 100644

> --- a/drivers/scsi/ufs/ufs-sysfs.c

> +++ b/drivers/scsi/ufs/ufs-sysfs.c

> @@ -252,6 +252,31 @@ static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,

>  	return ret;

>  }

>  

> +static ssize_t ufs_sysfs_write_desc_param(struct ufs_hba *hba,

> +				  enum desc_idn desc_id,

> +				  u8 desc_index,

> +				  u8 param_offset,

> +				  const char *buf,

> +				  ssize_t buf_size,

> +				  u8 width)

> +{

> +	int ret;

> +	unsigned long long value;

> +

> +	if (kstrtoull(buf, 0, &value))

> +		return -EINVAL;

> +

> +	/* Convert to big endian, and send only the appropriate width. */

> +	value = cpu_to_be64(value);

> +	ret = ufshcd_rw_desc_param(hba, UPIU_QUERY_OPCODE_WRITE_DESC, desc_id,

> +				desc_index, param_offset,

> +				(u8 *)&value + 8 - width, width);


Instead of using the above construct, please provide separate versions of
ufs_sysfs_write_desc_param() and ufshcd_rw_desc_param() for each supported
value of "width" (8, 16, 32 and/or 64) and also use the __be8 / __be16 /
__be32 / __be64 annotations for big endian numbers such that it becomes
possible to verify endianness correctness with sparse.

Thanks,

Bart.
diff mbox

Patch

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index 623c56074572..54e9f3bca9db 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -252,6 +252,31 @@  static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
 	return ret;
 }
 
+static ssize_t ufs_sysfs_write_desc_param(struct ufs_hba *hba,
+				  enum desc_idn desc_id,
+				  u8 desc_index,
+				  u8 param_offset,
+				  const char *buf,
+				  ssize_t buf_size,
+				  u8 width)
+{
+	int ret;
+	unsigned long long value;
+
+	if (kstrtoull(buf, 0, &value))
+		return -EINVAL;
+
+	/* Convert to big endian, and send only the appropriate width. */
+	value = cpu_to_be64(value);
+	ret = ufshcd_rw_desc_param(hba, UPIU_QUERY_OPCODE_WRITE_DESC, desc_id,
+				desc_index, param_offset,
+				(u8 *)&value + 8 - width, width);
+	if (ret)
+		return -EINVAL;
+
+	return buf_size;
+}
+
 #define UFS_DESC_PARAM(_name, _puname, _duname, _size)			\
 static ssize_t _name##_show(struct device *dev,				\
 	struct device_attribute *attr, char *buf)			\
@@ -357,8 +382,25 @@  static ssize_t cfg_unit_store(struct device *dev,
 	return count;
 }
 
-#define UFS_CONFIG_DESC_PARAM(_name, _uname, _size)			\
-	UFS_DESC_PARAM(cfg_##_name, _uname, CONFIGURATION, _size)
+#define UFS_CONFIG_DESC_PARAM(_name, _puname, _size)			\
+static ssize_t cfg_##_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_CONFIGURATION, 0,			\
+		CONFIGURATION_DESC_PARAM##_puname, buf, _size);		\
+}									\
+static ssize_t cfg_##_name##_store(struct device *dev,			\
+		struct device_attribute *attr, const char *buf,		\
+		size_t count)						\
+{									\
+	struct ufs_hba *hba = dev_get_drvdata(dev);			\
+	return ufs_sysfs_write_desc_param(hba,				\
+		QUERY_DESC_IDN_CONFIGURATION, 0,			\
+		CONFIGURATION_DESC_PARAM##_puname, buf, count, _size);	\
+}									\
+static DEVICE_ATTR_RW(cfg_##_name)
 
 #define UFS_CONFIG_UNIT_DESC_PARAM(_name, _uname, _size)		\
 static ssize_t unit_##_name##_show(struct device *dev,			\
@@ -375,7 +417,23 @@  static ssize_t unit_##_name##_show(struct device *dev,			\
 	return ufs_sysfs_read_desc_param(hba,				\
 		QUERY_DESC_IDN_CONFIGURATION, 0, offset, buf, _size);	\
 }									\
-static DEVICE_ATTR_RO(unit_##_name)
+static ssize_t unit_##_name##_store(struct device *dev,			\
+		struct device_attribute *attr, const char *buf,		\
+		size_t count)						\
+{									\
+	struct ufs_hba *hba = dev_get_drvdata(dev);			\
+	size_t offset = CONFIGURATION_DESC_PARAM_UNIT0 +		\
+		(hba->sysfs_config_unit *				\
+		 CONFIGURATION_UNIT_DESC_SIZE) +			\
+		 CONFIGURATION_UNIT_DESC_PARAM_##_uname;		\
+	if (offset + _size > hba->desc_size.conf_desc) {		\
+		return -EINVAL;						\
+	}								\
+	return ufs_sysfs_write_desc_param(hba,				\
+		QUERY_DESC_IDN_CONFIGURATION, 0, offset, buf, count,	\
+		_size);							\
+}									\
+static DEVICE_ATTR_RW(unit_##_name)
 
 UFS_CONFIG_DESC_PARAM(number_of_luns, _NUM_LU, 1);
 UFS_CONFIG_DESC_PARAM(boot_enable, _BOOT_ENBL, 1);