@@ -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
@@ -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;
@@ -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 */
@@ -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_ */
@@ -76,4 +76,6 @@ enum {
UFS_QUERY_TASK_SET = 0x81,
};
+#define UFS_DME_MAX_ATTRIBUTE 0x7FFF
+
#endif /* UAPI_UFS_H_ */