diff mbox

[v1,4/4] scsi: ufs: add ioctl interface to read UIC attributes

Message ID 1494511309-32256-5-git-send-email-michalx.potomski@intel.com (mailing list archive)
State Rejected, archived
Headers show

Commit Message

Potomski, MichalX May 11, 2017, 2:01 p.m. UTC
From: Szymon Mielczarek <szymonx.mielczarek@intel.com>

The interface allows to read both local (Host side) and peer (Device
side) UIC attributes using either DME_GET or DME_PEER_GET primitives.
The Attribute can be used to determine the current state or the
capabilities of the UFS InterConnect Layer (UIC - UniPro & M-PHY).

Signed-off-by: Szymon Mielczarek <szymonx.mielczarek@intel.com>
Signed-off-by: MichaƂ Potomski <michalx.potomski@intel.com>
---
 Documentation/scsi/ufs.txt      | 36 +++++++++++++++++++++++++
 drivers/scsi/ufs/ufshcd-ioctl.c | 58 +++++++++++++++++++++++++++++++++++++++++
 include/scsi/scsi.h             |  2 +-
 include/uapi/scsi/ufs/ioctl.h   | 22 ++++++++++++++++
 include/uapi/scsi/ufs/ufs.h     |  2 ++
 5 files changed, 119 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
index ed5768d..b8a4790 100644
--- a/Documentation/scsi/ufs.txt
+++ b/Documentation/scsi/ufs.txt
@@ -19,6 +19,7 @@  Contents
   4.1 UFS Query IOCTL
   4.2 UFS Auto-Hibern8 IOCTL
   4.3 UFS Task Management IOCTL
+  4.4 UFS DME Read IOCTL
 
 
 1. Overview
@@ -256,6 +257,41 @@  host and device using IOCTL interface.
   This one should be used with extreme care as it's more of a testing/vaidation
   interface.
 
+4.4 UFS DME Read IOCTL
+
+  This interface enables user to check link state of UFS Device. It's meant
+  mainly for test and troubleshooting purposes. You can use following
+  snippet to comunicate with this interface:
+
+	#include <sys/ioctl.h>
+	#include <scsi/ufs/ioctl.h>
+	#include <scsi/ufs/ufs.h>
+
+	static int handleDME(int fd, uint16_t attr_id, bool local_link,
+		uint32_t *response)
+	{
+		ufs_ioctl_dme_get_data dme_data;
+		int error;
+
+		/* Attribute ID (max. 0x7fff) */
+		dme_data.attr_id = attr_id;
+
+		/* Local or Device part of link? */
+		dme_data.peer = !local_link;
+
+		/* [fd] used here shall be opened UFS device */
+		error = ioctl(fd, UFS_IOCTL_DME, &dme_data);
+
+		if (!error)
+			/* This will return DME specific response */
+			*response = dme_data.response;
+
+		return error;
+	}
+
+  This is read-only interface, since we don't want to work-around driver
+  as these are link-level values and configurations managed strictly in driver.
+
 
 UFS Specifications can be found at,
 UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf
diff --git a/drivers/scsi/ufs/ufshcd-ioctl.c b/drivers/scsi/ufs/ufshcd-ioctl.c
index afcb099..750ff9d 100644
--- a/drivers/scsi/ufs/ufshcd-ioctl.c
+++ b/drivers/scsi/ufs/ufshcd-ioctl.c
@@ -376,6 +376,58 @@  static int ufshcd_task_mgmt_ioctl(struct ufs_hba *hba, u8 lun,
 }
 
 /**
+ * ufshcd_dme_get_ioctl - provide read access to all UniPro and M-PHY attributes
+ * on the both local and peer side of the Link
+ * @hba: per-adapter instance
+ * @buffer: user space buffer for ufs_ioctl_dme_get_data structure
+ *
+ * Returns 0 for success or negative error code otherwise
+ *
+ * It will send the UIC DME_GET or DME_PEER_GET command to read the value of
+ * specified attribute and put the value in the response field.
+ */
+static int ufshcd_dme_get_ioctl(struct ufs_hba *hba, void __user *buffer)
+{
+	struct ufs_ioctl_dme_get_data *ioctl_data;
+	int err = 0;
+
+	if (!buffer)
+		return -EINVAL;
+
+	ioctl_data = kzalloc(sizeof(struct ufs_ioctl_dme_get_data), GFP_KERNEL);
+	if (!ioctl_data) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* Extract params from user buffer */
+	if (copy_from_user(ioctl_data, buffer, sizeof(*ioctl_data))) {
+		err = -EFAULT;
+		goto out_release_mem;
+	}
+
+	err = ufshcd_dme_get_attr(hba,
+		UIC_ARG_MIB_SEL(ioctl_data->attr_id, ioctl_data->selector),
+		&ioctl_data->response, ioctl_data->peer);
+
+	if (err)
+		goto out_release_mem;
+
+	/* Copy response to user */
+	if (copy_to_user(buffer, ioctl_data, sizeof(*ioctl_data)))
+		err = -EFAULT;
+
+out_release_mem:
+	kfree(ioctl_data);
+out:
+	if (err)
+		dev_err(hba->dev, "User DME_GET request failed (error: %d)",
+			err);
+
+	return err;
+}
+
+/**
  * ufshcd_ioctl - ufs ioctl callback registered in scsi_host
  * @dev: scsi device required for per LUN queries
  * @cmd: command opcode
@@ -385,6 +437,7 @@  static int ufshcd_task_mgmt_ioctl(struct ufs_hba *hba, u8 lun,
  * UFS_IOCTL_QUERY
  * UFS_IOCTL_AUTO_HIBERN8
  * UFS_IOCTL_TASK_MANAGEMENT
+ * UFS_IOCTL_DME
  */
 int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
 {
@@ -411,6 +464,11 @@  int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
 			ufshcd_scsi_to_upiu_lun(dev->lun), buffer);
 		pm_runtime_put_sync(hba->dev);
 		break;
+	case UFS_IOCTL_DME:
+		pm_runtime_get_sync(hba->dev);
+		err = ufshcd_dme_get_ioctl(hba, buffer);
+		pm_runtime_put_sync(hba->dev);
+		break;
 	default:
 		err = -EOPNOTSUPP;
 		break;
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index b8e1006..74bdf3c 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -255,7 +255,7 @@  static inline int scsi_is_wlun(u64 lun)
  * Here are some scsi specific ioctl commands which are sometimes useful.
  *
  * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
- * include/uapi/scsi/ufs/ioctl.h defines 0x53A0 - 0x53A2
+ * include/uapi/scsi/ufs/ioctl.h defines 0x53A0 - 0x53A3
  */
 
 /* Used to obtain PUN and LUN info.  Conflicts with CDROMAUDIOBUFSIZ */
diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h
index 6b7e876..2118c21 100644
--- a/include/uapi/scsi/ufs/ioctl.h
+++ b/include/uapi/scsi/ufs/ioctl.h
@@ -10,6 +10,7 @@ 
 #define UFS_IOCTL_QUERY			0x53A0
 #define UFS_IOCTL_AUTO_HIBERN8		0x53A1
 #define UFS_IOCTL_TASK_MANAGEMENT	0x53A2
+#define UFS_IOCTL_DME			0x53A3
 
 /**
  * struct ufs_ioctl_query_data - used to transfer data to and from user via
@@ -107,4 +108,25 @@  struct ufs_ioctl_task_mgmt_data {
 	__u8 response;
 };
 
+/**
+ * struct ufs_ioctl_dme_get_data - used to request information from a specific
+ * UniPro or M-PHY attribute
+ *
+ * @attr_id: attribute identifier (valid range: 0x0000 to 0x7FFF)
+ * @selector: selector on attribute ( shall be != 0 only for some attribiutes;
+ * please reffer UniPro documentation for details)
+ * @peer: indicate whether peer or local UniPro Link
+ * @response: variable where the kernel will put the attribute value read from
+ * the local or peer UniPro Link
+ *
+ * Submitted: attr_id, peer
+ * Received: response
+ */
+struct ufs_ioctl_dme_get_data {
+	__u16 attr_id;
+	__u16 selector;
+	bool peer;
+	__u32 response;
+};
+
 #endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h
index 9f93c9a..dc17b65 100644
--- a/include/uapi/scsi/ufs/ufs.h
+++ b/include/uapi/scsi/ufs/ufs.h
@@ -76,4 +76,6 @@  enum {
 	UFS_QUERY_TASK_SET	= 0x81,
 };
 
+#define UFS_DME_MAX_ATTRIBUTE		0x7FFF
+
 #endif /* UAPI_UFS_H_ */