* [PATCH v1 0/4] UFS ioctl UAPI
@ 2017-05-11 14:01 Michal Potomski
2017-05-11 14:01 ` [PATCH v1 1/4] scsi: ufs: Add ioctl() interface with Query Request Michal Potomski
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Michal Potomski @ 2017-05-11 14:01 UTC (permalink / raw)
To: linux-scsi
Cc: vinholikatti, martin.petersen, jejb, subhashj,
Michał Potomski
From: Michał Potomski <michalx.potomski@intel.com>
This patchset introduces UFS ioctl UAPI. It's more readable and flexible
than its possible SysFS counterpart. Moreover it will be needed for
future features, which will require user setup, but are not satified
by SysFS "simple types" rule.
We have discussed and monitored UFS UAPI topic for some time now and we
came to conclusion, that ioctl API is our best bet as common interface for UFS.
Michał Potomski (3):
scsi: ufs: Add ioctl() interface with Query Request
scsi: ufs: Implement Auto-Hibern8 setup
scsi: ufs: Expose Task Management to ioctl() UAPI
Szymon Mielczarek (1):
scsi: ufs: add ioctl interface to read UIC attributes
Documentation/scsi/ufs.txt | 167 +++++++++++++-
drivers/scsi/ufs/Kconfig | 12 +
drivers/scsi/ufs/Makefile | 5 +-
drivers/scsi/ufs/ufs.h | 63 +-----
drivers/scsi/ufs/ufshcd-ioctl.c | 483 ++++++++++++++++++++++++++++++++++++++++
drivers/scsi/ufs/ufshcd-ioctl.h | 32 +++
drivers/scsi/ufs/ufshcd.c | 72 ++++--
drivers/scsi/ufs/ufshcd.h | 19 ++
drivers/scsi/ufs/ufshci.h | 9 +-
include/scsi/scsi.h | 1 +
include/uapi/scsi/Kbuild | 1 +
include/uapi/scsi/ufs/Kbuild | 4 +
include/uapi/scsi/ufs/ioctl.h | 132 +++++++++++
include/uapi/scsi/ufs/ufs.h | 81 +++++++
include/uapi/scsi/ufs/ufshci.h | 17 ++
15 files changed, 1028 insertions(+), 70 deletions(-)
create mode 100644 drivers/scsi/ufs/ufshcd-ioctl.c
create mode 100644 drivers/scsi/ufs/ufshcd-ioctl.h
create mode 100644 include/uapi/scsi/ufs/Kbuild
create mode 100644 include/uapi/scsi/ufs/ioctl.h
create mode 100644 include/uapi/scsi/ufs/ufs.h
create mode 100644 include/uapi/scsi/ufs/ufshci.h
--
1.9.1
--------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek
przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by
others is strictly prohibited.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v1 1/4] scsi: ufs: Add ioctl() interface with Query Request
2017-05-11 14:01 [PATCH v1 0/4] UFS ioctl UAPI Michal Potomski
@ 2017-05-11 14:01 ` Michal Potomski
2017-05-11 17:59 ` Christoph Hellwig
2017-05-11 14:01 ` [PATCH v1 2/4] scsi: ufs: Implement Auto-Hibern8 setup Michal Potomski
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Michal Potomski @ 2017-05-11 14:01 UTC (permalink / raw)
To: linux-scsi
Cc: vinholikatti, martin.petersen, jejb, subhashj,
Michał Potomski, Szymon Mielczarek
From: Michał Potomski <michalx.potomski@intel.com>
Based on unmerged patch: https://patchwork.kernel.org/patch/6435721/
This patch introduces ioctl() API using SCSI ioctl() API for
user-space in preparation to wider usage. We came to a conclusion,
that ioctl() interface is more convenient and readable for
features, that we've planned to add to the driver in near future,
namely UFS 2.1, e.g. Crypto Engine configuration. This level of
simplicity and flexibility is simply not achievable with SysFS
interface as its attributes shall contain only simple values
without mixing types.
This patch introduces new config SCSI_UFSHCD_IOCTL
This config flag enables/disables this API by designing whether
it should be compiled into UFS driver on which it lays.
Inherited from base:
- ioctl() API for UFS
Changes from base:
- Support for Query Write operations
- UFS ioctl() is now a separate and optional
Signed-off-by: Michał Potomski <michalx.potomski@intel.com>
Signed-off-by: Szymon Mielczarek <szymonx.mielczarek@intel.com>
---
Documentation/scsi/ufs.txt | 49 ++++++-
drivers/scsi/ufs/Kconfig | 12 ++
drivers/scsi/ufs/Makefile | 5 +-
drivers/scsi/ufs/ufs.h | 53 ++-----
drivers/scsi/ufs/ufshcd-ioctl.c | 310 ++++++++++++++++++++++++++++++++++++++++
drivers/scsi/ufs/ufshcd-ioctl.h | 32 +++++
drivers/scsi/ufs/ufshcd.c | 45 ++++--
drivers/scsi/ufs/ufshcd.h | 11 ++
include/scsi/scsi.h | 1 +
include/uapi/scsi/Kbuild | 1 +
include/uapi/scsi/ufs/Kbuild | 3 +
include/uapi/scsi/ufs/ioctl.h | 61 ++++++++
include/uapi/scsi/ufs/ufs.h | 69 +++++++++
13 files changed, 596 insertions(+), 56 deletions(-)
create mode 100644 drivers/scsi/ufs/ufshcd-ioctl.c
create mode 100644 drivers/scsi/ufs/ufshcd-ioctl.h
create mode 100644 include/uapi/scsi/ufs/Kbuild
create mode 100644 include/uapi/scsi/ufs/ioctl.h
create mode 100644 include/uapi/scsi/ufs/ufs.h
diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
index 41a6164..7326974 100644
--- a/Documentation/scsi/ufs.txt
+++ b/Documentation/scsi/ufs.txt
@@ -15,6 +15,8 @@ Contents
3.2 UTP Transfer requests
3.3 UFS error handling
3.4 SCSI Error handling
+4. UFSHCD User Interface
+ 4.1 UFS Query IOCTL
1. Overview
@@ -125,9 +127,54 @@ The current UFSHCD implementation supports following functionality,
SCSI Midlayer through .eh_abort_handler, .eh_device_reset_handler and
.eh_host_reset_handler.
-In this version of UFSHCD Query requests and power management
+In this version of UFSHCD power management
functionality are not implemented.
+
+4. UFSHCD User Interface
+------------------
+
+Current impementation of UFSHCD enables user to communicate with
+host and device using IOCTL interface.
+
+4.1 UFS Query IOCTL
+
+ This interface enables user to get information about UFS Device
+ and set some of its configurable properties. You can use following
+ snippet to communicate with this interface:
+
+ #include <sys/ioctl.h>
+ #include <scsi/ufs/ioctl.h>
+ #include <scsi/ufs/ufs.h>
+
+ static int handleQuery(int fd, uint8_t opcode, uint8_t idn,
+ uint8_t buf_size, uint8_t *buffer)
+ {
+ ufs_ioctl_query_data query_data;
+
+ /* Operation code (check <scsi/ufs/ufs.h>) */
+ query_data.opcode = opcode;
+
+ /* Query ID (check <scsi/ufs/ufs.h>) */
+ query_data.idn = idn;
+
+ /*
+ * Pointer to allocated memory. Filled with proper data if
+ * [opcode] determines write operation.
+ */
+ query_data.buffer = buffer;
+
+ /* Size of allocated memory */
+ query_data.buf_size = buf_size;
+
+ /* [fd] used here shall be opened UFS device */
+ return ioctl(fd, UFS_IOCTL_QUERY, &query_data);
+ }
+
+ This enables user to control some of the UFS specific features inaccessible
+ in other way.
+
+
UFS Specifications can be found at,
UFS - http://www.jedec.org/sites/default/files/docs/JESD220.pdf
UFSHCI - http://www.jedec.org/sites/default/files/docs/JESD223.pdf
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index e27b4d4..7c8618c 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -61,6 +61,18 @@ config SCSI_UFSHCD_PCI
If unsure, say N.
+config SCSI_UFSHCD_IOCTL
+ bool "Enable ioctl() Configuration Interface for this module"
+ depends on SCSI_UFSHCD
+ ---help---
+ This enables UFS Configuration Interface for user-space.
+ Interface enables you to configure and read state of some
+ of the UFS features, which are inavailable in other way.
+
+ If you intend to configure UFS Host/Device through it, say Y here.
+
+ If unsure, say N.
+
config SCSI_UFS_DWC_TC_PCI
tristate "DesignWare pci support using a G210 Test Chip"
depends on SCSI_UFSHCD_PCI
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 6e77cb0..85bc418 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -1,7 +1,10 @@
# UFSHCD makefile
+ufshcd-core-y := ufshcd.o
+ufshcd-core-$(CONFIG_SCSI_UFSHCD_IOCTL) += ufshcd-ioctl.o
+
obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o
obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
-obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
+obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 54deeb7..06da302 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -38,6 +38,7 @@
#include <linux/mutex.h>
#include <linux/types.h>
+#include <scsi/ufs/ufs.h>
#define MAX_CDB_SIZE 16
#define GENERAL_UPIU_REQUEST_SIZE 32
@@ -73,6 +74,16 @@ enum {
UFS_UPIU_RPMB_WLUN = 0xC4,
};
+/**
+ * ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor
+ * @lun: LU number to check
+ * @return: true if the lun has a matching unit descriptor, false otherwise
+ */
+static inline bool ufs_is_valid_unit_desc_lun(u8 lun)
+{
+ return (lun == UFS_UPIU_RPMB_WLUN || (lun < UFS_UPIU_MAX_GENERAL_LUN));
+}
+
/*
* UFS Protocol Information Unit related definitions
*/
@@ -128,35 +139,6 @@ enum {
UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
};
-/* Flag idn for Query Requests*/
-enum flag_idn {
- QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
- QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
- QUERY_FLAG_IDN_BKOPS_EN = 0x04,
-};
-
-/* Attribute idn for Query requests */
-enum attr_idn {
- QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
- QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
- QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
- QUERY_ATTR_IDN_EE_STATUS = 0x0E,
-};
-
-/* Descriptor idn for Query requests */
-enum desc_idn {
- QUERY_DESC_IDN_DEVICE = 0x0,
- QUERY_DESC_IDN_CONFIGURATION = 0x1,
- QUERY_DESC_IDN_UNIT = 0x2,
- QUERY_DESC_IDN_RFU_0 = 0x3,
- QUERY_DESC_IDN_INTERCONNECT = 0x4,
- QUERY_DESC_IDN_STRING = 0x5,
- QUERY_DESC_IDN_RFU_1 = 0x6,
- QUERY_DESC_IDN_GEOMETRY = 0x7,
- QUERY_DESC_IDN_POWER = 0x8,
- QUERY_DESC_IDN_MAX,
-};
-
enum desc_header_offset {
QUERY_DESC_LENGTH_OFFSET = 0x00,
QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
@@ -274,19 +256,6 @@ enum bkops_status {
BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL,
};
-/* UTP QUERY Transaction Specific Fields OpCode */
-enum query_opcode {
- UPIU_QUERY_OPCODE_NOP = 0x0,
- UPIU_QUERY_OPCODE_READ_DESC = 0x1,
- UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
- UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
- UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
- UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
- UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
- UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
- UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
-};
-
/* Query response result code */
enum {
QUERY_RESULT_SUCCESS = 0x00,
diff --git a/drivers/scsi/ufs/ufshcd-ioctl.c b/drivers/scsi/ufs/ufshcd-ioctl.c
new file mode 100644
index 0000000..ae70bf5
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-ioctl.c
@@ -0,0 +1,310 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * UFS ioctl - this architecture can be used to configure driver and
+ * device/host parameters, that are otherwise unavailable for such operation
+ */
+
+#include <scsi/ufs/ioctl.h>
+
+#include "ufshcd-ioctl.h"
+
+static int ufshcd_ioctl_query_desc(struct ufs_hba *hba,
+ struct ufs_ioctl_query_data *ioctl_data,
+ void *data_ptr, u8 lun, int length, bool write)
+{
+ int err = 0;
+ u8 index;
+
+ /* LUN indexed descriptors */
+ if (ioctl_data->idn == QUERY_DESC_IDN_UNIT) {
+ if (ufs_is_valid_unit_desc_lun(lun)) {
+ index = lun;
+ } else {
+ err = -EINVAL;
+ goto out;
+ }
+ /* LUN independent descriptors */
+ } else if (ioctl_data->idn < QUERY_DESC_IDN_MAX) {
+ index = 0;
+ /* Invalid descriptors */
+ } else {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = ufshcd_query_descriptor(hba, ioctl_data->opcode,
+ ioctl_data->idn, index, 0, data_ptr, &length);
+
+ if (!err && !write)
+ ioctl_data->buf_size =
+ min_t(int, ioctl_data->buf_size, length);
+ else
+ ioctl_data->buf_size = 0;
+
+out:
+ if (err)
+ dev_err(hba->dev, "Query Descriptor failed (error: %d)", err);
+
+ return err;
+}
+
+static int ufshcd_ioctl_query_attr(struct ufs_hba *hba,
+ struct ufs_ioctl_query_data *ioctl_data,
+ void *data_ptr, u8 lun, bool write)
+{
+ int err = 0;
+ u8 index;
+
+ /* LUN indexed attributes */
+ if (ioctl_data->idn == QUERY_ATTR_IDN_DYN_CAP_NEEDED ||
+ ioctl_data->idn == QUERY_ATTR_IDN_PRG_BLK_NUM) {
+ if (ufs_is_valid_unit_desc_lun(lun)) {
+ index = lun;
+ } else {
+ err = -EINVAL;
+ goto out;
+ }
+ /* LUN independent attributes */
+ } else if (ioctl_data->idn < QUERY_ATTR_IDN_MAX) {
+ index = 0;
+ /* Invalid attribiutes */
+ } else {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = ufshcd_query_attr(hba, ioctl_data->opcode,
+ ioctl_data->idn, index, 0, data_ptr);
+
+ if (!err && !write)
+ ioctl_data->buf_size =
+ min_t(int, ioctl_data->buf_size, sizeof(u32));
+ else
+ ioctl_data->buf_size = 0;
+
+out:
+ if (err)
+ dev_err(hba->dev, "Query Attribute failed (error: %d)", err);
+
+ return err;
+}
+
+static int ufshcd_ioctl_query_flag(struct ufs_hba *hba,
+ struct ufs_ioctl_query_data *ioctl_data, void *data_ptr,
+ bool write)
+{
+ int err = 0;
+
+ /*
+ * Some flags are added to reserved space between flags in
+ * more or less recent UFS Specs. If it's reserved for current
+ * device, we will get an R/W error during operation and return it.
+ */
+ if (ioctl_data->idn >= QUERY_FLAG_IDN_MAX) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = ufshcd_query_flag(hba, ioctl_data->opcode,
+ ioctl_data->idn, data_ptr);
+
+ if (!err && !write)
+ ioctl_data->buf_size =
+ min_t(int, ioctl_data->buf_size, sizeof(bool));
+ else
+ ioctl_data->buf_size = 0;
+
+out:
+ if (err)
+ dev_err(hba->dev, "Query Flag failed (error: %d)", err);
+
+ return err;
+}
+
+/**
+ * ufshcd_query_ioctl - perform user read queries
+ * @hba: per-adapter instance
+ * @lun: used for lun specific queries
+ * @buffer: user space buffer for reading and submitting query data and params
+ *
+ * Returns 0 for success or negative error code otherwise
+ *
+ * Expected/Submitted buffer structure is struct ufs_ioctl_query_data.
+ * It will read the opcode, idn and buf_length parameters, and put the
+ * response in the buffer field while updating the used size in buf_length.
+ */
+static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
+{
+ /*
+ * ioctl_data->buffer is untouchable - it's IO user data ptr.
+ *
+ * We might and will copy reply to it or request from it, but it's
+ * still pointer to user-space data, so treat it as __user argument.
+ */
+ struct ufs_ioctl_query_data *ioctl_data;
+ int err = 0;
+ void *data_ptr = NULL;
+ int length = 0;
+ size_t data_size = sizeof(*ioctl_data);
+ bool write = false;
+
+ if (!buffer)
+ return -EINVAL;
+
+ /* Prepare space in kernel for users request */
+ ioctl_data = kzalloc(data_size, GFP_KERNEL);
+
+ if (!ioctl_data) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* extract params from user buffer */
+ if (copy_from_user(ioctl_data, buffer, data_size)) {
+ err = -EFAULT;
+ goto out_release_mem;
+ }
+
+ if (!ioctl_data->buf_size) {
+ /* Noting to do */
+ err = 0;
+ goto out_release_mem;
+ }
+
+ switch (ioctl_data->opcode) {
+ case UPIU_QUERY_OPCODE_WRITE_DESC:
+ write = true;
+ case UPIU_QUERY_OPCODE_READ_DESC:
+ ufshcd_map_desc_id_to_length(hba, ioctl_data->idn, &length);
+ break;
+ case UPIU_QUERY_OPCODE_WRITE_ATTR:
+ write = true;
+ case UPIU_QUERY_OPCODE_READ_ATTR:
+ length = sizeof(u32);
+ break;
+ case UPIU_QUERY_OPCODE_SET_FLAG:
+ case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+ case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+ write = true;
+ case UPIU_QUERY_OPCODE_READ_FLAG:
+ length = sizeof(bool);
+ break;
+ default:
+ length = 0;
+ break;
+ }
+
+ if (!length) {
+ err = -EINVAL;
+ goto out_release_mem;
+ }
+
+ /* We have to allocate memory at this level */
+ data_ptr = kzalloc(length, GFP_KERNEL);
+
+ if (!data_ptr) {
+ err = -ENOMEM;
+ goto out_release_mem;
+ }
+
+ if (write) {
+ length = min_t(int, length, ioctl_data->buf_size);
+ err = copy_from_user(data_ptr, ioctl_data->buffer, length);
+
+ if (err)
+ goto out_release_mem;
+ }
+
+ /* Verify legal parameters & send query */
+ switch (ioctl_data->opcode) {
+ case UPIU_QUERY_OPCODE_WRITE_DESC:
+ case UPIU_QUERY_OPCODE_READ_DESC:
+ err = ufshcd_ioctl_query_desc(hba, ioctl_data, data_ptr,
+ lun, length, write);
+ break;
+ case UPIU_QUERY_OPCODE_WRITE_ATTR:
+ case UPIU_QUERY_OPCODE_READ_ATTR:
+ err = ufshcd_ioctl_query_attr(hba, ioctl_data, data_ptr,
+ lun, write);
+ break;
+ case UPIU_QUERY_OPCODE_SET_FLAG:
+ case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+ case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+ case UPIU_QUERY_OPCODE_READ_FLAG:
+ err = ufshcd_ioctl_query_flag(hba, ioctl_data,
+ data_ptr, write);
+ break;
+ default:
+ err = -EINVAL;
+ goto out_release_mem;
+ }
+
+ if (err)
+ goto out_release_mem;
+
+ /* Copy basic data to user */
+ err = copy_to_user(buffer, ioctl_data, data_size);
+
+ /*
+ * We copy result of query to ptr copied
+ * from user-space in the beginning
+ * if there is anything to be copied to user.
+ */
+ if (!err && ioctl_data->buf_size)
+ err = copy_to_user(ioctl_data->buffer, data_ptr,
+ ioctl_data->buf_size);
+
+out_release_mem:
+ kfree(ioctl_data);
+ kfree(data_ptr);
+out:
+ if (err)
+ dev_err(hba->dev, "User Query 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
+ * @buffer: user space buffer for transferring data
+ *
+ * Supported commands:
+ * UFS_IOCTL_QUERY
+ */
+int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
+{
+ struct ufs_hba *hba = shost_priv(dev->host);
+ int err = 0;
+
+ if (WARN_ON(!hba))
+ return -ENODEV;
+
+ switch (cmd) {
+ case UFS_IOCTL_QUERY:
+ pm_runtime_get_sync(hba->dev);
+ err = ufshcd_query_ioctl(hba, ufshcd_scsi_to_upiu_lun(dev->lun),
+ buffer);
+ pm_runtime_put_sync(hba->dev);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ if (err)
+ dev_err(hba->dev, "UFS ioctl() failed (cmd=%04x error: %d)",
+ cmd, err);
+
+ return err;
+}
diff --git a/drivers/scsi/ufs/ufshcd-ioctl.h b/drivers/scsi/ufs/ufshcd-ioctl.h
new file mode 100644
index 0000000..c86257d
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-ioctl.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * UFS ioctl - this architecture can be used to configure driver and
+ * device/host parameters, that are otherwise unavailable for such operation
+ */
+
+#ifndef _UFSHCD_IOCTL_H
+#define _UFSHCD_IOCTL_H
+
+#include <linux/errno.h>
+
+#include "ufshcd.h"
+
+#ifdef CONFIG_SCSI_UFSHCD_IOCTL
+int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer);
+#else
+static int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
+{
+ return -ENOIOCTLCMD;
+}
+#endif
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index abc7e87..9f3a39d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -41,9 +41,11 @@
#include <linux/devfreq.h>
#include <linux/nls.h>
#include <linux/of.h>
+
#include "ufshcd.h"
#include "ufs_quirks.h"
#include "unipro.h"
+#include "ufshcd-ioctl.h"
#define CREATE_TRACE_POINTS
#include <trace/events/ufs.h>
@@ -2244,7 +2246,7 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
*
* Returns UPIU LUN id
*/
-static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
+u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
{
if (scsi_is_wlun(scsi_lun))
return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID)
@@ -2259,7 +2261,7 @@ static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
*
* Returns SCSI W-LUN id
*/
-static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
+u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
{
return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE;
}
@@ -2720,7 +2722,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
*
* Returns 0 for success, non-zero in case of failure
*/
-static int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
enum attr_idn idn, u8 index, u8 selector, u32 *attr_val)
{
struct ufs_query_req *request = NULL;
@@ -2810,7 +2812,22 @@ static int ufshcd_query_attr_retry(struct ufs_hba *hba,
return ret;
}
-static int __ufshcd_query_descriptor(struct ufs_hba *hba,
+/**
+ * ufshcd_query_descriptor - API function for sending descriptor
+ * requests
+ * hba: per-adapter instance
+ * opcode: attribute opcode
+ * idn: attribute idn to access
+ * index: index field
+ * selector: selector field
+ * desc_buf: the buffer that contains the descriptor
+ * buf_len: length parameter passed to the device
+ *
+ * Returns 0 for success, non-zero in case of failure.
+ * The buf_len parameter will contain, on return, the length parameter
+ * received on the response.
+ */
+int ufshcd_query_descriptor(struct ufs_hba *hba,
enum query_opcode opcode, enum desc_idn idn, u8 index,
u8 selector, u8 *desc_buf, int *buf_len)
{
@@ -2875,8 +2892,8 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
}
/**
- * ufshcd_query_descriptor_retry - API function for sending descriptor
- * requests
+ * ufshcd_query_descriptor_retry - function for sending descriptor
+ * requests with retry mechanism
* hba: per-adapter instance
* opcode: attribute opcode
* idn: attribute idn to access
@@ -2890,16 +2907,16 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
* received on the response.
*/
static int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
- enum query_opcode opcode,
- enum desc_idn idn, u8 index,
- u8 selector,
- u8 *desc_buf, int *buf_len)
+ enum query_opcode opcode,
+ enum desc_idn idn, u8 index,
+ u8 selector,
+ u8 *desc_buf, int *buf_len)
{
int err;
int retries;
for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
- err = __ufshcd_query_descriptor(hba, opcode, idn, index,
+ err = ufshcd_query_descriptor(hba, opcode, idn, index,
selector, desc_buf, buf_len);
if (!err || err == -EINVAL)
break;
@@ -3184,7 +3201,7 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba,
* Unit descriptors are only available for general purpose LUs (LUN id
* from 0 to 7) and RPMB Well known LU.
*/
- if (lun != UFS_UPIU_RPMB_WLUN && (lun >= UFS_UPIU_MAX_GENERAL_LUN))
+ if (!ufs_is_valid_unit_desc_lun(lun))
return -EOPNOTSUPP;
return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun,
@@ -6502,6 +6519,10 @@ static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd)
.eh_device_reset_handler = ufshcd_eh_device_reset_handler,
.eh_host_reset_handler = ufshcd_eh_host_reset_handler,
.eh_timed_out = ufshcd_eh_timed_out,
+ .ioctl = ufshcd_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ufshcd_ioctl,
+#endif
.this_id = -1,
.sg_tablesize = SG_ALL,
.cmd_per_lun = UFSHCD_CMD_PER_LUN,
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index cdc8bd0..bf8a670 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -841,6 +841,13 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
/* Expose Query-Request API */
int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
enum flag_idn idn, bool *flag_res);
+
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+ enum attr_idn idn, u8 index, u8 selector, u32 *attr_val);
+
+int ufshcd_query_descriptor(struct ufs_hba *hba, enum query_opcode opcode,
+ enum desc_idn idn, u8 index, u8 selector, u8 *desc_buf, int *buf_len);
+
int ufshcd_hold(struct ufs_hba *hba, bool async);
void ufshcd_release(struct ufs_hba *hba);
@@ -849,6 +856,10 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba);
+/* Expose API for obtaining UPIU/SCSI LUN */
+u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun);
+u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id);
+
/* Wrapper functions for safely calling variant operations */
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
{
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index a1e1930..f128e9e 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -255,6 +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
*/
/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */
diff --git a/include/uapi/scsi/Kbuild b/include/uapi/scsi/Kbuild
index d791e0a..fad00e0 100644
--- a/include/uapi/scsi/Kbuild
+++ b/include/uapi/scsi/Kbuild
@@ -1,5 +1,6 @@
# UAPI Header export list
header-y += fc/
+header-y += ufs/
header-y += scsi_bsg_fc.h
header-y += scsi_netlink.h
header-y += scsi_netlink_fc.h
diff --git a/include/uapi/scsi/ufs/Kbuild b/include/uapi/scsi/ufs/Kbuild
new file mode 100644
index 0000000..cc3ef20
--- /dev/null
+++ b/include/uapi/scsi/ufs/Kbuild
@@ -0,0 +1,3 @@
+# UAPI Header export list
+header-y += ioctl.h
+header-y += ufs.h
diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h
new file mode 100644
index 0000000..1c65505
--- /dev/null
+++ b/include/uapi/scsi/ufs/ioctl.h
@@ -0,0 +1,61 @@
+#ifndef UAPI_UFS_IOCTL_H_
+#define UAPI_UFS_IOCTL_H_
+
+#include <linux/types.h>
+
+/*
+ * IOCTL opcode for ufs queries has the following opcode after
+ * SCSI_IOCTL_GET_PCI
+ */
+#define UFS_IOCTL_QUERY 0x53A0
+
+/**
+ * struct ufs_ioctl_query_data - used to transfer data to and from user via
+ * ioctl
+ *
+ * @opcode: type of data to query (descriptor/attribute/flag)
+ * @idn: id of the data structure
+ * @buf_size: number of allocated bytes/data size on return
+ * @buffer: data location
+ *
+ * Received: buffer and buf_size (available space for transferred data)
+ * Submitted: opcode, idn, length, buf_size
+ * Optionally submitted: buffer, buf_size (in Write operations)
+ */
+struct ufs_ioctl_query_data {
+ /*
+ * User should select one of the opcode defined in "enum query_opcode".
+ * Please check include/uapi/scsi/ufs/ufs.h for the definition of it.
+ * Note that only UPIU_QUERY_OPCODE_READ_DESC,
+ * UPIU_QUERY_OPCODE_READ_ATTR & UPIU_QUERY_OPCODE_READ_FLAG are
+ * supported as of now. All other query_opcode would be considered
+ * invalid.
+ * As of now only read query operations are supported.
+ */
+ __u32 opcode;
+ /*
+ * User should select one of the idn from "enum flag_idn" or "enum
+ * attr_idn" or "enum desc_idn" based on whether opcode above is
+ * attribute, flag or descriptor.
+ * Please check include/uapi/scsi/ufs/ufs.h for the definition of it.
+ */
+ __u8 idn;
+ /*
+ * User should specify the size of the buffer (buffer[0] below) where
+ * it wants to read the query data (attribute/flag/descriptor).
+ * As we might end up reading less data then what is specified in
+ * buf_size. So we are updating buf_size to what exactly we have read.
+ */
+ __u16 buf_size;
+ /*
+ * Pointer to the the data buffer where kernel will copy
+ * the query data (attribute/flag/descriptor) read from the UFS device
+ * Note:
+ * For Read Descriptor you will have to allocate at the most 255 bytes
+ * For Read Attribute you will have to allocate 4 bytes
+ * For Read Flag you will have to allocate 1 byte
+ */
+ __u8 *buffer;
+};
+
+#endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h
new file mode 100644
index 0000000..096ebea
--- /dev/null
+++ b/include/uapi/scsi/ufs/ufs.h
@@ -0,0 +1,69 @@
+#ifndef UAPI_UFS_H_
+#define UAPI_UFS_H_
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+ QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
+ QUERY_FLAG_IDN_PERM_WP_EN = 0x02,
+ QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
+ QUERY_FLAG_IDN_BKOPS_EN = 0x04,
+ QUERY_FLAG_IDN_DEV_LIFESPAN_MOD_EN = 0x05,
+ QUERY_FLAG_IDN_PURGE_EN = 0x06,
+ QUERY_FLAG_IDN_PHY_RES_RM = 0x08,
+ QUERY_FLAG_IDN_BUSY_RTC = 0x09,
+ QUERY_FLAG_IDN_PERM_DIS_FW_UPD = 0x0B,
+ QUERY_FLAG_IDN_MAX,
+};
+
+/* Attribute idn for Query requests */
+enum attr_idn {
+ QUERY_ATTR_IDN_BOOT_LUN_EN = 0x00,
+ QUERY_ATTR_IDN_RESERVED = 0x01,
+ QUERY_ATTR_IDN_CUR_PWR_MODE = 0x02,
+ QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
+ QUERY_ATTR_IDN_OUT_OF_ORD_DATA = 0x04,
+ QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
+ QUERY_ATTR_IDN_PURGE_STATUS = 0x06,
+ QUERY_ATTR_IDN_MAX_DIN_SIZE = 0x07,
+ QUERY_ATTR_IDN_MAX_DOUT_SIZE = 0x08,
+ QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09,
+ QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A,
+ QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B,
+ QUERY_ATTR_IDN_MAX_NUM_RTT = 0x0C,
+ QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
+ QUERY_ATTR_IDN_EE_STATUS = 0x0E,
+ QUERY_ATTR_IDN_SEC_PASSED = 0x0F,
+ QUERY_ATTR_IDN_CTX_CONF = 0x10,
+ QUERY_ATTR_IDN_PRG_BLK_NUM = 0x11,
+ QUERY_ATTR_IDN_MAX,
+};
+
+/* Descriptor idn for Query requests */
+enum desc_idn {
+ QUERY_DESC_IDN_DEVICE = 0x0,
+ QUERY_DESC_IDN_CONFIGURATION = 0x1,
+ QUERY_DESC_IDN_UNIT = 0x2,
+ QUERY_DESC_IDN_RFU_0 = 0x3,
+ QUERY_DESC_IDN_INTERCONNECT = 0x4,
+ QUERY_DESC_IDN_STRING = 0x5,
+ QUERY_DESC_IDN_RFU_1 = 0x6,
+ QUERY_DESC_IDN_GEOMETRY = 0x7,
+ QUERY_DESC_IDN_POWER = 0x8,
+ QUERY_DESC_IDN_DEV_HEALTH = 0x9,
+ QUERY_DESC_IDN_MAX,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
+ UPIU_QUERY_OPCODE_NOP = 0x0,
+ UPIU_QUERY_OPCODE_READ_DESC = 0x1,
+ UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
+ UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
+ UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
+ UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
+ UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
+ UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
+ UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
+};
+
+#endif /* UAPI_UFS_H_ */
--
1.9.1
--------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek
przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by
others is strictly prohibited.
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 2/4] scsi: ufs: Implement Auto-Hibern8 setup
2017-05-11 14:01 [PATCH v1 0/4] UFS ioctl UAPI Michal Potomski
2017-05-11 14:01 ` [PATCH v1 1/4] scsi: ufs: Add ioctl() interface with Query Request Michal Potomski
@ 2017-05-11 14:01 ` Michal Potomski
2017-05-11 14:01 ` [PATCH v1 3/4] scsi: ufs: Expose Task Management to ioctl() UAPI Michal Potomski
2017-05-11 14:01 ` [PATCH v1 4/4] scsi: ufs: add ioctl interface to read UIC attributes Michal Potomski
3 siblings, 0 replies; 7+ messages in thread
From: Michal Potomski @ 2017-05-11 14:01 UTC (permalink / raw)
To: linux-scsi
Cc: vinholikatti, martin.petersen, jejb, subhashj,
Michał Potomski
From: Michał Potomski <michalx.potomski@intel.com>
Since Auto-Hibern8 feature has to be enabled by the user
proper API has been given via ioctl() by adding it to
already existing implementation of UFS ioctl().
We expose this API to user-space, since we don't know
in driver, what kind of additional Power Management rules
user wants to use. Due to that we want to expose API, to
let user or high level S/W decide, whether it wants to
use Auto-Hibern8 feature for Power Saving and give him
"slider" to decide between performance and power efficiency.
This is important because different platforms using
the same UFS host and/or device might want different
options on this one, e.g. High-End Desktop PC might
want to have this feature disabled, while Mobile or
Server platforms might want to have this feature enabled,
but levels will vary depending on what's to be achieved.
As this feature is meant to be transparent for driver,
we'd like to let user decide whether he wants this enabled
or not.
Signed-off-by: Michał Potomski <michalx.potomski@intel.com>
---
Documentation/scsi/ufs.txt | 47 +++++++++++++++++++++++++++++++
drivers/scsi/ufs/ufshcd-ioctl.c | 62 +++++++++++++++++++++++++++++++++++++++++
drivers/scsi/ufs/ufshcd.c | 25 +++++++++++++++++
drivers/scsi/ufs/ufshcd.h | 4 +++
drivers/scsi/ufs/ufshci.h | 9 ++++--
include/scsi/scsi.h | 2 +-
include/uapi/scsi/ufs/Kbuild | 1 +
include/uapi/scsi/ufs/ioctl.h | 31 +++++++++++++++++++++
include/uapi/scsi/ufs/ufshci.h | 17 +++++++++++
9 files changed, 194 insertions(+), 4 deletions(-)
create mode 100644 include/uapi/scsi/ufs/ufshci.h
diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
index 7326974..6c0e995 100644
--- a/Documentation/scsi/ufs.txt
+++ b/Documentation/scsi/ufs.txt
@@ -17,6 +17,7 @@ Contents
3.4 SCSI Error handling
4. UFSHCD User Interface
4.1 UFS Query IOCTL
+ 4.2 UFS Auto-Hibern8 IOCTL
1. Overview
@@ -174,6 +175,52 @@ host and device using IOCTL interface.
This enables user to control some of the UFS specific features inaccessible
in other way.
+4.2 UFS Auto-Hibern8 IOCTL
+
+ This interface enables user to get/set information about UFS Host
+ Auto-Hibern8 feature for capable hosts. You can use following snippet
+ to comunicate with this interface:
+
+ #include <sys/ioctl.h>
+ #include <scsi/ufs/ioctl.h>
+ #include <scsi/ufs/ufshci.h>
+
+ static int handleWrite(int fd, uint8_t scale, uint16_t timer_val)
+ {
+ ufs_ioctl_auto_hibern8_data hibern8_data;
+
+ /* State, that we want to write the data */
+ hibern8_data.write = true;
+
+ /* Timer scale (check <scsi/ufs/ufshci.h>) */
+ hibern8_data.scale = *scale;
+
+ /* Timer value (max. 0x3fff) */
+ hibern8_data.timer_val = *timer_val;
+
+ /* [fd] used here shall be opened UFS device */
+ return ioctl(fd, UFS_IOCTL_AUTO_HIBERN8, &hibern8_data);
+ }
+
+ static int handleRead(int fd, uint8_t *scale, uint16_t *timer_val)
+ {
+ ufs_ioctl_auto_hibern8_data hibern8_data;
+ int error;
+
+ /* State, that we want to read data */
+ hibern8_data.write = false;
+
+ /* [fd] used here shall be opened UFS device */
+ error = ioctl(fd, UFS_IOCTL_AUTO_HIBERN8, &hibern8_data);
+
+ if (!error) {
+ *scale = hibern8_data.scale;
+ *timer_val = hibern8_data.timer_val;
+ }
+
+ return error;
+ }
+
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 ae70bf5..71f4026 100644
--- a/drivers/scsi/ufs/ufshcd-ioctl.c
+++ b/drivers/scsi/ufs/ufshcd-ioctl.c
@@ -273,6 +273,62 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
return err;
}
+static int ufshcd_auto_hibern8_ioctl(struct ufs_hba *hba, void __user *buffer)
+{
+ struct ufs_ioctl_auto_hibern8_data *ioctl_data;
+ int err = 0;
+ u32 status = 0;
+
+ if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+ return -ENOTSUPP;
+
+ if (!buffer)
+ return -EINVAL;
+
+ ioctl_data = kzalloc(sizeof(struct ufs_ioctl_auto_hibern8_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;
+ }
+
+ if (ioctl_data->write) {
+ if (ioctl_data->timer_val > UFSHCD_AHIBERN8_TIMER_MASK ||
+ (ioctl_data->scale >= UFSHCD_AHIBERN8_SCALE_MAX)) {
+ err = -EINVAL;
+ goto out_release_mem;
+ }
+
+ /* Write valid state to host */
+ ufshcd_setup_auto_hibern8(hba, ioctl_data->scale,
+ ioctl_data->timer_val);
+ } else {
+ status = ufshcd_read_auto_hibern8_state(hba);
+ ioctl_data->scale =
+ (status & UFSHCD_AHIBERN8_SCALE_MASK) >> 10;
+ ioctl_data->timer_val =
+ (status & UFSHCD_AHIBERN8_TIMER_MASK);
+
+ /* Copy state to user */
+ err = copy_to_user(buffer, ioctl_data, sizeof(*ioctl_data));
+ }
+
+out_release_mem:
+ kfree(ioctl_data);
+out:
+ if (err)
+ dev_err(hba->dev, "Auto-Hibern8 request failed (error: %d)",
+ err);
+
+ return err;
+}
+
/**
* ufshcd_ioctl - ufs ioctl callback registered in scsi_host
* @dev: scsi device required for per LUN queries
@@ -281,6 +337,7 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
*
* Supported commands:
* UFS_IOCTL_QUERY
+ * UFS_IOCTL_AUTO_HIBERN8
*/
int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
{
@@ -297,6 +354,11 @@ int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
buffer);
pm_runtime_put_sync(hba->dev);
break;
+ case UFS_IOCTL_AUTO_HIBERN8:
+ pm_runtime_get_sync(hba->dev);
+ err = ufshcd_auto_hibern8_ioctl(hba, buffer);
+ pm_runtime_put_sync(hba->dev);
+ break;
default:
err = -EOPNOTSUPP;
break;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9f3a39d..6fcbeb5 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -933,6 +933,30 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
}
/**
+ * ufshcd_read_auto_hibern8_state - Reads hosts auto-hibern8 feature state
+ * @hba: per adapter instance
+ */
+u32 ufshcd_read_auto_hibern8_state(struct ufs_hba *hba)
+{
+ return ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER);
+}
+
+/**
+ * ufshcd_setup_auto_hibern8 - Sets up hosts auto-hibern8 feature
+ * @hba: per adapter instance
+ * @scale: timer scale (1/10/100us/1/10/100ms)
+ * @timer_val: value to be multipled with scale (idle timeout)
+ */
+void ufshcd_setup_auto_hibern8(struct ufs_hba *hba, u8 scale, u16 timer_val)
+{
+ u32 val = (scale << 10) & UFSHCD_AHIBERN8_SCALE_MASK;
+
+ val |= timer_val & UFSHCD_AHIBERN8_TIMER_MASK;
+
+ ufshcd_writel(hba, val, REG_AUTO_HIBERNATE_IDLE_TIMER);
+}
+
+/**
* ufshcd_is_devfreq_scaling_required - check if scaling is required or not
* @hba: per adapter instance
* @scale_up: True if scaling up and false if scaling down
@@ -5338,6 +5362,7 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
{
hba->errors = UFSHCD_ERROR_MASK & intr_status;
+
if (hba->errors)
ufshcd_check_errors(hba);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index bf8a670..392f702 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -860,6 +860,10 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun);
u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id);
+/* Expose Auto-Hibern8 API */
+void ufshcd_setup_auto_hibern8(struct ufs_hba *hba, u8 scale, u16 timer_val);
+u32 ufshcd_read_auto_hibern8_state(struct ufs_hba *hba);
+
/* Wrapper functions for safely calling variant operations */
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
{
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index f60145d..789bbd8 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -36,6 +36,8 @@
#ifndef _UFSHCI_H
#define _UFSHCI_H
+#include <scsi/ufs/ufshci.h>
+
enum {
TASK_REQ_UPIU_SIZE_DWORDS = 8,
TASK_RSP_UPIU_SIZE_DWORDS = 8,
@@ -86,6 +88,7 @@ enum {
enum {
MASK_TRANSFER_REQUESTS_SLOTS = 0x0000001F,
MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000,
+ MASK_AUTO_HIBERN8_SUPPORT = 0x00800000,
MASK_64_ADDRESSING_SUPPORT = 0x01000000,
MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000,
MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000,
@@ -136,9 +139,9 @@ enum {
#define CONTROLLER_FATAL_ERROR UFS_BIT(16)
#define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17)
-#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\
- UIC_HIBERNATE_EXIT |\
- UIC_POWER_MODE)
+#define UFSHCD_UHS_MASK (UIC_HIBERNATE_EXIT | UIC_HIBERNATE_ENTER)
+
+#define UFSHCD_UIC_PWR_MASK (UFSHCD_UHS_MASK | UIC_POWER_MODE)
#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index f128e9e..43f87ad 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
+ * include/uapi/scsi/ufs/ioctl.h defines 0x53A0 - 0x53A1
*/
/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */
diff --git a/include/uapi/scsi/ufs/Kbuild b/include/uapi/scsi/ufs/Kbuild
index cc3ef20..07a2ce3 100644
--- a/include/uapi/scsi/ufs/Kbuild
+++ b/include/uapi/scsi/ufs/Kbuild
@@ -1,3 +1,4 @@
# UAPI Header export list
header-y += ioctl.h
header-y += ufs.h
+header-y += ufshci.h
diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h
index 1c65505..f3583de 100644
--- a/include/uapi/scsi/ufs/ioctl.h
+++ b/include/uapi/scsi/ufs/ioctl.h
@@ -8,6 +8,7 @@
* SCSI_IOCTL_GET_PCI
*/
#define UFS_IOCTL_QUERY 0x53A0
+#define UFS_IOCTL_AUTO_HIBERN8 0x53A1
/**
* struct ufs_ioctl_query_data - used to transfer data to and from user via
@@ -58,4 +59,34 @@ struct ufs_ioctl_query_data {
__u8 *buffer;
};
+/**
+ * struct ufs_ioctl_auto_hibern8_data - used to hold Auto-Hibern8 feature
+ * configuration
+ *
+ * @write: flag indicating whether config should be written or read
+ * @scale: scale of the timer (length of one tick)
+ * @timer_val: value of the timer to be multipled by scale (0x0000-0x3FFF)
+ *
+ * Received/Submitted: scale, timer_val
+ */
+struct ufs_ioctl_auto_hibern8_data {
+ /*
+ * This flag indicates whether configuration wirtten in this structure
+ * should be written, or overwritten by reading currently written
+ */
+ bool write;
+
+ /*
+ * Scale of the timer. Prease refer to <uapi/scsi/ufs/ufshci.h> for
+ * correct values and their meaning.
+ */
+ __u8 scale;
+
+ /*
+ * Actual timer value, which will be multipled by the scale.
+ * Maximal value: 1023. 0 will disable the feature.
+ */
+ __u16 timer_val;
+};
+
#endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufshci.h b/include/uapi/scsi/ufs/ufshci.h
new file mode 100644
index 0000000..c50065b
--- /dev/null
+++ b/include/uapi/scsi/ufs/ufshci.h
@@ -0,0 +1,17 @@
+#ifndef _UAPI_UFSHCI_H
+#define _UAPI_UFSHCI_H
+
+enum {
+ UFSHCD_AHIBERN8_SCALE_1US = 0,
+ UFSHCD_AHIBERN8_SCALE_10US = 1,
+ UFSHCD_AHIBERN8_SCALE_100US = 2,
+ UFSHCD_AHIBERN8_SCALE_1MS = 3,
+ UFSHCD_AHIBERN8_SCALE_10MS = 4,
+ UFSHCD_AHIBERN8_SCALE_100MS = 5,
+ UFSHCD_AHIBERN8_SCALE_MAX,
+};
+
+#define UFSHCD_AHIBERN8_TIMER_MASK 0x03ff
+#define UFSHCD_AHIBERN8_SCALE_MASK 0x1C00
+
+#endif
--
1.9.1
--------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek
przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by
others is strictly prohibited.
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 3/4] scsi: ufs: Expose Task Management to ioctl() UAPI
2017-05-11 14:01 [PATCH v1 0/4] UFS ioctl UAPI Michal Potomski
2017-05-11 14:01 ` [PATCH v1 1/4] scsi: ufs: Add ioctl() interface with Query Request Michal Potomski
2017-05-11 14:01 ` [PATCH v1 2/4] scsi: ufs: Implement Auto-Hibern8 setup Michal Potomski
@ 2017-05-11 14:01 ` Michal Potomski
2017-05-11 17:57 ` Christoph Hellwig
2017-05-11 14:01 ` [PATCH v1 4/4] scsi: ufs: add ioctl interface to read UIC attributes Michal Potomski
3 siblings, 1 reply; 7+ messages in thread
From: Michal Potomski @ 2017-05-11 14:01 UTC (permalink / raw)
To: linux-scsi
Cc: vinholikatti, martin.petersen, jejb, subhashj,
Michał Potomski
From: Michał Potomski <michalx.potomski@intel.com>
Since we already have UFS ioctl() API some additional tools
like task management are "nice-to-have" for testing and management
purposes.
Using this API we can transparently from user perspective
query or abort tasks and reset Logical Units. This will help
to test all hosts and devices to check their stability, error
handling, etc. While this feature does not present great value
for standard user, it might help a lot in troubleshooting of
the device.
Signed-off-by: Michał Potomski <michalx.potomski@intel.com>
---
Documentation/scsi/ufs.txt | 35 +++++++++++++++++++++++++
drivers/scsi/ufs/ufs.h | 10 --------
drivers/scsi/ufs/ufshcd-ioctl.c | 57 +++++++++++++++++++++++++++++++++++++++--
drivers/scsi/ufs/ufshcd.c | 2 +-
drivers/scsi/ufs/ufshcd.h | 4 +++
include/scsi/scsi.h | 2 +-
include/uapi/scsi/ufs/ioctl.h | 18 +++++++++++++
include/uapi/scsi/ufs/ufs.h | 10 ++++++++
8 files changed, 124 insertions(+), 14 deletions(-)
diff --git a/Documentation/scsi/ufs.txt b/Documentation/scsi/ufs.txt
index 6c0e995..ed5768d 100644
--- a/Documentation/scsi/ufs.txt
+++ b/Documentation/scsi/ufs.txt
@@ -18,6 +18,7 @@ Contents
4. UFSHCD User Interface
4.1 UFS Query IOCTL
4.2 UFS Auto-Hibern8 IOCTL
+ 4.3 UFS Task Management IOCTL
1. Overview
@@ -220,6 +221,40 @@ host and device using IOCTL interface.
return error;
}
+4.3 UFS Task Management IOCTL
+
+ This interface enables user to manage tasks on the 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 handleTask(int fd, uint8_t task_id, uint8_t task_func,
+ uint8_t *response)
+ {
+ ufs_ioctl_task_mgmt_data task_data;
+ int error;
+
+ /* Task ID (normally in range 0-F) */
+ task_data.task_id = task_id;
+
+ /* Task Function (check <scsi/ufs/ufs.h>) */
+ task_data.task_func = task_func;
+
+ /* [fd] used here shall be opened UFS device */
+ error = ioctl(fd, UFS_IOCTL_TASK_MANAGEMENT, &task_data);
+
+ if (!error)
+ /* This will return task specific response */
+ *response = task_data.response;
+
+ return error;
+ }
+
+ This one should be used with extreme care as it's more of a testing/vaidation
+ interface.
UFS Specifications can be found at,
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 06da302..8bfa5f3 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -88,16 +88,6 @@ static inline bool ufs_is_valid_unit_desc_lun(u8 lun)
* UFS Protocol Information Unit related definitions
*/
-/* Task management functions */
-enum {
- UFS_ABORT_TASK = 0x01,
- UFS_ABORT_TASK_SET = 0x02,
- UFS_CLEAR_TASK_SET = 0x04,
- UFS_LOGICAL_RESET = 0x08,
- UFS_QUERY_TASK = 0x80,
- UFS_QUERY_TASK_SET = 0x81,
-};
-
/* UTP UPIU Transaction Codes Initiator to Target */
enum {
UPIU_TRANSACTION_NOP_OUT = 0x00,
diff --git a/drivers/scsi/ufs/ufshcd-ioctl.c b/drivers/scsi/ufs/ufshcd-ioctl.c
index 71f4026..afcb099 100644
--- a/drivers/scsi/ufs/ufshcd-ioctl.c
+++ b/drivers/scsi/ufs/ufshcd-ioctl.c
@@ -180,6 +180,7 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
goto out_release_mem;
}
+ /* Prepare to handle query */
switch (ioctl_data->opcode) {
case UPIU_QUERY_OPCODE_WRITE_DESC:
write = true;
@@ -329,6 +330,51 @@ static int ufshcd_auto_hibern8_ioctl(struct ufs_hba *hba, void __user *buffer)
return err;
}
+static int ufshcd_task_mgmt_ioctl(struct ufs_hba *hba, u8 lun,
+ void __user *buffer)
+{
+ struct ufs_ioctl_task_mgmt_data *ioctl_data;
+ int err = 0;
+
+ if (!buffer)
+ return -EINVAL;
+
+ if (!ufs_is_valid_unit_desc_lun(lun))
+ return -EINVAL;
+
+ ioctl_data = kzalloc(sizeof(struct ufs_ioctl_task_mgmt_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_issue_tm_cmd(hba, lun, ioctl_data->task_id,
+ ioctl_data->task_func, &ioctl_data->response);
+
+ 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 Task Management failed (error: %d)",
+ err);
+
+ return err;
+}
+
/**
* ufshcd_ioctl - ufs ioctl callback registered in scsi_host
* @dev: scsi device required for per LUN queries
@@ -338,6 +384,7 @@ static int ufshcd_auto_hibern8_ioctl(struct ufs_hba *hba, void __user *buffer)
* Supported commands:
* UFS_IOCTL_QUERY
* UFS_IOCTL_AUTO_HIBERN8
+ * UFS_IOCTL_TASK_MANAGEMENT
*/
int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
{
@@ -359,6 +405,12 @@ int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
err = ufshcd_auto_hibern8_ioctl(hba, buffer);
pm_runtime_put_sync(hba->dev);
break;
+ case UFS_IOCTL_TASK_MANAGEMENT:
+ pm_runtime_get_sync(hba->dev);
+ err = ufshcd_task_mgmt_ioctl(hba,
+ ufshcd_scsi_to_upiu_lun(dev->lun), buffer);
+ pm_runtime_put_sync(hba->dev);
+ break;
default:
err = -EOPNOTSUPP;
break;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 6fcbeb5..6c52102 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5437,7 +5437,7 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag)
*
* Returns non-zero value on error, zero on success.
*/
-static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
+int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
u8 tm_function, u8 *tm_response)
{
struct utp_task_req_desc *task_req_descp;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 392f702..ef1607f 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -864,6 +864,10 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
void ufshcd_setup_auto_hibern8(struct ufs_hba *hba, u8 scale, u16 timer_val);
u32 ufshcd_read_auto_hibern8_state(struct ufs_hba *hba);
+/* Expose Task Management API */
+int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
+ u8 tm_function, u8 *tm_response);
+
/* Wrapper functions for safely calling variant operations */
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
{
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 43f87ad..b8e1006 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 - 0x53A1
+ * include/uapi/scsi/ufs/ioctl.h defines 0x53A0 - 0x53A2
*/
/* 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 f3583de..6b7e876 100644
--- a/include/uapi/scsi/ufs/ioctl.h
+++ b/include/uapi/scsi/ufs/ioctl.h
@@ -9,6 +9,7 @@
*/
#define UFS_IOCTL_QUERY 0x53A0
#define UFS_IOCTL_AUTO_HIBERN8 0x53A1
+#define UFS_IOCTL_TASK_MANAGEMENT 0x53A2
/**
* struct ufs_ioctl_query_data - used to transfer data to and from user via
@@ -89,4 +90,21 @@ struct ufs_ioctl_auto_hibern8_data {
__u16 timer_val;
};
+/**
+ * struct ufs_ioctl_task_mgmt_data - used to perform Task Management specific
+ * functions
+ *
+ * @task_id: ID of a task to be managed
+ * @task_func: function to perform on managed task
+ * @response: Task Management response
+ *
+ * Submitted: task_id, task_func
+ * Received: response
+ */
+struct ufs_ioctl_task_mgmt_data {
+ __u8 task_id;
+ __u8 task_func;
+ __u8 response;
+};
+
#endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h
index 096ebea..9f93c9a 100644
--- a/include/uapi/scsi/ufs/ufs.h
+++ b/include/uapi/scsi/ufs/ufs.h
@@ -66,4 +66,14 @@ enum query_opcode {
UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
};
+/* Task management functions */
+enum {
+ UFS_ABORT_TASK = 0x01,
+ UFS_ABORT_TASK_SET = 0x02,
+ UFS_CLEAR_TASK_SET = 0x04,
+ UFS_LOGICAL_RESET = 0x08,
+ UFS_QUERY_TASK = 0x80,
+ UFS_QUERY_TASK_SET = 0x81,
+};
+
#endif /* UAPI_UFS_H_ */
--
1.9.1
--------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek
przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by
others is strictly prohibited.
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v1 4/4] scsi: ufs: add ioctl interface to read UIC attributes
2017-05-11 14:01 [PATCH v1 0/4] UFS ioctl UAPI Michal Potomski
` (2 preceding siblings ...)
2017-05-11 14:01 ` [PATCH v1 3/4] scsi: ufs: Expose Task Management to ioctl() UAPI Michal Potomski
@ 2017-05-11 14:01 ` Michal Potomski
3 siblings, 0 replies; 7+ messages in thread
From: Michal Potomski @ 2017-05-11 14:01 UTC (permalink / raw)
To: linux-scsi
Cc: vinholikatti, martin.petersen, jejb, subhashj, Szymon Mielczarek,
Michał Potomski
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 --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_ */
--
1.9.1
--------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek
przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by
others is strictly prohibited.
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v1 3/4] scsi: ufs: Expose Task Management to ioctl() UAPI
2017-05-11 14:01 ` [PATCH v1 3/4] scsi: ufs: Expose Task Management to ioctl() UAPI Michal Potomski
@ 2017-05-11 17:57 ` Christoph Hellwig
0 siblings, 0 replies; 7+ messages in thread
From: Christoph Hellwig @ 2017-05-11 17:57 UTC (permalink / raw)
To: Michal Potomski; +Cc: linux-scsi, vinholikatti, martin.petersen, jejb, subhashj
On Thu, May 11, 2017 at 04:01:48PM +0200, Michal Potomski wrote:
> From: Michał Potomski <michalx.potomski@intel.com>
>
> Since we already have UFS ioctl() API some additional tools
> like task management are "nice-to-have" for testing and management
> purposes.
No way you're going to bypass the SCSI midlayer for task management.
NAK with prejudice.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v1 1/4] scsi: ufs: Add ioctl() interface with Query Request
2017-05-11 14:01 ` [PATCH v1 1/4] scsi: ufs: Add ioctl() interface with Query Request Michal Potomski
@ 2017-05-11 17:59 ` Christoph Hellwig
0 siblings, 0 replies; 7+ messages in thread
From: Christoph Hellwig @ 2017-05-11 17:59 UTC (permalink / raw)
To: Michal Potomski
Cc: linux-scsi, vinholikatti, martin.petersen, jejb, subhashj,
Szymon Mielczarek
NAK for new SCSI LLDD ioctl handlers, we're not in the 90s anymore.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2017-05-11 17:59 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-05-11 14:01 [PATCH v1 0/4] UFS ioctl UAPI Michal Potomski
2017-05-11 14:01 ` [PATCH v1 1/4] scsi: ufs: Add ioctl() interface with Query Request Michal Potomski
2017-05-11 17:59 ` Christoph Hellwig
2017-05-11 14:01 ` [PATCH v1 2/4] scsi: ufs: Implement Auto-Hibern8 setup Michal Potomski
2017-05-11 14:01 ` [PATCH v1 3/4] scsi: ufs: Expose Task Management to ioctl() UAPI Michal Potomski
2017-05-11 17:57 ` Christoph Hellwig
2017-05-11 14:01 ` [PATCH v1 4/4] scsi: ufs: add ioctl interface to read UIC attributes Michal Potomski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox