clear-pkgs-linux-iot-lts2018/0029-nvme-connect-to-rpmb-l...

321 lines
9.1 KiB
Diff

From e15149c46ebef61db4df55552a043ab91117d100 Mon Sep 17 00:00:00 2001
From: Tomas Winkler <tomas.winkler@intel.com>
Date: Wed, 25 Apr 2018 19:07:06 +0300
Subject: [PATCH 029/550] nvme: connect to rpmb layer
This patch covers rpmb storage operation
as defined in NVMe spec 1.3a in section 8.10.
It only covers standard RPMB storage API, the device
configuration is not covered.
Change-Id: I35c9cc7aeec5a08041b9986d60fc9ee55c66dda7
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
drivers/nvme/host/Kconfig | 1 +
drivers/nvme/host/Makefile | 1 +
drivers/nvme/host/core.c | 54 +++++++++++++----
drivers/nvme/host/nvme.h | 9 +++
drivers/nvme/host/pci.c | 4 ++
drivers/nvme/host/rpmb.c | 119 +++++++++++++++++++++++++++++++++++++
6 files changed, 178 insertions(+), 10 deletions(-)
create mode 100644 drivers/nvme/host/rpmb.c
diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig
index 88a8b5916624..a0027cebf2db 100644
--- a/drivers/nvme/host/Kconfig
+++ b/drivers/nvme/host/Kconfig
@@ -5,6 +5,7 @@ config BLK_DEV_NVME
tristate "NVM Express block device"
depends on PCI && BLOCK
select NVME_CORE
+ select RPMB
---help---
The NVM Express driver is for solid state drives directly
connected to the PCI or PCI Express bus. If you know you
diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile
index aea459c65ae1..99f99e87b82b 100644
--- a/drivers/nvme/host/Makefile
+++ b/drivers/nvme/host/Makefile
@@ -15,6 +15,7 @@ nvme-core-$(CONFIG_NVM) += lightnvm.o
nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS) += fault_inject.o
nvme-y += pci.o
+nvme-y += rpmb.o
nvme-fabrics-y += fabrics.o
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index dd8ec1dd9219..43aa98f729d6 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -11,7 +11,6 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
-
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
#include <linux/delay.h>
@@ -1659,25 +1658,57 @@ static const struct pr_ops nvme_pr_ops = {
.pr_clear = nvme_pr_clear,
};
-#ifdef CONFIG_BLK_SED_OPAL
-int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
- bool send)
+int nvme_sec_send(struct nvme_ctrl *ctrl, u8 nssf, u16 spsp, u8 secp,
+ void *buffer, size_t len)
{
- struct nvme_ctrl *ctrl = data;
struct nvme_command cmd;
+ dev_dbg(ctrl->device, "%s target = %hhu SPSP = %hu SECP = %hhX len=%zd\n",
+ __func__, nssf, spsp, secp, len);
+
memset(&cmd, 0, sizeof(cmd));
- if (send)
- cmd.common.opcode = nvme_admin_security_send;
- else
- cmd.common.opcode = nvme_admin_security_recv;
+ cmd.common.opcode = nvme_admin_security_send;
+ cmd.common.nsid = 0;
+ cmd.common.cdw10[0] =
+ cpu_to_le32(((u32)secp) << 24 | ((u32)spsp) << 8 | nssf);
+ cmd.common.cdw10[1] = cpu_to_le32(len);
+
+ return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len,
+ ADMIN_TIMEOUT, NVME_QID_ANY, 1, 0);
+}
+EXPORT_SYMBOL_GPL(nvme_sec_send);
+
+int nvme_sec_recv(struct nvme_ctrl *ctrl, u8 nssf, u16 spsp, u8 secp,
+ void *buffer, size_t len)
+{
+ struct nvme_command cmd;
+
+ dev_dbg(ctrl->device, "%s target = %hhu SPSP = %hu SECP = %hhX len=%zd\n",
+ __func__, nssf, spsp, secp, len);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.common.opcode = nvme_admin_security_recv;
cmd.common.nsid = 0;
- cmd.common.cdw10[0] = cpu_to_le32(((u32)secp) << 24 | ((u32)spsp) << 8);
+ cmd.common.cdw10[0] =
+ cpu_to_le32(((u32)secp) << 24 | ((u32)spsp) << 8 | nssf);
cmd.common.cdw10[1] = cpu_to_le32(len);
return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len,
ADMIN_TIMEOUT, NVME_QID_ANY, 1, 0);
}
+EXPORT_SYMBOL_GPL(nvme_sec_recv);
+
+#ifdef CONFIG_BLK_SED_OPAL
+int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
+ bool send)
+{
+ struct nvme_ctrl *ctrl = data;
+
+ if (send)
+ return nvme_sec_send(ctrl, 0, spsp, secp, buffer, len);
+ else
+ return nvme_sec_recv(ctrl, 0, spsp, secp, buffer, len);
+}
EXPORT_SYMBOL_GPL(nvme_sec_submit);
#endif /* CONFIG_BLK_SED_OPAL */
@@ -2468,7 +2499,10 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
ctrl->hmmaxd = le16_to_cpu(id->hmmaxd);
}
+ ctrl->rpmbs = le32_to_cpu(id->rpmbs);
+
ret = nvme_mpath_init(ctrl, id);
+
kfree(id);
if (ret < 0)
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index bb4a2003c097..a596e9e84d1e 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -21,6 +21,7 @@
#include <linux/blk-mq.h>
#include <linux/lightnvm.h>
#include <linux/sed-opal.h>
+#include <linux/rpmb.h>
#include <linux/fault-inject.h>
#include <linux/rcupdate.h>
@@ -167,6 +168,7 @@ struct nvme_ctrl {
struct list_head subsys_entry;
struct opal_dev *opal_dev;
+ struct rpmb_dev *rdev;
char name[12];
u16 cntlid;
@@ -193,6 +195,7 @@ struct nvme_ctrl {
u8 apsta;
u32 oaes;
u32 aen_result;
+ u32 rpmbs;
unsigned int shutdown_timeout;
unsigned int kato;
bool subsystem;
@@ -420,6 +423,12 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl);
void nvme_stop_ctrl(struct nvme_ctrl *ctrl);
void nvme_put_ctrl(struct nvme_ctrl *ctrl);
int nvme_init_identify(struct nvme_ctrl *ctrl);
+int nvme_sec_send(struct nvme_ctrl *ctrl, u8 nssf, u16 spsp, u8 secp,
+ void *buffer, size_t len);
+int nvme_sec_recv(struct nvme_ctrl *ctrl, u8 nssf, u16 spsp, u8 secp,
+ void *buffer, size_t len);
+int nvme_init_rpmb(struct nvme_ctrl *ctrl);
+void nvme_exit_rpmb(struct nvme_ctrl *ctrl);
void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index d668682f91df..6c19fa7525e3 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2289,6 +2289,10 @@ static void nvme_reset_work(struct work_struct *work)
if (result)
goto out;
+ result = nvme_init_rpmb(&dev->ctrl);
+ if (result < 0)
+ goto out;
+
if (dev->ctrl.oacs & NVME_CTRL_OACS_SEC_SUPP) {
if (!dev->ctrl.opal_dev)
dev->ctrl.opal_dev =
diff --git a/drivers/nvme/host/rpmb.c b/drivers/nvme/host/rpmb.c
new file mode 100644
index 000000000000..34e807bfc4f9
--- /dev/null
+++ b/drivers/nvme/host/rpmb.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/*
+ * Copyright(c) 2018 Intel Corporation. All rights reserved.
+ */
+#include <linux/rpmb.h>
+#include "nvme.h"
+#define NVME_SECP_RPMB 0xEA /* Security Protocol EAh is assigned
+ * for NVMe use (refer to ACS-4)
+ */
+#define NVME_SPSP_RPMB 0x0001 /* RPMB Target */
+static int nvme_rpmb_cmd_seq(struct device *dev, u8 target,
+ struct rpmb_cmd *cmds, u32 ncmds)
+{
+ struct nvme_ctrl *ctrl;
+ struct rpmb_cmd *cmd;
+ u32 size;
+ int ret;
+ int i;
+
+ ctrl = dev_get_drvdata(dev);
+
+ for (ret = 0, i = 0; i < ncmds && !ret; i++) {
+ cmd = &cmds[i];
+ size = rpmb_ioc_frames_len_nvme(cmd->nframes);
+ if (cmd->flags & RPMB_F_WRITE)
+ ret = nvme_sec_send(ctrl, target,
+ NVME_SPSP_RPMB, NVME_SECP_RPMB,
+ cmd->frames, size);
+ else
+ ret = nvme_sec_recv(ctrl, target,
+ NVME_SPSP_RPMB, NVME_SECP_RPMB,
+ cmd->frames, size);
+ }
+
+ return ret;
+}
+
+static int nvme_rpmb_get_capacity(struct device *dev, u8 target)
+{
+ struct nvme_ctrl *ctrl;
+
+ ctrl = dev_get_drvdata(dev);
+
+ return ((ctrl->rpmbs >> 16) & 0xFF) + 1;
+}
+
+static struct rpmb_ops nvme_rpmb_dev_ops = {
+ .cmd_seq = nvme_rpmb_cmd_seq,
+ .get_capacity = nvme_rpmb_get_capacity,
+ .type = RPMB_TYPE_NVME,
+};
+
+static void nvme_rpmb_set_cap(struct nvme_ctrl *ctrl,
+ struct rpmb_ops *ops)
+{
+ ops->wr_cnt_max = ((ctrl->rpmbs >> 24) & 0xFF) + 1;
+ ops->rd_cnt_max = ops->wr_cnt_max;
+ ops->block_size = 2; /* 1 sector == 2 half sectors */
+ ops->auth_method = (ctrl->rpmbs >> 3) & 0x3;
+}
+
+static void nvme_rpmb_add(struct nvme_ctrl *ctrl)
+{
+ struct rpmb_dev *rdev;
+ int ndevs = ctrl->rpmbs & 0x7;
+ int i;
+
+ nvme_rpmb_set_cap(ctrl, &nvme_rpmb_dev_ops);
+
+ /* Add RPMB partitions */
+ for (i = 0; i < ndevs; i++) {
+ rdev = rpmb_dev_register(ctrl->device, i, &nvme_rpmb_dev_ops);
+ if (IS_ERR(rdev)) {
+ dev_warn(ctrl->device, "%s: cannot register to rpmb %ld\n",
+ dev_name(ctrl->device), PTR_ERR(rdev));
+ }
+ dev_set_drvdata(&rdev->dev, ctrl);
+ }
+}
+
+static void nvme_rpmb_remove(struct nvme_ctrl *ctrl)
+{
+ int ndevs = ctrl->rpmbs & 0x7;
+ int i;
+
+ /* FIXME: target */
+ for (i = 0; i < ndevs; i++)
+ rpmb_dev_unregister_by_device(ctrl->device, i);
+}
+
+int nvme_init_rpmb(struct nvme_ctrl *ctrl)
+{
+ dev_err(ctrl->device, "RPMBS %X\n", ctrl->rpmbs);
+
+ if ((ctrl->rpmbs & 0x7) == 0x0) {
+ dev_err(ctrl->device, "RPMBS No partitions\n");
+ return 0;
+ }
+
+ dev_err(ctrl->device, "RPMBS Number of partitions %d\n",
+ ctrl->rpmbs & 0x7);
+ dev_err(ctrl->device, "RPMBS Authentication Method: %d\n",
+ (ctrl->rpmbs >> 3) & 0x3);
+ dev_err(ctrl->device, "RPMBS Total Size: %d %dK",
+ (ctrl->rpmbs >> 16) & 0xFF,
+ (((ctrl->rpmbs >> 16) & 0xFF) + 1) * 128);
+ dev_err(ctrl->device, "RPMBS Access Size: %d %dB",
+ (ctrl->rpmbs >> 24) & 0xFF,
+ (((ctrl->rpmbs >> 24) & 0xFF) + 1) * 512);
+
+ nvme_rpmb_add(ctrl);
+
+ return 0;
+}
+
+void nvme_exit_rpmb(struct nvme_ctrl *ctrl)
+{
+ nvme_rpmb_remove(ctrl);
+}
--
2.19.1