From 5dc44e6c21a1477f10dc28135760448f74e5d82d Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Thu, 2 Apr 2020 09:46:12 +0200 Subject: [PATCH] add support for issuing simple copy commands Add support for NVMe TP 4065a ("Simple Copy Command"), v2020.05.04 ("Ratified"). Signed-off-by: Klaus Jensen Co-authored-by: Steven Seungcheol Lee --- Documentation/nvme-copy.1 | 141 ++++ Documentation/nvme-copy.html | 989 ++++++++++++++++++++++++++++ Documentation/nvme-copy.txt | 111 ++++ completions/_nvme | 43 +- completions/bash-nvme-completion.sh | 11 +- linux/nvme.h | 20 +- nvme-builtin.h | 1 + nvme-ioctl.c | 46 ++ nvme-ioctl.h | 7 + nvme-print.c | 19 +- nvme-status.c | 1 - nvme.c | 131 ++++ 12 files changed, 1512 insertions(+), 8 deletions(-) create mode 100644 Documentation/nvme-copy.1 create mode 100644 Documentation/nvme-copy.html create mode 100644 Documentation/nvme-copy.txt diff --git a/Documentation/nvme-copy.1 b/Documentation/nvme-copy.1 new file mode 100644 index 00000000..9760e8c8 --- /dev/null +++ b/Documentation/nvme-copy.1 @@ -0,0 +1,141 @@ +'\" t +.\" Title: nvme-copy +.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" Date: 05/06/2020 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-COPY" "1" "05/06/2020" "NVMe" "NVMe Manual" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +nvme-copy \- Send an NVMe Simple Copy command, provide results +.SH "SYNOPSIS" +.sp +.nf +\fInvme\-copy\fR [\-\-sdlba= | \-d ] + [\-\-blocks= | \-b ] + [\-\-slbs= | \-s ] + [\-\-limited\-retry | \-l] + [\-\-force\-unit\-access | \-f] + [\-\-prinfow= | \-p ] + [\-\-prinfor= | \-P ] + [\-\-ref\-tag= | \-r ] + [\-\-expected\-ref\-tags= | \-R ] + [\-\-app\-tag= | \-a ] + [\-\-expected\-app\-tags= | \-A ] + [\-\-app\-mask= | \-m ] + [\-\-expected\-app\-masks= | \-M ] + [\-\-dir\-type= | \-T ] + [\-\-dir\-spec= | \-S ] + [\-\-format= | \-F ] +.fi +.SH "DESCRIPTION" +.sp +The Copy command is used by the host to copy data from one or more source logical block ranges to a single consecutive destination logical block range\&. +.SH "OPTIONS" +.PP +\-\-sdlba=, \-d +.RS 4 +64\-bit addr of first destination logical block +.RE +.PP +\-\-blocks=, \-b +.RS 4 +Comma separated list of the number of blocks in each range +.RE +.PP +\-\-slbs=, \-s +.RS 4 +Comma separated list of the starting blocks in each range +.RE +.PP +\-\-limited\-retry, \-l +.RS 4 +Sets the limited retry flag\&. +.RE +.PP +\-\-force\-unit\-access, \-f +.RS 4 +Set the force\-unit access flag\&. +.RE +.PP +\-\-prinfow=, \-p +.RS 4 +Protection Information field write definition\&. +.RE +.PP +\-\-prinfor=, \-P +.RS 4 +Protection Information field read definition\&. +.RE +.PP +\-\-ref\-tag=, \-r +.RS 4 +initial lba reference tag\&. +.RE +.PP +\-\-expected\-ref\-tags=, \-R +.RS 4 +expected lba reference tags (comma\-separated list)\&. +.RE +.PP +\-\-app\-tag=, \-a +.RS 4 +lba app tag +.RE +.PP +\-\-expected\-app\-tags=, \-A +.RS 4 +expected lba app tags (comma\-separated list) +.RE +.PP +\-\-app\-mask=, \-m +.RS 4 +lba tag mask +.RE +.PP +\-\-expected\-app\-masks=, \-M +.RS 4 +expected lba tag masks (comma\-separated list) +.RE +.PP +\-\-dir\-type=, \-T +.RS 4 +Optional directive type\&. The nvme\-cli only enforces the value be in the defined range for the directive type, though the NVMe specifcation (1\&.3a) defines only one directive, 01h, for write stream idenfiers\&. +.RE +.PP +\-\-dir\-spec=, \-S +.RS 4 +Optional field for directive specifics\&. When used with write streams, this value is defined to be the write stream identifier\&. The nvme\-cli will not validate the stream requested is within the controller\(cqs capabilities\&. +.RE +.PP +\-\-format=, \-F +.RS 4 +source range entry format +.RE +.SH "EXAMPLES" +.sp +No examples yet\&. +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-copy.html b/Documentation/nvme-copy.html new file mode 100644 index 00000000..96acd037 --- /dev/null +++ b/Documentation/nvme-copy.html @@ -0,0 +1,989 @@ + + + + + + +nvme-copy(1) + + + + + +
+
+

SYNOPSIS

+
+
+
nvme-copy <device> [--sdlba=<sdlba> | -d <sdlba>]
+                        [--blocks=<nlb-list,> | -b <nlb-list,>]
+                        [--slbs=<slbas,> | -s <slbas,>]
+                        [--limited-retry | -l]
+                        [--force-unit-access | -f]
+                        [--prinfow=<prinfow> | -p <prinfow>]
+                        [--prinfor=<prinfor> | -P <prinfor>]
+                        [--ref-tag=<reftag> | -r <reftag>]
+                        [--expected-ref-tags=<reftag,> | -R <reftag,>]
+                        [--app-tag=<apptag> | -a <apptag>]
+                        [--expected-app-tags=<apptag,> | -A <apptag,>]
+                        [--app-mask=<appmask> | -m <appmask>]
+                        [--expected-app-masks=<appmask,> | -M <appmask,>]
+                        [--dir-type=<type> | -T <type>]
+                        [--dir-spec=<spec> | -S <spec>]
+                        [--format=<entry-format> | -F <entry-format>]
+
+
+
+
+
+

DESCRIPTION

+
+

The Copy command is used by the host to copy data from one or more source +logical block ranges to a single consecutive destination logical block range.

+
+
+
+

OPTIONS

+
+
+
+--sdlba=<sdlba> +
+
+-d <sdlba> +
+
+

+ 64-bit addr of first destination logical block +

+
+
+--blocks=<nlb-list,> +
+
+-b <nlb-list,> +
+
+

+ Comma separated list of the number of blocks in each range +

+
+
+--slbs=<slbas,> +
+
+-s <slbas,> +
+
+

+ Comma separated list of the starting blocks in each range +

+
+
+--limited-retry +
+
+-l +
+
+

+ Sets the limited retry flag. +

+
+
+--force-unit-access +
+
+-f +
+
+

+ Set the force-unit access flag. +

+
+
+--prinfow=<prinfow> +
+
+-p <prinfow> +
+
+

+ Protection Information field write definition. +

+
+
+--prinfor=<prinfor> +
+
+-P <prinfor> +
+
+

+ Protection Information field read definition. +

+
+
+--ref-tag=<reftag> +
+
+-r <reftag> +
+
+

+ initial lba reference tag. +

+
+
+--expected-ref-tags=<reftag,> +
+
+-R <reftag,> +
+
+

+ expected lba reference tags (comma-separated list). +

+
+
+--app-tag=<apptag> +
+
+-a <apptag> +
+
+

+ lba app tag +

+
+
+--expected-app-tags=<apptag,> +
+
+-A <apptag,> +
+
+

+ expected lba app tags (comma-separated list) +

+
+
+--app-mask=<appmask> +
+
+-m <appmask> +
+
+

+ lba tag mask +

+
+
+--expected-app-masks=<appmask,> +
+
+-M <appmask,> +
+
+

+ expected lba tag masks (comma-separated list) +

+
+
+--dir-type=<type> +
+
+-T <type> +
+
+

+ Optional directive type. The nvme-cli only enforces the value + be in the defined range for the directive type, though the NVMe + specifcation (1.3a) defines only one directive, 01h, for write + stream idenfiers. +

+
+
+--dir-spec=<spec> +
+
+-S <spec> +
+
+

+ Optional field for directive specifics. When used with + write streams, this value is defined to be the write stream + identifier. The nvme-cli will not validate the stream requested + is within the controller’s capabilities. +

+
+
+--format=<entry-format> +
+
+-F <entry-format> +
+
+

+ source range entry format +

+
+
+
+
+
+

EXAMPLES

+
+

No examples yet.

+
+
+
+

NVME

+
+

Part of the nvme-user suite

+
+
+
+

+ + + diff --git a/Documentation/nvme-copy.txt b/Documentation/nvme-copy.txt new file mode 100644 index 00000000..d6452ec0 --- /dev/null +++ b/Documentation/nvme-copy.txt @@ -0,0 +1,111 @@ +nvme-copy(1) +============ + +NAME +---- +nvme-copy - Send an NVMe Simple Copy command, provide results + +SYNOPSIS +-------- +[verse] +'nvme-copy' [--sdlba= | -d ] + [--blocks= | -b ] + [--slbs= | -s ] + [--limited-retry | -l] + [--force-unit-access | -f] + [--prinfow= | -p ] + [--prinfor= | -P ] + [--ref-tag= | -r ] + [--expected-ref-tags= | -R ] + [--app-tag= | -a ] + [--expected-app-tags= | -A ] + [--app-mask= | -m ] + [--expected-app-masks= | -M ] + [--dir-type= | -T ] + [--dir-spec= | -S ] + [--format= | -F ] + +DESCRIPTION +----------- +The Copy command is used by the host to copy data from one or more source +logical block ranges to a single consecutive destination logical block range. + +OPTIONS +------- +--sdlba=:: +-d :: + 64-bit addr of first destination logical block + +--blocks=:: +-b :: + Comma separated list of the number of blocks in each range + +--slbs=:: +-s :: + Comma separated list of the starting blocks in each range + +--limited-retry:: +-l:: + Sets the limited retry flag. + +--force-unit-access:: +-f:: + Set the force-unit access flag. + +--prinfow=:: +-p :: + Protection Information field write definition. + +--prinfor=:: +-P :: + Protection Information field read definition. + +--ref-tag=:: +-r :: + initial lba reference tag. + +--expected-ref-tags=:: +-R :: + expected lba reference tags (comma-separated list). + +--app-tag=:: +-a :: + lba app tag + +--expected-app-tags=:: +-A :: + expected lba app tags (comma-separated list) + +--app-mask=:: +-m :: + lba tag mask + +--expected-app-masks=:: +-M :: + expected lba tag masks (comma-separated list) + +--dir-type=:: +-T :: + Optional directive type. The nvme-cli only enforces the value + be in the defined range for the directive type, though the NVMe + specifcation (1.3a) defines only one directive, 01h, for write + stream idenfiers. + +--dir-spec=:: +-S :: + Optional field for directive specifics. When used with + write streams, this value is defined to be the write stream + identifier. The nvme-cli will not validate the stream requested + is within the controller's capabilities. + +--format=:: +-F :: + source range entry format + +EXAMPLES +-------- +No examples yet. + +NVME +---- +Part of the nvme-user suite diff --git a/completions/_nvme b/completions/_nvme index 7a6e5ddc..7599f042 100644 --- a/completions/_nvme +++ b/completions/_nvme @@ -35,6 +35,7 @@ _nvme () { 'resv-register:register reservation on a namespace' 'resv-release:release reservation on a namespace' 'resv-report:report reservation on a namespace' + 'copy:submit a simple copy command' 'flush:submit a flush' 'compare:compare data on device to data elsewhere' 'read:submit a read command' @@ -530,6 +531,46 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme resv-register options" _reg ;; + (copy) + local _copy + _copy=( + /dev/nvme':supply a device to use (required)' + --sdlba=':64-bit addr of first destination logical block' + -d':alias of --sdlba' + --slbs=':64-bit addr of first block per range (comma-separated list)' + -s':alias of --slbs' + --blocks=':number of blocks per range (comma-separated list, zeroes-based values)' + -b':alias of --blocks' + --limited-retry':if included, controller should try less hard to retrieve data from media (if not included, all available data recovery means used)' + -l':alias of --limited-retry' + --force-unit-access':if included, the data shall be read from non-volatile media' + -f':alias of --force-unit access' + --prinfow=':protection information and check field (write part)' + -p':alias of --prinfow' + --prinfor=':protection information and check field (read part)' + -P':alias of --prinfor' + --ref-tag=':initial lba reference tag (write part)' + -r':alias of --ref-tag' + --expected-ref-tags=':expected lba reference tags (read part, comma-separated list)' + -R':alias of --expected-ref-tags' + --app-tag=':lba application tag (write part)' + -a':alias of --app-tag' + --expected-app-tags=':expected lba application tags (read part, comma-separated list)' + -A':alias of --expected-app-tags' + --app-tag-mask=':lba application tag mask (write part)' + -m':alias of --app-tag-mask' + --expected-app-tag-masks=':expected lba application tag masks (read part, comma-separated list)' + -M':alias of --expected-app-tag-masks' + --dir-type':directive type (write part)' + -T':alias of --dir-type' + --dir-spec':directive specific (write part)' + -S':alias of --dir-spec' + --format':source range entry format' + -F':alias of --format' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme copy options" _copy + ;; (flush) local _flush _flush=( @@ -658,7 +699,7 @@ _nvme () { list-ctrl get-ns-id get-log fw-log smart-log error-log get-feature set-feature format fw-activate fw-download admin-passthru io-passthru security-send security-recv resv-acquire resv-register resv-release - resv-report flush compare read write show-regs + resv-report flush compare read write copy show-regs ) _arguments '*:: :->subcmds' _describe -t commands "help: infos on a specific nvme command, or provide no option to see a synopsis of all nvme commands" _h diff --git a/completions/bash-nvme-completion.sh b/completions/bash-nvme-completion.sh index 5c5226e6..d417d06f 100644 --- a/completions/bash-nvme-completion.sh +++ b/completions/bash-nvme-completion.sh @@ -9,7 +9,7 @@ _cmds="list id-ctrl id-ns list-ns id-iocs create-ns delete-ns \ fw-download admin-passthru io-passthru security-send \ security-recv resv-acquire resv-register resv-release \ resv-report dsm flush compare read write write-zeroes \ - write-uncor reset subsystem-reset show-regs discover \ + write-uncor copy reset subsystem-reset show-regs discover \ connect-all connect disconnect version help \ intel lnvm memblaze list-subsys" @@ -148,6 +148,15 @@ nvme_list_opts () { opts+=" --namespace-id= -n --ctx-attrs= -a --blocks= -b\ -slbs= -s --ad -d --idw -w --idr -r --cdw11= -c" ;; + "copy") + opts+=" --sdlba= -d --blocks= -b --slbs= -s \ + --limited-retry -l --force-unit-access -f \ + --prinfow= -p --prinfor= -P \ + --ref-tag= -r --expected-ref-tag= -R \ + --app-tag= -a --expected-app-tag= -A \ + --app-tag-mask= -m --expected-app-tag-mask= -M \ + --dir-type= -T --dir-spec= -S --format= -F" + ;; "flush") opts+=" --namespace-id= -n" ;; diff --git a/linux/nvme.h b/linux/nvme.h index 86782ece..a7ab85d0 100644 --- a/linux/nvme.h +++ b/linux/nvme.h @@ -335,7 +335,7 @@ struct nvme_id_ctrl { __u8 icsvscc; __u8 nwpc; __le16 acwu; - __u8 rsvd534[2]; + __le16 ocfs; __le32 sgls; __le32 mnan; __u8 rsvd544[224]; @@ -405,7 +405,10 @@ struct nvme_id_ns { __le16 npdg; __le16 npda; __le16 nows; - __u8 rsvd74[18]; + __le16 mssrl; + __le32 mcl; + __u8 msrc; + __u8 rsvd81[11]; __le32 anagrpid; __u8 rsvd96[3]; __u8 nsattr; @@ -833,6 +836,7 @@ enum nvme_opcode { nvme_cmd_resv_report = 0x0e, nvme_cmd_resv_acquire = 0x11, nvme_cmd_resv_release = 0x15, + nvme_cmd_copy = 0x19, nvme_zns_cmd_mgmt_send = 0x79, nvme_zns_cmd_mgmt_recv = 0x7a, nvme_zns_cmd_append = 0x7d, @@ -962,6 +966,16 @@ struct nvme_dsm_range { __le64 slba; }; +struct nvme_copy_range { + __u8 rsvd0[8]; + __le64 slba; + __le16 nlb; + __u8 rsvd18[6]; + __le32 eilbrt; + __le16 elbatm; + __le16 elbat; +}; + /* Features */ struct nvme_feat_auto_pst { __le64 entries[32]; @@ -1403,7 +1417,7 @@ enum { NVME_SC_BAD_ATTRIBUTES = 0x180, NVME_SC_INVALID_PI = 0x181, NVME_SC_READ_ONLY = 0x182, - NVME_SC_ONCS_NOT_SUPPORTED = 0x183, + NVME_SC_CMD_SIZE_LIMIT_EXCEEDED = 0x183, /* * I/O Command Set Specific - Fabrics commands: diff --git a/nvme-builtin.h b/nvme-builtin.h index 6804ffe6..87338b5e 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -52,6 +52,7 @@ COMMAND_LIST( ENTRY("resv-release", "Submit a Reservation Release, return results", resv_release) ENTRY("resv-report", "Submit a Reservation Report, return results", resv_report) ENTRY("dsm", "Submit a Data Set Management command, return results", dsm) + ENTRY("copy", "Submit a Simple Copy command, return results", copy) ENTRY("flush", "Submit a Flush command, return results", flush) ENTRY("compare", "Submit a Compare command, return results", compare) ENTRY("read", "Submit a read command, return results", read_cmd) diff --git a/nvme-ioctl.c b/nvme-ioctl.c index 4da1d11a..0c516b26 100644 --- a/nvme-ioctl.c +++ b/nvme-ioctl.c @@ -269,6 +269,52 @@ struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas, return dsm; } +int nvme_copy(int fd, __u32 nsid, struct nvme_copy_range *copy, __u64 sdlba, + __u16 nr, __u8 prinfor, __u8 prinfow, __u8 dtype, __u16 dspec, + __u8 format, int lr, int fua, __u32 ilbrt, __u16 lbatm, + __u16 lbat) +{ + __u32 cdw12 = ((nr - 1) & 0xff) | ((format & 0xf) << 8) | + ((prinfor & 0xf) << 12) | ((dtype & 0xf) << 20) | + ((prinfow & 0xf) << 26) | ((fua & 0x1) << 30) | + ((lr & 0x1) << 31); + + struct nvme_passthru_cmd cmd = { + .opcode = nvme_cmd_copy, + .nsid = nsid, + .addr = (__u64)(uintptr_t)copy, + .data_len = nr * sizeof(*copy), + .cdw10 = sdlba & 0xffffffff, + .cdw11 = sdlba >> 32, + .cdw12 = cdw12, + .cdw13 = (dspec & 0xffff) << 16, + .cdw14 = ilbrt, + .cdw15 = (lbatm << 16) | lbat, + }; + + return nvme_submit_io_passthru(fd, &cmd); +} + +struct nvme_copy_range *nvme_setup_copy_range(__u16 *nlbs, __u64 *slbas, + __u32 *eilbrts, __u16 *elbatms, __u16 *elbats, __u16 nr) +{ + struct nvme_copy_range *copy = malloc(nr * sizeof(*copy)); + if (!copy) { + fprintf(stderr, "malloc: %s\n", strerror(errno)); + return NULL; + } + + for (int i = 0; i < nr; i++) { + copy[i].nlb = cpu_to_le16(nlbs[i]); + copy[i].slba = cpu_to_le64(slbas[i]); + copy[i].eilbrt = cpu_to_le32(eilbrts[i]); + copy[i].elbatm = cpu_to_le16(elbatms[i]); + copy[i].elbat = cpu_to_le16(elbats[i]); + } + + return copy; +} + int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa, bool iekey, __u64 crkey, __u64 nrkey) { diff --git a/nvme-ioctl.h b/nvme-ioctl.h index 6be12546..89cb4792 100644 --- a/nvme-ioctl.h +++ b/nvme-ioctl.h @@ -65,6 +65,13 @@ struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas, __u64 *slbas, __u16 nr_ranges); +int nvme_copy(int fd, __u32 nsid, struct nvme_copy_range *copy, __u64 sdlba, + __u16 nr, __u8 prinfor, __u8 prinfow, __u8 dtype, __u16 dspec, + __u8 format, int lr, int fua, __u32 ilbrt, __u16 lbatm, + __u16 lbat); +struct nvme_copy_range *nvme_setup_copy_range(__u16 *nlbs, __u64 *slbas, + __u32 *eilbrts, __u16 *elbatms, __u16 *elbats, __u16 nr); + int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa, bool iekey, __u64 crkey, __u64 nrkey); int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl, diff --git a/nvme-print.c b/nvme-print.c index 22ab8d75..f037a28c 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -176,6 +176,10 @@ static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode) json_object_add_value_int(root, "nows", le16_to_cpu(ns->nows)); } + json_object_add_value_int(root, "mssrl", le16_to_cpu(ns->mssrl)); + json_object_add_value_int(root, "mcl", le32_to_cpu(ns->mcl)); + json_object_add_value_int(root, "msrc", ns->msrc); + json_object_add_value_int(root, "anagrpid", le32_to_cpu(ns->anagrpid)); json_object_add_value_int(root, "endgid", le16_to_cpu(ns->endgid)); @@ -299,6 +303,7 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, json_object_add_value_int(root, "icsvscc", ctrl->icsvscc); json_object_add_value_int(root, "nwpc", ctrl->nwpc); json_object_add_value_int(root, "acwu", le16_to_cpu(ctrl->acwu)); + json_object_add_value_int(root, "ocfs", le16_to_cpu(ctrl->ocfs)); json_object_add_value_int(root, "sgls", le32_to_cpu(ctrl->sgls)); if (strlen(subnqn)) @@ -2082,7 +2087,8 @@ static void nvme_show_id_ctrl_cqes(__u8 cqes) static void nvme_show_id_ctrl_oncs(__le16 ctrl_oncs) { __u16 oncs = le16_to_cpu(ctrl_oncs); - __u16 rsvd = (oncs & 0xFF00) >> 8; + __u16 rsvd = (oncs & 0xFE00) >> 9; + __u16 copy = (oncs & 0x100) >> 8; __u16 vrfy = (oncs & 0x80) >> 7; __u16 tmst = (oncs & 0x40) >> 6; __u16 resv = (oncs & 0x20) >> 5; @@ -2093,7 +2099,9 @@ static void nvme_show_id_ctrl_oncs(__le16 ctrl_oncs) __u16 cmp = oncs & 0x1; if (rsvd) - printf(" [15:8] : %#x\tReserved\n", rsvd); + printf(" [15:9] : %#x\tReserved\n", rsvd); + printf(" [8:8] : %#x\tCopy %sSupported\n", + copy, copy ? "" : "Not "); printf(" [7:7] : %#x\tVerify %sSupported\n", vrfy, vrfy ? "" : "Not "); printf(" [6:6] : %#x\tTimestamp %sSupported\n", @@ -2475,6 +2483,9 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, printf("npda : %u\n", le16_to_cpu(ns->npda)); printf("nows : %u\n", le16_to_cpu(ns->nows)); } + printf("mssrl : %u\n", le16_to_cpu(ns->mssrl)); + printf("mcl : %d\n", le32_to_cpu(ns->mcl)); + printf("msrc : %u\n", ns->msrc); printf("nsattr : %u\n", ns->nsattr); printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid)); printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid)); @@ -2506,6 +2517,7 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, ns->lbaf[i].rp, i == (ns->flbas & 0xf) ? "(in use)" : ""); } + if (vs) { printf("vs[]:\n"); d(ns->vs, sizeof(ns->vs), 16, 1); @@ -2858,6 +2870,7 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, if (human) nvme_show_id_ctrl_nwpc(ctrl->nwpc); printf("acwu : %d\n", le16_to_cpu(ctrl->acwu)); + printf("ocfs : %d\n", le16_to_cpu(ctrl->ocfs)); printf("sgls : %#x\n", le32_to_cpu(ctrl->sgls)); if (human) nvme_show_id_ctrl_sgls(ctrl->sgls); @@ -4228,6 +4241,8 @@ const char *nvme_status_to_string(__u32 status) return "ANA_ATTACH_FAIL: The controller is not attached to the namespace as a result of an ANA condition"; case NVME_SC_BAD_ATTRIBUTES: return "BAD_ATTRIBUTES: Bad attributes were given"; + case NVME_SC_CMD_SIZE_LIMIT_EXCEEDED: + return "CMD_SIZE_LIMIT_EXCEEDED: Command size limit exceeded"; case NVME_SC_WRITE_FAULT: return "WRITE_FAULT: The write data could not be committed to the media"; case NVME_SC_READ_ERROR: diff --git a/nvme-status.c b/nvme-status.c index 1b060dc2..a78c1fd0 100644 --- a/nvme-status.c +++ b/nvme-status.c @@ -97,7 +97,6 @@ static inline __u8 nvme_cmd_specific_status_to_errno(__u16 status) case NVME_SC_NS_ALREADY_ATTACHED: return EALREADY; case NVME_SC_THIN_PROV_NOT_SUPP: - case NVME_SC_ONCS_NOT_SUPPORTED: return EOPNOTSUPP; case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS: return EINPROGRESS; diff --git a/nvme.c b/nvme.c index e08351c0..f1ea6b7d 100644 --- a/nvme.c +++ b/nvme.c @@ -3570,6 +3570,137 @@ ret: return nvme_status_to_errno(err, false); } +static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "The Copy command is used by the host to copy data " + "from one or more source logical block ranges to a " + "single consecutive destination logical block " + "range."; + + const char *d_sdlba = "64-bit addr of first destination logical block"; + const char *d_slbas = "64-bit addr of first block per range (comma-separated list)"; + const char *d_nlbs = "number of blocks per range (comma-separated list, zeroes-based values)"; + const char *d_lr = "limited retry"; + const char *d_fua = "force unit access"; + const char *d_prinfor = "protection information and check field (read part)"; + const char *d_prinfow = "protection information and check field (write part)"; + const char *d_ilbrt = "initial lba reference tag (write part)"; + const char *d_eilbrts = "expected lba reference tags (read part, comma-separated list)"; + const char *d_lbat = "lba application tag (write part)"; + const char *d_elbats = "expected lba application tags (read part, comma-separated list)"; + const char *d_lbatm = "lba application tag mask (write part)"; + const char *d_elbatms = "expected lba application tag masks (read part, comma-separated list)"; + const char *d_dtype = "directive type (write part)"; + const char *d_dspec = "directive specific (write part)"; + const char *d_format = "source range entry format"; + + int err, fd; + uint16_t nr, nb, ns, nrts, natms, nats; + __u32 namespace_id; + int nlbs[128] = { 0 }; + unsigned long long slbas[128] = {0,}; + int eilbrts[128] = { 0 }; + int elbatms[128] = { 0 }; + int elbats[128] = { 0 }; + struct nvme_copy_range *copy; + + struct config { + __u64 sdlba; + char *nlbs; + char *slbas; + __u32 ilbrt; + char *eilbrts; + __u16 lbatm; + char *elbatms; + __u16 lbat; + char *elbats; + __u8 prinfow; + __u8 prinfor; + int lr; + int fua; + __u8 dtype; + __u16 dspec; + __u8 format; + }; + + struct config cfg = { + .nlbs = "", + .slbas = "", + .eilbrts = "", + .elbatms = "", + .elbats = "", + }; + + OPT_ARGS(opts) = { + OPT_SUFFIX("sdlba", 'd', &cfg.sdlba, d_sdlba), + OPT_LIST("slbs", 's', &cfg.slbas, d_slbas), + OPT_LIST("blocks", 'b', &cfg.nlbs, d_nlbs), + OPT_FLAG("limited-retry", 'l', &cfg.lr, d_lr), + OPT_FLAG("force-unit-access", 'f', &cfg.fua, d_fua), + OPT_BYTE("prinfow", 'p', &cfg.prinfow, d_prinfow), + OPT_BYTE("prinfor", 'P', &cfg.prinfor, d_prinfor), + OPT_UINT("ref-tag", 'r', &cfg.ilbrt, d_ilbrt), + OPT_LIST("expected-ref-tags", 'R', &cfg.eilbrts, d_eilbrts), + OPT_SHRT("app-tag", 'a', &cfg.lbat, d_lbat), + OPT_LIST("expected-app-tags", 'A', &cfg.elbats, d_elbats), + OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, d_lbatm), + OPT_LIST("expected-app-tag-masks", 'M', &cfg.elbatms, d_elbatms), + OPT_BYTE("dir-type", 'T', &cfg.dtype, d_dtype), + OPT_SHRT("dir-spec", 'S', &cfg.dspec, d_dspec), + OPT_BYTE("format", 'F', &cfg.format, d_format), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) { + err = fd; + goto ret; + } + + nb = argconfig_parse_comma_sep_array(cfg.nlbs, nlbs, ARRAY_SIZE(nlbs)); + ns = argconfig_parse_comma_sep_array_long(cfg.slbas, slbas, ARRAY_SIZE(slbas)); + nrts = argconfig_parse_comma_sep_array(cfg.eilbrts, eilbrts, ARRAY_SIZE(eilbrts)); + natms = argconfig_parse_comma_sep_array(cfg.elbatms, elbatms, ARRAY_SIZE(elbatms)); + nats = argconfig_parse_comma_sep_array(cfg.elbats, elbats, ARRAY_SIZE(elbats)); + + nr = max(nb, max(ns, max(nrts, max(natms, nats)))); + if (!nr || nr > 128) { + fprintf(stderr, "invalid range\n"); + err = -EINVAL; + goto close_fd; + } + + namespace_id = nvme_get_nsid(fd); + if (namespace_id == 0) { + err = -EINVAL; + goto close_fd; + } + + copy = nvme_setup_copy_range((__u16 *)nlbs, (__u64 *)slbas, + (__u32 *)eilbrts, (__u16 *)elbatms, (__u16 *)elbats, + nr); + if (!copy) { + fprintf(stderr, "failed to allocate payload\n"); + err = -ENOMEM; + goto close_fd; + } + + err = nvme_copy(fd, namespace_id, copy, cfg.sdlba, nr, cfg.prinfor, + cfg.prinfow, cfg.dtype, cfg.dspec, cfg.format, cfg.lr, + cfg.fua, cfg.ilbrt, cfg.lbatm, cfg.lbat); + if (err < 0) + perror("NVMe Copy"); + else if (err != 0) + nvme_show_status(err); + else + printf("NVMe Copy: success\n"); + +close_fd: + close(fd); +ret: + return nvme_status_to_errno(err, false); +} + static int flush(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Commit data and metadata associated with "\ -- 2.50.1