]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
NVMe: Add compare command support
authorKeith Busch <keith.busch@intel.com>
Sat, 6 Dec 2014 00:16:45 +0000 (17:16 -0700)
committerKeith Busch <keith.busch@intel.com>
Sat, 6 Dec 2014 00:16:45 +0000 (17:16 -0700)
Signed-off-by: Keith Busch <keith.busch@intel.com>
Documentation/nvme-compare.txt [new file with mode: 0644]
nvme.c

diff --git a/Documentation/nvme-compare.txt b/Documentation/nvme-compare.txt
new file mode 100644 (file)
index 0000000..81436d9
--- /dev/null
@@ -0,0 +1,44 @@
+nvme-compare(1)
+===============
+
+NAME
+----
+nvme-compare - Send an NVMe Compare command, provide results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-compare' <device> [--start-block=<slba> | -s <slba>]
+                       [--block-count=<nlb> | -c <nlb>]
+                       [--data-size=<size> | -z <size>]
+                       [--ref-tag=<reftag> | -r <reftag>]
+                       [--data=<data-file> | -d <data-file>]
+                       [--prinfo=<prinfo> | -p <prinfo>]
+                       [--app-tag-mask=<appmask> | -m <appmask>]
+                       [--app-tag=<apptag> | -a <apptag>]
+                       [--limited-retry | -l]
+                       [--force-unit-access | -f]
+
+DESCRIPTION
+-----------
+The Compare command reads the logical blocks specified by the command
+from the medium and compares the data read to a comparison data buffer
+transferred as part of the command. If the data read from the controller
+and the comparison data buffer are equivalent with no miscompares,
+then the command completes successfully. If there is any miscompare,
+the command completes with an error of Compare Failure. If metadata is
+provided, then a comparison is also performed for the metadata.
+
+OPTIONS
+-------
+--start-block=<slba>::
+-s <slba>::
+       Start block.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/nvme.c b/nvme.c
index 783d6e36c8c3be0d464df049c12e51c04920eb64..1c9584b44c2329827e5acdcbe18f8d85534aeaa4 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -66,6 +66,7 @@ static const char *devicename;
        ENTRY(RESV_RELEASE, "resv-release", "Submit a Reservation Release, return results", resv_release) \
        ENTRY(RESV_REPORT, "resv-report", "Submit a Reservation Report, return results", resv_report) \
        ENTRY(FLUSH, "flush", "Submit a Flush command, return results", flush) \
+       ENTRY(COMPARE, "compare", "Submit a Comapre command, return results", compare) \
        ENTRY(HELP, "help", "Display this help", help)
 
 #define ENTRY(i, n, h, f) \
@@ -1610,6 +1611,82 @@ static int resv_report(int argc, char **argv)
        return 0;
 }
 
+static int compare(int argc, char **argv)
+{
+       struct nvme_user_io io;
+       void *buffer;
+        int err, opt, dfd = STDIN_FILENO, long_index = 0;
+       unsigned int data_size = 0;
+       __u8 prinfo = 0;
+       static struct option opts[] = {
+               {"start-block", required_argument, 0, 's'},
+               {"block-count", required_argument, 0, 'c'},
+               {"data-size", required_argument, 0, 'z'},
+               {"ref-tag", required_argument, 0, 'r'},
+               {"data", required_argument, 0, 'd'},
+               {"prinfo", required_argument, 0, 'p'},
+               {"app-tag-mask", required_argument, 0, 'm'},
+               {"app-tag", required_argument, 0, 'a'},
+               {"limited-retry", no_argument, 0, 'l'},
+               {"force-unit-access", no_argument, 0, 'f'},
+               { 0, 0, 0, 0}
+       };
+
+       memset(&io, 0, sizeof(io));
+       while ((opt = getopt_long(argc, (char **)argv, "p:s:c:z:r:d:m:a:lf", opts,
+                                                       &long_index)) != -1) {
+               switch(opt) {
+               case 's': get_long(optarg, &io.slba); break;
+               case 'c': get_short(optarg, &io.nblocks); break;
+               case 'z': get_int(optarg, &data_size); break;
+               case 'r': get_int(optarg, &io.reftag); break;
+               case 'm': get_short(optarg, &io.appmask); break;
+               case 'a': get_short(optarg, &io.apptag); break;
+               case 'p':
+                       get_byte(optarg, &prinfo);
+                       if (prinfo > 0xf)
+                               return EINVAL;
+                       io.control |= (prinfo << 10);
+                       break;
+               case 'l':
+                       io.control |= NVME_RW_LR;
+                       break;
+               case 'f':
+                       io.control | NVME_RW_FUA;
+                       break;
+               case 'd': 
+                       dfd = open(optarg, O_RDONLY);
+                       if (dfd < 0) {
+                               perror(optarg);
+                               return EINVAL;
+                       }
+                       break;
+               default:
+                       return EINVAL;
+               }
+       };
+       get_dev(optind, argc, argv);
+
+       if (!data_size) {
+               fprintf(stderr, "data size not provided\n");
+               return EINVAL;
+       }
+       buffer = malloc(data_size);
+       if (read(dfd, (void *)buffer, data_size) < 0) {
+               fprintf(stderr, "failed to read compare buffer\n");
+               return EINVAL;
+       }
+
+        io.opcode = nvme_cmd_compare;
+       io.addr = (__u64)buffer;
+       err = ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
+       if (err < 0)
+               perror("ioctl");
+       else
+               printf("compare:%s(%04x)\n", nvme_status_to_string(err), err);
+       return 0;
+}
+
 static int sec_recv(int argc, char **argv)
 {
        struct nvme_admin_cmd cmd;