nvme: add nvme opcodes, structures and helper functions
authorAnkit Kumar <ankit.kumar@samsung.com>
Tue, 31 May 2022 13:31:50 +0000 (19:01 +0530)
committerJens Axboe <axboe@kernel.dk>
Thu, 2 Jun 2022 08:19:41 +0000 (02:19 -0600)
Add NVMe specification opcodes, data structures and helper
functions to get identify namespace and form nvme uring command.

This will help the follow up patches to get nvme-ns generic
character device size, lba size.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
Co-authored-by: Anuj Gupta <anuj20.g@samsung.com>
Link: https://lore.kernel.org/r/20220531133155.17493-5-ankit.kumar@samsung.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Makefile
engines/nvme.c [new file with mode: 0644]
engines/nvme.h [new file with mode: 0644]

index ed66305a202b3a81daf351f06f804ac0588ebb48..188a74d7b46e26d50aa7101731e41b7be742eeb4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -231,7 +231,7 @@ ifdef CONFIG_LIBXNVME
 endif
 ifeq ($(CONFIG_TARGET_OS), Linux)
   SOURCE += diskutil.c fifo.c blktrace.c cgroup.c trim.c engines/sg.c \
-               oslib/linux-dev-lookup.c engines/io_uring.c
+               oslib/linux-dev-lookup.c engines/io_uring.c engines/nvme.c
   cmdprio_SRCS = engines/cmdprio.c
 ifdef CONFIG_HAS_BLKZONED
   SOURCE += oslib/linux-blkzoned.c
@@ -241,7 +241,7 @@ endif
 endif
 ifeq ($(CONFIG_TARGET_OS), Android)
   SOURCE += diskutil.c fifo.c blktrace.c cgroup.c trim.c profiles/tiobench.c \
-               oslib/linux-dev-lookup.c engines/io_uring.c
+               oslib/linux-dev-lookup.c engines/io_uring.c engines/nvme.c
   cmdprio_SRCS = engines/cmdprio.c
 ifdef CONFIG_HAS_BLKZONED
   SOURCE += oslib/linux-blkzoned.c
diff --git a/engines/nvme.c b/engines/nvme.c
new file mode 100644 (file)
index 0000000..6fecf0b
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * nvme structure declarations and helper functions for the
+ * io_uring_cmd engine.
+ */
+
+#include "nvme.h"
+
+int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
+                           struct iovec *iov)
+{
+       struct nvme_data *data = FILE_ENG_DATA(io_u->file);
+       __u64 slba;
+       __u32 nlb;
+
+       memset(cmd, 0, sizeof(struct nvme_uring_cmd));
+
+       if (io_u->ddir == DDIR_READ)
+               cmd->opcode = nvme_cmd_read;
+       else if (io_u->ddir == DDIR_WRITE)
+               cmd->opcode = nvme_cmd_write;
+       else
+               return -ENOTSUP;
+
+       slba = io_u->offset >> data->lba_shift;
+       nlb = (io_u->xfer_buflen >> data->lba_shift) - 1;
+
+       /* cdw10 and cdw11 represent starting lba */
+       cmd->cdw10 = slba & 0xffffffff;
+       cmd->cdw11 = slba >> 32;
+       /* cdw12 represent number of lba's for read/write */
+       cmd->cdw12 = nlb;
+       if (iov) {
+               iov->iov_base = io_u->xfer_buf;
+               iov->iov_len = io_u->xfer_buflen;
+               cmd->addr = (__u64)(uintptr_t)iov;
+               cmd->data_len = 1;
+       } else {
+               cmd->addr = (__u64)(uintptr_t)io_u->xfer_buf;
+               cmd->data_len = io_u->xfer_buflen;
+       }
+       cmd->nsid = data->nsid;
+       return 0;
+}
+
+static int nvme_identify(int fd, __u32 nsid, enum nvme_identify_cns cns,
+                        enum nvme_csi csi, void *data)
+{
+       struct nvme_passthru_cmd cmd = {
+               .opcode         = nvme_admin_identify,
+               .nsid           = nsid,
+               .addr           = (__u64)(uintptr_t)data,
+               .data_len       = NVME_IDENTIFY_DATA_SIZE,
+               .cdw10          = cns,
+               .cdw11          = csi << NVME_IDENTIFY_CSI_SHIFT,
+               .timeout_ms     = NVME_DEFAULT_IOCTL_TIMEOUT,
+       };
+
+       return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+}
+
+int fio_nvme_get_info(struct fio_file *f, __u32 *nsid, __u32 *lba_sz,
+                     __u64 *nlba)
+{
+       struct nvme_id_ns ns;
+       unsigned int namespace_id;
+       int fd, err;
+
+       if (f->filetype != FIO_TYPE_CHAR) {
+               log_err("ioengine io_uring_cmd only works with nvme ns "
+                       "generic char devices (/dev/ngXnY)\n");
+               return 1;
+       }
+
+       fd = open(f->file_name, O_RDONLY);
+       if (fd < 0)
+               return -errno;
+
+       namespace_id = ioctl(fd, NVME_IOCTL_ID);
+       if (namespace_id < 0) {
+               log_err("failed to fetch namespace-id");
+               close(fd);
+               return -errno;
+       }
+
+       /*
+        * Identify namespace to get namespace-id, namespace size in LBA's
+        * and LBA data size.
+        */
+       err = nvme_identify(fd, namespace_id, NVME_IDENTIFY_CNS_NS,
+                               NVME_CSI_NVM, &ns);
+       if (err) {
+               log_err("failed to fetch identify namespace\n");
+               close(fd);
+               return err;
+       }
+
+       *nsid = namespace_id;
+       *lba_sz = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
+       *nlba = ns.nsze;
+
+       close(fd);
+       return 0;
+}
diff --git a/engines/nvme.h b/engines/nvme.h
new file mode 100644 (file)
index 0000000..8e626bb
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * nvme structure declarations and helper functions for the
+ * io_uring_cmd engine.
+ */
+
+#ifndef FIO_NVME_H
+#define FIO_NVME_H
+
+#include <linux/nvme_ioctl.h>
+#include "../fio.h"
+
+/*
+ * If the uapi headers installed on the system lacks nvme uring command
+ * support, use the local version to prevent compilation issues.
+ */
+#ifndef CONFIG_NVME_URING_CMD
+struct nvme_uring_cmd {
+       __u8    opcode;
+       __u8    flags;
+       __u16   rsvd1;
+       __u32   nsid;
+       __u32   cdw2;
+       __u32   cdw3;
+       __u64   metadata;
+       __u64   addr;
+       __u32   metadata_len;
+       __u32   data_len;
+       __u32   cdw10;
+       __u32   cdw11;
+       __u32   cdw12;
+       __u32   cdw13;
+       __u32   cdw14;
+       __u32   cdw15;
+       __u32   timeout_ms;
+       __u32   rsvd2;
+};
+
+#define NVME_URING_CMD_IO      _IOWR('N', 0x80, struct nvme_uring_cmd)
+#define NVME_URING_CMD_IO_VEC  _IOWR('N', 0x81, struct nvme_uring_cmd)
+#endif /* CONFIG_NVME_URING_CMD */
+
+#define NVME_DEFAULT_IOCTL_TIMEOUT 0
+#define NVME_IDENTIFY_DATA_SIZE 4096
+#define NVME_IDENTIFY_CSI_SHIFT 24
+
+enum nvme_identify_cns {
+       NVME_IDENTIFY_CNS_NS = 0x00,
+};
+
+enum nvme_csi {
+       NVME_CSI_NVM                    = 0,
+       NVME_CSI_KV                     = 1,
+       NVME_CSI_ZNS                    = 2,
+};
+
+enum nvme_admin_opcode {
+       nvme_admin_identify             = 0x06,
+};
+
+enum nvme_io_opcode {
+       nvme_cmd_write                  = 0x01,
+       nvme_cmd_read                   = 0x02,
+};
+
+struct nvme_data {
+       __u32 nsid;
+       __u32 lba_shift;
+};
+
+struct nvme_lbaf {
+       __le16                  ms;
+       __u8                    ds;
+       __u8                    rp;
+};
+
+struct nvme_id_ns {
+       __le64                  nsze;
+       __le64                  ncap;
+       __le64                  nuse;
+       __u8                    nsfeat;
+       __u8                    nlbaf;
+       __u8                    flbas;
+       __u8                    mc;
+       __u8                    dpc;
+       __u8                    dps;
+       __u8                    nmic;
+       __u8                    rescap;
+       __u8                    fpi;
+       __u8                    dlfeat;
+       __le16                  nawun;
+       __le16                  nawupf;
+       __le16                  nacwu;
+       __le16                  nabsn;
+       __le16                  nabo;
+       __le16                  nabspf;
+       __le16                  noiob;
+       __u8                    nvmcap[16];
+       __le16                  npwg;
+       __le16                  npwa;
+       __le16                  npdg;
+       __le16                  npda;
+       __le16                  nows;
+       __le16                  mssrl;
+       __le32                  mcl;
+       __u8                    msrc;
+       __u8                    rsvd81[11];
+       __le32                  anagrpid;
+       __u8                    rsvd96[3];
+       __u8                    nsattr;
+       __le16                  nvmsetid;
+       __le16                  endgid;
+       __u8                    nguid[16];
+       __u8                    eui64[8];
+       struct nvme_lbaf        lbaf[16];
+       __u8                    rsvd192[192];
+       __u8                    vs[3712];
+};
+
+static inline int ilog2(uint32_t i)
+{
+       int log = -1;
+
+       while (i) {
+               i >>= 1;
+               log++;
+       }
+       return log;
+}
+
+int fio_nvme_get_info(struct fio_file *f, __u32 *nsid, __u32 *lba_sz,
+                     __u64 *nlba);
+
+int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
+                           struct iovec *iov);
+
+#endif