]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
nvme: add Verify command
authorKenneth Heitke <kenneth.heitke@intel.com>
Fri, 10 May 2019 18:40:57 +0000 (12:40 -0600)
committerKenneth Heitke <kenneth.heitke@intel.com>
Tue, 23 Jul 2019 18:26:27 +0000 (12:26 -0600)
Reviewed-by: Edmund Nadolski <edmund.nadolski@intel.com>
Reviewed-by: Revanth Rajashekar <revanth.rajashekar@intel.com>
Signed-off-by: Kenneth Heitke <kenneth.heitke@intel.com>
linux/nvme.h
nvme-builtin.h
nvme-ioctl.c
nvme-ioctl.h
nvme-print.c
nvme.c

index a2cd1bb555b7fa65dd75574d9aa48bc7b37726e8..40bc8d7a76b6c5c121d601c5bec41b64b2abdbfc 100644 (file)
@@ -676,6 +676,7 @@ enum nvme_opcode {
        nvme_cmd_compare        = 0x05,
        nvme_cmd_write_zeroes   = 0x08,
        nvme_cmd_dsm            = 0x09,
+       nvme_cmd_verify         = 0x0c,
        nvme_cmd_resv_register  = 0x0d,
        nvme_cmd_resv_report    = 0x0e,
        nvme_cmd_resv_acquire   = 0x11,
index f9c91a53301427c5321b9e68c11494bbf90073f6..1eb8b9291c3fe6ad8930938ed5a1082b133026d7 100644 (file)
@@ -54,6 +54,7 @@ COMMAND_LIST(
        ENTRY("write", "Submit a write command, return results", write_cmd)
        ENTRY("write-zeroes", "Submit a write zeroes command, return results", write_zeroes)
        ENTRY("write-uncor", "Submit a write uncorrectable command, return results", write_uncor)
+       ENTRY("verify", "Submit a verify command, return results", verify_cmd)
        ENTRY("sanitize", "Submit a sanitize command", sanitize)
        ENTRY("sanitize-log", "Retrieve sanitize log, show it", sanitize_log)
        ENTRY("reset", "Resets the controller", reset)
index 524502bf4bedf9214bc7d8ba71602983364d1b9c..0fbb91314d1f07e90a11097cad8f8117880252d5 100644 (file)
@@ -178,6 +178,22 @@ int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
                       reftag, apptag, appmask, data, metadata);
 }
 
+int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
+               __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
+{
+       struct nvme_passthru_cmd cmd = {
+               .opcode         = nvme_cmd_verify,
+               .nsid           = nsid,
+               .cdw10          = slba & 0xffffffff,
+               .cdw11          = slba >> 32,
+               .cdw12          = nblocks | (control << 16),
+               .cdw14          = reftag,
+               .cdw15          = apptag | (appmask << 16),
+       };
+
+       return nvme_submit_io_passthru(fd, &cmd);
+}
+
 int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
                     __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
                     __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
index 68f0892570b44c61eb6214b1da1fa243cbd263a9..a0173c41833d9c7386a2987d4ed071f374f8d0a2 100644 (file)
@@ -38,6 +38,9 @@ int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control,
                 __u32 dsmgmt, __u32 reftag, __u16 apptag,
                 __u16 appmask, void *data, void *metadata);
 
+int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
+               __u16 control, __u32 reftag, __u16 apptag, __u16 appmask);
+
 /* NVME_IO_CMD */
 int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
                     __u32 nsid, __u32 cdw2, __u32 cdw3,
index 19f21424f2d67683d0939d770ef665a1e07ae7c8..2b6bc389015bc1eec35d0043314d25373bd0b6b7 100644 (file)
@@ -362,7 +362,8 @@ static void show_nvme_id_ctrl_cqes(__u8 cqes)
 static void show_nvme_id_ctrl_oncs(__le16 ctrl_oncs)
 {
        __u16 oncs = le16_to_cpu(ctrl_oncs);
-       __u16 rsvd = (oncs & 0xFF80) >> 7;
+       __u16 rsvd = (oncs & 0xFF00) >> 8;
+       __u16 vrfy = (oncs & 0x80) >> 7;
        __u16 tmst = (oncs & 0x40) >> 6;
        __u16 resv = (oncs & 0x20) >> 5;
        __u16 save = (oncs & 0x10) >> 4;
@@ -372,7 +373,9 @@ static void show_nvme_id_ctrl_oncs(__le16 ctrl_oncs)
        __u16 cmp = oncs & 0x1;
 
        if (rsvd)
-               printf(" [15:7] : %#x\tReserved\n", rsvd);
+               printf(" [15:8] : %#x\tReserved\n", rsvd);
+       printf("  [7:7] : %#x\tVerify %sSupported\n",
+               vrfy, vrfy ? "" : "Not ");
        printf("  [6:6] : %#x\tTimestamp %sSupported\n",
                tmst, tmst ? "" : "Not ");
        printf("  [5:5] : %#x\tReservations %sSupported\n",
diff --git a/nvme.c b/nvme.c
index fbb63a121489352b27711cbf05791881cbc9294c..fd806d00820b00789dc6e6fbce49e1ca39f9912f 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -108,7 +108,7 @@ static int open_dev(char *dev)
                return -ENODEV;
        }
        return fd;
- perror:
+perror:
        perror(dev);
        return err;
 }
@@ -4656,6 +4656,95 @@ static int write_cmd(int argc, char **argv, struct command *cmd, struct plugin *
        return submit_io(nvme_cmd_write, "write", desc, argc, argv);
 }
 
+static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       int err, fd;
+       __u16 control = 0;
+       const char *desc = "Verify specified logical blocks on the given device.";
+       const char *namespace_id = "desired namespace";
+       const char *start_block = "64-bit LBA of first block to access";
+       const char *block_count = "number of blocks (zeroes based) on device to access";
+       const char *limited_retry = "limit media access attempts";
+       const char *force = "force device to commit cached data before performing the verify operation";
+       const char *prinfo = "PI and check field";
+       const char *ref_tag = "reference tag (for end to end PI)";
+       const char *app_tag_mask = "app tag mask (for end to end PI)";
+       const char *app_tag = "app tag (for end to end PI)";
+
+       struct config {
+               __u64 start_block;
+               __u32 namespace_id;
+               __u32 ref_tag;
+               __u16 app_tag;
+               __u16 app_tag_mask;
+               __u16 block_count;
+               __u8  prinfo;
+               int   limited_retry;
+               int   force_unit_access;
+       };
+
+       struct config cfg = {
+               .namespace_id      = 0,
+               .start_block       = 0,
+               .block_count       = 0,
+               .prinfo            = 0,
+               .ref_tag           = 0,
+               .app_tag           = 0,
+               .app_tag_mask      = 0,
+               .limited_retry     = 0,
+               .force_unit_access = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id",      'n', "NUM", CFG_POSITIVE,    &cfg.namespace_id,      required_argument, namespace_id},
+               {"start-block",       's', "NUM", CFG_LONG_SUFFIX, &cfg.start_block,       required_argument, start_block},
+               {"block-count",       'c', "NUM", CFG_SHORT,       &cfg.block_count,       required_argument, block_count},
+               {"limited-retry",     'l', "",    CFG_NONE,        &cfg.limited_retry,     no_argument,       limited_retry},
+               {"force-unit-access", 'f', "",    CFG_NONE,        &cfg.force_unit_access, no_argument,       force},
+               {"prinfo",            'p', "NUM", CFG_BYTE,        &cfg.prinfo,            required_argument, prinfo},
+               {"ref-tag",           'r', "NUM", CFG_POSITIVE,    &cfg.ref_tag,           required_argument, ref_tag},
+               {"app-tag",           'a', "NUM", CFG_SHORT,       &cfg.app_tag,           required_argument, app_tag},
+               {"app-tag-mask",      'm', "NUM", CFG_SHORT,       &cfg.app_tag_mask,      required_argument, app_tag_mask},
+               {NULL}
+       };
+
+       fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+       if (fd < 0)
+               return fd;
+
+       if (cfg.prinfo > 0xf) {
+               err = EINVAL;
+               goto close_fd;
+       }
+
+       control |= (cfg.prinfo << 10);
+       if (cfg.limited_retry)
+               control |= NVME_RW_LR;
+       if (cfg.force_unit_access)
+               control |= NVME_RW_FUA;
+
+       if (!cfg.namespace_id) {
+               cfg.namespace_id = get_nsid(fd);
+               if (cfg.namespace_id == 0) {
+                       err = EINVAL;
+                       goto close_fd;
+               }
+       }
+
+       err = nvme_verify(fd, cfg.namespace_id, cfg.start_block, cfg.block_count,
+                               control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask);
+       if (err < 0)
+               perror("verify");
+       else if (err != 0)
+               show_nvme_status(err);
+       else
+               printf("NVME Verify Success\n");
+
+close_fd:
+       close(fd);
+       return err;
+}
+
 static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
 {
        const char *desc = "Obtain results of one or more "\