From: Kenneth Heitke Date: Fri, 10 May 2019 18:40:57 +0000 (-0600) Subject: nvme: add Verify command X-Git-Tag: v1.9~28^2 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=eac5076d1dad95c7eb464f79dd1b7bc1bc263bcb;p=users%2Fsagi%2Fnvme-cli.git nvme: add Verify command Reviewed-by: Edmund Nadolski Reviewed-by: Revanth Rajashekar Signed-off-by: Kenneth Heitke --- diff --git a/linux/nvme.h b/linux/nvme.h index a2cd1bb5..40bc8d7a 100644 --- a/linux/nvme.h +++ b/linux/nvme.h @@ -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, diff --git a/nvme-builtin.h b/nvme-builtin.h index f9c91a53..1eb8b929 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -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) diff --git a/nvme-ioctl.c b/nvme-ioctl.c index 524502bf..0fbb9131 100644 --- a/nvme-ioctl.c +++ b/nvme-ioctl.c @@ -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, diff --git a/nvme-ioctl.h b/nvme-ioctl.h index 68f08925..a0173c41 100644 --- a/nvme-ioctl.h +++ b/nvme-ioctl.h @@ -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, diff --git a/nvme-print.c b/nvme-print.c index 19f21424..2b6bc389 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -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 fbb63a12..fd806d00 100644 --- 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 "\