Add support to those uic commands, that are currently supported
by ufshcd api: the variants of dme_{peer}_{set_get}.

At this point better not to add any new api, as careless
uic command may turn the device into a brick.

Signed-off-by: Avri Altman <avri.alt...@wdc.com>
---
 drivers/scsi/ufs/ufs_bsg.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/ufs/ufs_bsg.h |  2 ++
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
index f4986f0..b2e48ad 100644
--- a/drivers/scsi/ufs/ufs_bsg.c
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -58,6 +58,55 @@ static int ufs_bsg_verify_query_size(unsigned int 
request_len,
        return 0;
 }
 
+static int ufs_bsg_exec_uic_cmd(struct uic_command *uc)
+{
+       u32 attr_sel = uc->argument1;
+       u8 attr_set = (uc->argument2 >> 16) & 0xff;
+       u32 mib_val = uc->argument3;
+       int cmd = uc->command;
+       int ret = 0;
+
+       switch (cmd) {
+       case UIC_CMD_DME_GET:
+               ret = ufshcd_dme_get_attr(bsg_host->hba, attr_sel,
+                                         &mib_val, DME_LOCAL);
+               break;
+       case UIC_CMD_DME_SET:
+               ret = ufshcd_dme_set_attr(bsg_host->hba, attr_sel, attr_set,
+                                         mib_val, DME_LOCAL);
+               break;
+       case UIC_CMD_DME_PEER_GET:
+               ret = ufshcd_dme_get_attr(bsg_host->hba, attr_sel,
+                                         &mib_val, DME_PEER);
+               break;
+       case UIC_CMD_DME_PEER_SET:
+               ret = ufshcd_dme_set_attr(bsg_host->hba, attr_sel, attr_set,
+                                         mib_val, DME_PEER);
+               break;
+       case UIC_CMD_DME_POWERON:
+       case UIC_CMD_DME_POWEROFF:
+       case UIC_CMD_DME_ENABLE:
+       case UIC_CMD_DME_RESET:
+       case UIC_CMD_DME_END_PT_RST:
+       case UIC_CMD_DME_LINK_STARTUP:
+       case UIC_CMD_DME_HIBER_ENTER:
+       case UIC_CMD_DME_HIBER_EXIT:
+       case UIC_CMD_DME_TEST_MODE:
+               ret = -ENOTSUPP;
+               pr_err("%s unsupported command 0x%x\n", __func__, cmd);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       if (ret)
+               pr_err("%s error in command 0x%x\n", __func__, cmd);
+
+       uc->argument3 = mib_val;
+
+       return ret;
+}
+
 static int ufs_bsg_request(struct bsg_job *job)
 {
        struct ufs_bsg_request *bsg_request = job->request;
@@ -65,6 +114,7 @@ static int ufs_bsg_request(struct bsg_job *job)
        unsigned int request_len = job->request_len;
        unsigned int reply_len = job->reply_len;
        struct utp_upiu_query *qr;
+       struct uic_command uc = {};
        struct utp_upiu_req *req_upiu = NULL;
        struct utp_upiu_req *rsp_upiu = NULL;
        int msgcode;
@@ -119,7 +169,11 @@ static int ufs_bsg_request(struct bsg_job *job)
 
                break;
        case UPIU_TRANSACTION_UIC_CMD:
-               /* later */
+               memcpy(&uc, &bsg_request->tsf.uc, UIC_CMD_SIZE);
+               ret = ufs_bsg_exec_uic_cmd(&uc);
+               memcpy(&bsg_reply->tsf.uc, &uc, UIC_CMD_SIZE);
+
+               break;
        case UPIU_TRANSACTION_COMMAND:
        case UPIU_TRANSACTION_DATA_OUT:
 not_supported:
diff --git a/drivers/scsi/ufs/ufs_bsg.h b/drivers/scsi/ufs/ufs_bsg.h
index 876de9f..b9c8dc5 100644
--- a/drivers/scsi/ufs/ufs_bsg.h
+++ b/drivers/scsi/ufs/ufs_bsg.h
@@ -15,6 +15,8 @@
 
 #define UFS_BSG_NOP (-1)
 #define UPIU_TRANSACTION_UIC_CMD 0x1F
+/* uic commands are 4DW long, per UFSHCI V2.1 paragraph 5.6.1 */
+#define UIC_CMD_SIZE (sizeof(u32) * 4)
 
 enum {
        REQ_UPIU_SIZE_DWORDS    = 8,
-- 
1.9.1

Reply via email to