diff mbox series

[v3,7/7] scsi: ufs-bsg: Add support for uic commands in ufs_bsg_request()

Message ID 1535970796-25582-8-git-send-email-avri.altman@wdc.com (mailing list archive)
State Superseded
Headers show
Series scsi: ufs bsg endpoint | expand

Commit Message

Avri Altman Sept. 3, 2018, 10:33 a.m. UTC
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.altman@wdc.com>
---
 drivers/scsi/ufs/ufs_bsg.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/ufs/ufs_bsg.h |  2 ++
 2 files changed, 57 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
index 8c9167d..d1255be 100644
--- a/drivers/scsi/ufs/ufs_bsg.c
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -61,6 +61,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;
@@ -68,6 +117,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;
@@ -122,7 +172,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 9cc71bc..219597d 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,