[PATCH RFC 3/3] scsi: ufs: Add sysfs support for ufs provision

2018-05-21 Thread Sayali Lokhande
Add sysfs support to trigger ufs provisioning at runtime.
Usage :
echo  > /sys/bus/platform/devices/1d84000.ufshcd/ufs_provision
To check provisioning status:
cat /sys/bus/platform/devices/1d84000.ufshc/ufs_provision
1 -> Success (Reboot device to check updated provisioning)

Signed-off-by: Sayali Lokhande 
---
 drivers/scsi/ufs/ufs.h|   2 +
 drivers/scsi/ufs/ufshcd.c | 125 +-
 drivers/scsi/ufs/ufshcd.h |   6 +++
 3 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 1f99904..0b497fc 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -427,6 +427,7 @@ enum {
 };
 
 struct ufs_unit_desc {
+   u8 LUNum;
u8 bLUEnable;  /* 1 for enabled LU */
u8 bBootLunID; /* 0 for using this LU for boot */
u8 bLUWriteProtect;/* 1 = power on WP, 2 = permanent WP */
@@ -451,6 +452,7 @@ struct ufs_config_descr {
u32qVendorConfigCode;  /* Vendor specific configuration code */
struct ufs_unit_desc unit[8];
u8  lun_to_grow;
+   u8 num_luns;
 };
 
 /* Task management service response */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9ae64e2..0c94885 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1580,6 +1580,106 @@ void ufshcd_release(struct ufs_hba *hba)
 }
 EXPORT_SYMBOL_GPL(ufshcd_release);
 
+static ssize_t ufshcd_desc_config_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+
+   return snprintf(buf, PAGE_SIZE, "%d\n", hba->ufs_provision.is_enabled);
+}
+
+static ssize_t ufshcd_desc_config_store(struct device *dev,
+   struct device_attribute *attr, const char *buf, size_t count)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+   struct ufs_config_descr *cfg = >cfgs;
+   char *strbuf;
+   char *strbuf_copy;
+   int desc_buf[count];
+   int *pt;
+   char *token;
+   int i, ret;
+   int value, commit = 0;
+   int num_luns = 0;
+   int KB_per_block = 4;
+
+   /* reserve one byte for null termination */
+   strbuf = kmalloc(count + 1, GFP_KERNEL);
+   if (!strbuf)
+   return -ENOMEM;
+
+   strbuf_copy = strbuf;
+   strlcpy(strbuf, buf, count + 1);
+
+   for (i = 0; i < count; i++) {
+   token = strsep(, " ");
+   if (!token) {
+   num_luns = desc_buf[i-1];
+   dev_dbg(hba->dev, "%s: token %s, num_luns %d\n",
+   __func__, token, num_luns);
+   break;
+   }
+
+   ret = kstrtoint(token, 0, );
+   if (ret) {
+   dev_err(hba->dev, "%s: kstrtoint failed %d %s\n",
+   __func__, ret, token);
+   break;
+   }
+   desc_buf[i] = value;
+   dev_dbg(hba->dev, " desc_buf[%d] 0x%x", i, desc_buf[i]);
+   }
+
+   /* Fill in the descriptors with parsed configuration data */
+   pt = desc_buf;
+   cfg->bNumberLU = *pt++;
+   cfg->bBootEnable = *pt++;
+   cfg->bDescrAccessEn = *pt++;
+   cfg->bInitPowerMode = *pt++;
+   cfg->bHighPriorityLUN = *pt++;
+   cfg->bSecureRemovalType = *pt++;
+   cfg->bInitActiveICCLevel = *pt++;
+   cfg->wPeriodicRTCUpdate = *pt++;
+   cfg->bConfigDescrLock = *pt++;
+   dev_dbg(hba->dev, "%s: %u %u %u %u %u %u %u %u %u\n", __func__,
+   cfg->bNumberLU, cfg->bBootEnable, cfg->bDescrAccessEn,
+   cfg->bInitPowerMode, cfg->bHighPriorityLUN, cfg->bSecureRemovalType,
+   cfg->bInitActiveICCLevel, cfg->wPeriodicRTCUpdate,
+   cfg->bConfigDescrLock);
+
+   for (i = 0; i < num_luns; i++) {
+   cfg->unit[i].LUNum = *pt++;
+   cfg->unit[i].bLUEnable = *pt++;
+   cfg->unit[i].bBootLunID = *pt++;
+   /* dNumAllocUnits = size_in_kb/KB_per_block */
+   cfg->unit[i].dNumAllocUnits = (u32)(*pt++ / KB_per_block);
+   cfg->unit[i].bDataReliability = *pt++;
+   cfg->unit[i].bLUWriteProtect = *pt++;
+   cfg->unit[i].bMemoryType = *pt++;
+   cfg->unit[i].bLogicalBlockSize = *pt++;
+   cfg->unit[i].bProvisioningType = *pt++;
+   cfg->unit[i].wContextCapabilities = *pt++;
+   }
+
+   cfg->lun_to_grow = *pt++;
+   commit = *pt++;
+   cfg->num_luns = *pt;
+   dev_dbg(hba->dev, "%s: lun_to_grow %u, commit %u num_luns %u\n",
+   __func__, cfg->lun_to_grow, commit, cfg->num_luns);
+   if (commit == 1) {
+   ret = ufshcd_do_config_device(hba);
+   if (!ret) {
+   hba->ufs_provision.is_enabled = 1;
+ 

[PATCH RFC 3/3] scsi: ufs: Add sysfs support for ufs provision

2018-05-21 Thread Sayali Lokhande
Add sysfs support to trigger ufs provisioning at runtime.
Usage :
echo  > /sys/bus/platform/devices/1d84000.ufshcd/ufs_provision
To check provisioning status:
cat /sys/bus/platform/devices/1d84000.ufshc/ufs_provision
1 -> Success (Reboot device to check updated provisioning)

Signed-off-by: Sayali Lokhande 
---
 drivers/scsi/ufs/ufs.h|   2 +
 drivers/scsi/ufs/ufshcd.c | 125 +-
 drivers/scsi/ufs/ufshcd.h |   6 +++
 3 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 1f99904..0b497fc 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -427,6 +427,7 @@ enum {
 };
 
 struct ufs_unit_desc {
+   u8 LUNum;
u8 bLUEnable;  /* 1 for enabled LU */
u8 bBootLunID; /* 0 for using this LU for boot */
u8 bLUWriteProtect;/* 1 = power on WP, 2 = permanent WP */
@@ -451,6 +452,7 @@ struct ufs_config_descr {
u32qVendorConfigCode;  /* Vendor specific configuration code */
struct ufs_unit_desc unit[8];
u8  lun_to_grow;
+   u8 num_luns;
 };
 
 /* Task management service response */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9ae64e2..0c94885 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1580,6 +1580,106 @@ void ufshcd_release(struct ufs_hba *hba)
 }
 EXPORT_SYMBOL_GPL(ufshcd_release);
 
+static ssize_t ufshcd_desc_config_show(struct device *dev,
+   struct device_attribute *attr, char *buf)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+
+   return snprintf(buf, PAGE_SIZE, "%d\n", hba->ufs_provision.is_enabled);
+}
+
+static ssize_t ufshcd_desc_config_store(struct device *dev,
+   struct device_attribute *attr, const char *buf, size_t count)
+{
+   struct ufs_hba *hba = dev_get_drvdata(dev);
+   struct ufs_config_descr *cfg = >cfgs;
+   char *strbuf;
+   char *strbuf_copy;
+   int desc_buf[count];
+   int *pt;
+   char *token;
+   int i, ret;
+   int value, commit = 0;
+   int num_luns = 0;
+   int KB_per_block = 4;
+
+   /* reserve one byte for null termination */
+   strbuf = kmalloc(count + 1, GFP_KERNEL);
+   if (!strbuf)
+   return -ENOMEM;
+
+   strbuf_copy = strbuf;
+   strlcpy(strbuf, buf, count + 1);
+
+   for (i = 0; i < count; i++) {
+   token = strsep(, " ");
+   if (!token) {
+   num_luns = desc_buf[i-1];
+   dev_dbg(hba->dev, "%s: token %s, num_luns %d\n",
+   __func__, token, num_luns);
+   break;
+   }
+
+   ret = kstrtoint(token, 0, );
+   if (ret) {
+   dev_err(hba->dev, "%s: kstrtoint failed %d %s\n",
+   __func__, ret, token);
+   break;
+   }
+   desc_buf[i] = value;
+   dev_dbg(hba->dev, " desc_buf[%d] 0x%x", i, desc_buf[i]);
+   }
+
+   /* Fill in the descriptors with parsed configuration data */
+   pt = desc_buf;
+   cfg->bNumberLU = *pt++;
+   cfg->bBootEnable = *pt++;
+   cfg->bDescrAccessEn = *pt++;
+   cfg->bInitPowerMode = *pt++;
+   cfg->bHighPriorityLUN = *pt++;
+   cfg->bSecureRemovalType = *pt++;
+   cfg->bInitActiveICCLevel = *pt++;
+   cfg->wPeriodicRTCUpdate = *pt++;
+   cfg->bConfigDescrLock = *pt++;
+   dev_dbg(hba->dev, "%s: %u %u %u %u %u %u %u %u %u\n", __func__,
+   cfg->bNumberLU, cfg->bBootEnable, cfg->bDescrAccessEn,
+   cfg->bInitPowerMode, cfg->bHighPriorityLUN, cfg->bSecureRemovalType,
+   cfg->bInitActiveICCLevel, cfg->wPeriodicRTCUpdate,
+   cfg->bConfigDescrLock);
+
+   for (i = 0; i < num_luns; i++) {
+   cfg->unit[i].LUNum = *pt++;
+   cfg->unit[i].bLUEnable = *pt++;
+   cfg->unit[i].bBootLunID = *pt++;
+   /* dNumAllocUnits = size_in_kb/KB_per_block */
+   cfg->unit[i].dNumAllocUnits = (u32)(*pt++ / KB_per_block);
+   cfg->unit[i].bDataReliability = *pt++;
+   cfg->unit[i].bLUWriteProtect = *pt++;
+   cfg->unit[i].bMemoryType = *pt++;
+   cfg->unit[i].bLogicalBlockSize = *pt++;
+   cfg->unit[i].bProvisioningType = *pt++;
+   cfg->unit[i].wContextCapabilities = *pt++;
+   }
+
+   cfg->lun_to_grow = *pt++;
+   commit = *pt++;
+   cfg->num_luns = *pt;
+   dev_dbg(hba->dev, "%s: lun_to_grow %u, commit %u num_luns %u\n",
+   __func__, cfg->lun_to_grow, commit, cfg->num_luns);
+   if (commit == 1) {
+   ret = ufshcd_do_config_device(hba);
+   if (!ret) {
+   hba->ufs_provision.is_enabled = 1;
+   dev_err(hba->dev,
+