]> www.infradead.org Git - users/hch/nvme-cli.git/commitdiff
add support for issuing simple copy commands
authorKlaus Jensen <k.jensen@samsung.com>
Thu, 2 Apr 2020 07:46:12 +0000 (09:46 +0200)
committerKeith Busch <kbusch@kernel.org>
Fri, 31 Jul 2020 17:22:38 +0000 (11:22 -0600)
Add support for NVMe TP 4065a ("Simple Copy Command"), v2020.05.04
("Ratified").

Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Co-authored-by: Steven Seungcheol Lee <sc108.lee@samsung.com>
12 files changed:
Documentation/nvme-copy.1 [new file with mode: 0644]
Documentation/nvme-copy.html [new file with mode: 0644]
Documentation/nvme-copy.txt [new file with mode: 0644]
completions/_nvme
completions/bash-nvme-completion.sh
linux/nvme.h
nvme-builtin.h
nvme-ioctl.c
nvme-ioctl.h
nvme-print.c
nvme-status.c
nvme.c

diff --git a/Documentation/nvme-copy.1 b/Documentation/nvme-copy.1
new file mode 100644 (file)
index 0000000..9760e8c
--- /dev/null
@@ -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 <http://docbook.sf.net/>
+.\"      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 <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>]
+.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=<sdlba>, \-d <sdlba>
+.RS 4
+64\-bit addr of first destination logical block
+.RE
+.PP
+\-\-blocks=<nlb\-list,>, \-b <nlb\-list,>
+.RS 4
+Comma separated list of the number of blocks in each range
+.RE
+.PP
+\-\-slbs=<slbas,>, \-s <slbas,>
+.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=<prinfow>, \-p <prinfow>
+.RS 4
+Protection Information field write definition\&.
+.RE
+.PP
+\-\-prinfor=<prinfor>, \-P <prinfor>
+.RS 4
+Protection Information field read definition\&.
+.RE
+.PP
+\-\-ref\-tag=<reftag>, \-r <reftag>
+.RS 4
+initial lba reference tag\&.
+.RE
+.PP
+\-\-expected\-ref\-tags=<reftag,>, \-R <reftag,>
+.RS 4
+expected lba reference tags (comma\-separated list)\&.
+.RE
+.PP
+\-\-app\-tag=<apptag>, \-a <apptag>
+.RS 4
+lba app tag
+.RE
+.PP
+\-\-expected\-app\-tags=<apptag,>, \-A <apptag,>
+.RS 4
+expected lba app tags (comma\-separated list)
+.RE
+.PP
+\-\-app\-mask=<appmask>, \-m <appmask>
+.RS 4
+lba tag mask
+.RE
+.PP
+\-\-expected\-app\-masks=<appmask,>, \-M <appmask,>
+.RS 4
+expected lba tag masks (comma\-separated list)
+.RE
+.PP
+\-\-dir\-type=<type>, \-T <type>
+.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=<spec>, \-S <spec>
+.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=<entry\-format>, \-F <entry\-format>
+.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 (file)
index 0000000..96acd03
--- /dev/null
@@ -0,0 +1,989 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
+    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
+<head>\r
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
+<meta name="generator" content="AsciiDoc 8.6.10" />\r
+<title>nvme-copy(1)</title>\r
+<style type="text/css">\r
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */\r
+\r
+/* Default font. */\r
+body {\r
+  font-family: Georgia,serif;\r
+}\r
+\r
+/* Title font. */\r
+h1, h2, h3, h4, h5, h6,\r
+div.title, caption.title,\r
+thead, p.table.header,\r
+#toctitle,\r
+#author, #revnumber, #revdate, #revremark,\r
+#footer {\r
+  font-family: Arial,Helvetica,sans-serif;\r
+}\r
+\r
+body {\r
+  margin: 1em 5% 1em 5%;\r
+}\r
+\r
+a {\r
+  color: blue;\r
+  text-decoration: underline;\r
+}\r
+a:visited {\r
+  color: fuchsia;\r
+}\r
+\r
+em {\r
+  font-style: italic;\r
+  color: navy;\r
+}\r
+\r
+strong {\r
+  font-weight: bold;\r
+  color: #083194;\r
+}\r
+\r
+h1, h2, h3, h4, h5, h6 {\r
+  color: #527bbd;\r
+  margin-top: 1.2em;\r
+  margin-bottom: 0.5em;\r
+  line-height: 1.3;\r
+}\r
+\r
+h1, h2, h3 {\r
+  border-bottom: 2px solid silver;\r
+}\r
+h2 {\r
+  padding-top: 0.5em;\r
+}\r
+h3 {\r
+  float: left;\r
+}\r
+h3 + * {\r
+  clear: left;\r
+}\r
+h5 {\r
+  font-size: 1.0em;\r
+}\r
+\r
+div.sectionbody {\r
+  margin-left: 0;\r
+}\r
+\r
+hr {\r
+  border: 1px solid silver;\r
+}\r
+\r
+p {\r
+  margin-top: 0.5em;\r
+  margin-bottom: 0.5em;\r
+}\r
+\r
+ul, ol, li > p {\r
+  margin-top: 0;\r
+}\r
+ul > li     { color: #aaa; }\r
+ul > li > * { color: black; }\r
+\r
+.monospaced, code, pre {\r
+  font-family: "Courier New", Courier, monospace;\r
+  font-size: inherit;\r
+  color: navy;\r
+  padding: 0;\r
+  margin: 0;\r
+}\r
+pre {\r
+  white-space: pre-wrap;\r
+}\r
+\r
+#author {\r
+  color: #527bbd;\r
+  font-weight: bold;\r
+  font-size: 1.1em;\r
+}\r
+#email {\r
+}\r
+#revnumber, #revdate, #revremark {\r
+}\r
+\r
+#footer {\r
+  font-size: small;\r
+  border-top: 2px solid silver;\r
+  padding-top: 0.5em;\r
+  margin-top: 4.0em;\r
+}\r
+#footer-text {\r
+  float: left;\r
+  padding-bottom: 0.5em;\r
+}\r
+#footer-badges {\r
+  float: right;\r
+  padding-bottom: 0.5em;\r
+}\r
+\r
+#preamble {\r
+  margin-top: 1.5em;\r
+  margin-bottom: 1.5em;\r
+}\r
+div.imageblock, div.exampleblock, div.verseblock,\r
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,\r
+div.admonitionblock {\r
+  margin-top: 1.0em;\r
+  margin-bottom: 1.5em;\r
+}\r
+div.admonitionblock {\r
+  margin-top: 2.0em;\r
+  margin-bottom: 2.0em;\r
+  margin-right: 10%;\r
+  color: #606060;\r
+}\r
+\r
+div.content { /* Block element content. */\r
+  padding: 0;\r
+}\r
+\r
+/* Block element titles. */\r
+div.title, caption.title {\r
+  color: #527bbd;\r
+  font-weight: bold;\r
+  text-align: left;\r
+  margin-top: 1.0em;\r
+  margin-bottom: 0.5em;\r
+}\r
+div.title + * {\r
+  margin-top: 0;\r
+}\r
+\r
+td div.title:first-child {\r
+  margin-top: 0.0em;\r
+}\r
+div.content div.title:first-child {\r
+  margin-top: 0.0em;\r
+}\r
+div.content + div.title {\r
+  margin-top: 0.0em;\r
+}\r
+\r
+div.sidebarblock > div.content {\r
+  background: #ffffee;\r
+  border: 1px solid #dddddd;\r
+  border-left: 4px solid #f0f0f0;\r
+  padding: 0.5em;\r
+}\r
+\r
+div.listingblock > div.content {\r
+  border: 1px solid #dddddd;\r
+  border-left: 5px solid #f0f0f0;\r
+  background: #f8f8f8;\r
+  padding: 0.5em;\r
+}\r
+\r
+div.quoteblock, div.verseblock {\r
+  padding-left: 1.0em;\r
+  margin-left: 1.0em;\r
+  margin-right: 10%;\r
+  border-left: 5px solid #f0f0f0;\r
+  color: #888;\r
+}\r
+\r
+div.quoteblock > div.attribution {\r
+  padding-top: 0.5em;\r
+  text-align: right;\r
+}\r
+\r
+div.verseblock > pre.content {\r
+  font-family: inherit;\r
+  font-size: inherit;\r
+}\r
+div.verseblock > div.attribution {\r
+  padding-top: 0.75em;\r
+  text-align: left;\r
+}\r
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */\r
+div.verseblock + div.attribution {\r
+  text-align: left;\r
+}\r
+\r
+div.admonitionblock .icon {\r
+  vertical-align: top;\r
+  font-size: 1.1em;\r
+  font-weight: bold;\r
+  text-decoration: underline;\r
+  color: #527bbd;\r
+  padding-right: 0.5em;\r
+}\r
+div.admonitionblock td.content {\r
+  padding-left: 0.5em;\r
+  border-left: 3px solid #dddddd;\r
+}\r
+\r
+div.exampleblock > div.content {\r
+  border-left: 3px solid #dddddd;\r
+  padding-left: 0.5em;\r
+}\r
+\r
+div.imageblock div.content { padding-left: 0; }\r
+span.image img { border-style: none; vertical-align: text-bottom; }\r
+a.image:visited { color: white; }\r
+\r
+dl {\r
+  margin-top: 0.8em;\r
+  margin-bottom: 0.8em;\r
+}\r
+dt {\r
+  margin-top: 0.5em;\r
+  margin-bottom: 0;\r
+  font-style: normal;\r
+  color: navy;\r
+}\r
+dd > *:first-child {\r
+  margin-top: 0.1em;\r
+}\r
+\r
+ul, ol {\r
+    list-style-position: outside;\r
+}\r
+ol.arabic {\r
+  list-style-type: decimal;\r
+}\r
+ol.loweralpha {\r
+  list-style-type: lower-alpha;\r
+}\r
+ol.upperalpha {\r
+  list-style-type: upper-alpha;\r
+}\r
+ol.lowerroman {\r
+  list-style-type: lower-roman;\r
+}\r
+ol.upperroman {\r
+  list-style-type: upper-roman;\r
+}\r
+\r
+div.compact ul, div.compact ol,\r
+div.compact p, div.compact p,\r
+div.compact div, div.compact div {\r
+  margin-top: 0.1em;\r
+  margin-bottom: 0.1em;\r
+}\r
+\r
+tfoot {\r
+  font-weight: bold;\r
+}\r
+td > div.verse {\r
+  white-space: pre;\r
+}\r
+\r
+div.hdlist {\r
+  margin-top: 0.8em;\r
+  margin-bottom: 0.8em;\r
+}\r
+div.hdlist tr {\r
+  padding-bottom: 15px;\r
+}\r
+dt.hdlist1.strong, td.hdlist1.strong {\r
+  font-weight: bold;\r
+}\r
+td.hdlist1 {\r
+  vertical-align: top;\r
+  font-style: normal;\r
+  padding-right: 0.8em;\r
+  color: navy;\r
+}\r
+td.hdlist2 {\r
+  vertical-align: top;\r
+}\r
+div.hdlist.compact tr {\r
+  margin: 0;\r
+  padding-bottom: 0;\r
+}\r
+\r
+.comment {\r
+  background: yellow;\r
+}\r
+\r
+.footnote, .footnoteref {\r
+  font-size: 0.8em;\r
+}\r
+\r
+span.footnote, span.footnoteref {\r
+  vertical-align: super;\r
+}\r
+\r
+#footnotes {\r
+  margin: 20px 0 20px 0;\r
+  padding: 7px 0 0 0;\r
+}\r
+\r
+#footnotes div.footnote {\r
+  margin: 0 0 5px 0;\r
+}\r
+\r
+#footnotes hr {\r
+  border: none;\r
+  border-top: 1px solid silver;\r
+  height: 1px;\r
+  text-align: left;\r
+  margin-left: 0;\r
+  width: 20%;\r
+  min-width: 100px;\r
+}\r
+\r
+div.colist td {\r
+  padding-right: 0.5em;\r
+  padding-bottom: 0.3em;\r
+  vertical-align: top;\r
+}\r
+div.colist td img {\r
+  margin-top: 0.3em;\r
+}\r
+\r
+@media print {\r
+  #footer-badges { display: none; }\r
+}\r
+\r
+#toc {\r
+  margin-bottom: 2.5em;\r
+}\r
+\r
+#toctitle {\r
+  color: #527bbd;\r
+  font-size: 1.1em;\r
+  font-weight: bold;\r
+  margin-top: 1.0em;\r
+  margin-bottom: 0.1em;\r
+}\r
+\r
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {\r
+  margin-top: 0;\r
+  margin-bottom: 0;\r
+}\r
+div.toclevel2 {\r
+  margin-left: 2em;\r
+  font-size: 0.9em;\r
+}\r
+div.toclevel3 {\r
+  margin-left: 4em;\r
+  font-size: 0.9em;\r
+}\r
+div.toclevel4 {\r
+  margin-left: 6em;\r
+  font-size: 0.9em;\r
+}\r
+\r
+span.aqua { color: aqua; }\r
+span.black { color: black; }\r
+span.blue { color: blue; }\r
+span.fuchsia { color: fuchsia; }\r
+span.gray { color: gray; }\r
+span.green { color: green; }\r
+span.lime { color: lime; }\r
+span.maroon { color: maroon; }\r
+span.navy { color: navy; }\r
+span.olive { color: olive; }\r
+span.purple { color: purple; }\r
+span.red { color: red; }\r
+span.silver { color: silver; }\r
+span.teal { color: teal; }\r
+span.white { color: white; }\r
+span.yellow { color: yellow; }\r
+\r
+span.aqua-background { background: aqua; }\r
+span.black-background { background: black; }\r
+span.blue-background { background: blue; }\r
+span.fuchsia-background { background: fuchsia; }\r
+span.gray-background { background: gray; }\r
+span.green-background { background: green; }\r
+span.lime-background { background: lime; }\r
+span.maroon-background { background: maroon; }\r
+span.navy-background { background: navy; }\r
+span.olive-background { background: olive; }\r
+span.purple-background { background: purple; }\r
+span.red-background { background: red; }\r
+span.silver-background { background: silver; }\r
+span.teal-background { background: teal; }\r
+span.white-background { background: white; }\r
+span.yellow-background { background: yellow; }\r
+\r
+span.big { font-size: 2em; }\r
+span.small { font-size: 0.6em; }\r
+\r
+span.underline { text-decoration: underline; }\r
+span.overline { text-decoration: overline; }\r
+span.line-through { text-decoration: line-through; }\r
+\r
+div.unbreakable { page-break-inside: avoid; }\r
+\r
+\r
+/*\r
+ * xhtml11 specific\r
+ *\r
+ * */\r
+\r
+div.tableblock {\r
+  margin-top: 1.0em;\r
+  margin-bottom: 1.5em;\r
+}\r
+div.tableblock > table {\r
+  border: 3px solid #527bbd;\r
+}\r
+thead, p.table.header {\r
+  font-weight: bold;\r
+  color: #527bbd;\r
+}\r
+p.table {\r
+  margin-top: 0;\r
+}\r
+/* Because the table frame attribute is overriden by CSS in most browsers. */\r
+div.tableblock > table[frame="void"] {\r
+  border-style: none;\r
+}\r
+div.tableblock > table[frame="hsides"] {\r
+  border-left-style: none;\r
+  border-right-style: none;\r
+}\r
+div.tableblock > table[frame="vsides"] {\r
+  border-top-style: none;\r
+  border-bottom-style: none;\r
+}\r
+\r
+\r
+/*\r
+ * html5 specific\r
+ *\r
+ * */\r
+\r
+table.tableblock {\r
+  margin-top: 1.0em;\r
+  margin-bottom: 1.5em;\r
+}\r
+thead, p.tableblock.header {\r
+  font-weight: bold;\r
+  color: #527bbd;\r
+}\r
+p.tableblock {\r
+  margin-top: 0;\r
+}\r
+table.tableblock {\r
+  border-width: 3px;\r
+  border-spacing: 0px;\r
+  border-style: solid;\r
+  border-color: #527bbd;\r
+  border-collapse: collapse;\r
+}\r
+th.tableblock, td.tableblock {\r
+  border-width: 1px;\r
+  padding: 4px;\r
+  border-style: solid;\r
+  border-color: #527bbd;\r
+}\r
+\r
+table.tableblock.frame-topbot {\r
+  border-left-style: hidden;\r
+  border-right-style: hidden;\r
+}\r
+table.tableblock.frame-sides {\r
+  border-top-style: hidden;\r
+  border-bottom-style: hidden;\r
+}\r
+table.tableblock.frame-none {\r
+  border-style: hidden;\r
+}\r
+\r
+th.tableblock.halign-left, td.tableblock.halign-left {\r
+  text-align: left;\r
+}\r
+th.tableblock.halign-center, td.tableblock.halign-center {\r
+  text-align: center;\r
+}\r
+th.tableblock.halign-right, td.tableblock.halign-right {\r
+  text-align: right;\r
+}\r
+\r
+th.tableblock.valign-top, td.tableblock.valign-top {\r
+  vertical-align: top;\r
+}\r
+th.tableblock.valign-middle, td.tableblock.valign-middle {\r
+  vertical-align: middle;\r
+}\r
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {\r
+  vertical-align: bottom;\r
+}\r
+\r
+\r
+/*\r
+ * manpage specific\r
+ *\r
+ * */\r
+\r
+body.manpage h1 {\r
+  padding-top: 0.5em;\r
+  padding-bottom: 0.5em;\r
+  border-top: 2px solid silver;\r
+  border-bottom: 2px solid silver;\r
+}\r
+body.manpage h2 {\r
+  border-style: none;\r
+}\r
+body.manpage div.sectionbody {\r
+  margin-left: 3em;\r
+}\r
+\r
+@media print {\r
+  body.manpage div#toc { display: none; }\r
+}\r
+\r
+\r
+</style>\r
+<script type="text/javascript">\r
+/*<![CDATA[*/\r
+var asciidoc = {  // Namespace.\r
+\r
+/////////////////////////////////////////////////////////////////////\r
+// Table Of Contents generator\r
+/////////////////////////////////////////////////////////////////////\r
+\r
+/* Author: Mihai Bazon, September 2002\r
+ * http://students.infoiasi.ro/~mishoo\r
+ *\r
+ * Table Of Content generator\r
+ * Version: 0.4\r
+ *\r
+ * Feel free to use this script under the terms of the GNU General Public\r
+ * License, as long as you do not remove or alter this notice.\r
+ */\r
+\r
+ /* modified by Troy D. Hanson, September 2006. License: GPL */\r
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */\r
+\r
+// toclevels = 1..4.\r
+toc: function (toclevels) {\r
+\r
+  function getText(el) {\r
+    var text = "";\r
+    for (var i = el.firstChild; i != null; i = i.nextSibling) {\r
+      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.\r
+        text += i.data;\r
+      else if (i.firstChild != null)\r
+        text += getText(i);\r
+    }\r
+    return text;\r
+  }\r
+\r
+  function TocEntry(el, text, toclevel) {\r
+    this.element = el;\r
+    this.text = text;\r
+    this.toclevel = toclevel;\r
+  }\r
+\r
+  function tocEntries(el, toclevels) {\r
+    var result = new Array;\r
+    var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');\r
+    // Function that scans the DOM tree for header elements (the DOM2\r
+    // nodeIterator API would be a better technique but not supported by all\r
+    // browsers).\r
+    var iterate = function (el) {\r
+      for (var i = el.firstChild; i != null; i = i.nextSibling) {\r
+        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {\r
+          var mo = re.exec(i.tagName);\r
+          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {\r
+            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);\r
+          }\r
+          iterate(i);\r
+        }\r
+      }\r
+    }\r
+    iterate(el);\r
+    return result;\r
+  }\r
+\r
+  var toc = document.getElementById("toc");\r
+  if (!toc) {\r
+    return;\r
+  }\r
+\r
+  // Delete existing TOC entries in case we're reloading the TOC.\r
+  var tocEntriesToRemove = [];\r
+  var i;\r
+  for (i = 0; i < toc.childNodes.length; i++) {\r
+    var entry = toc.childNodes[i];\r
+    if (entry.nodeName.toLowerCase() == 'div'\r
+     && entry.getAttribute("class")\r
+     && entry.getAttribute("class").match(/^toclevel/))\r
+      tocEntriesToRemove.push(entry);\r
+  }\r
+  for (i = 0; i < tocEntriesToRemove.length; i++) {\r
+    toc.removeChild(tocEntriesToRemove[i]);\r
+  }\r
+\r
+  // Rebuild TOC entries.\r
+  var entries = tocEntries(document.getElementById("content"), toclevels);\r
+  for (var i = 0; i < entries.length; ++i) {\r
+    var entry = entries[i];\r
+    if (entry.element.id == "")\r
+      entry.element.id = "_toc_" + i;\r
+    var a = document.createElement("a");\r
+    a.href = "#" + entry.element.id;\r
+    a.appendChild(document.createTextNode(entry.text));\r
+    var div = document.createElement("div");\r
+    div.appendChild(a);\r
+    div.className = "toclevel" + entry.toclevel;\r
+    toc.appendChild(div);\r
+  }\r
+  if (entries.length == 0)\r
+    toc.parentNode.removeChild(toc);\r
+},\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////\r
+// Footnotes generator\r
+/////////////////////////////////////////////////////////////////////\r
+\r
+/* Based on footnote generation code from:\r
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html\r
+ */\r
+\r
+footnotes: function () {\r
+  // Delete existing footnote entries in case we're reloading the footnodes.\r
+  var i;\r
+  var noteholder = document.getElementById("footnotes");\r
+  if (!noteholder) {\r
+    return;\r
+  }\r
+  var entriesToRemove = [];\r
+  for (i = 0; i < noteholder.childNodes.length; i++) {\r
+    var entry = noteholder.childNodes[i];\r
+    if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")\r
+      entriesToRemove.push(entry);\r
+  }\r
+  for (i = 0; i < entriesToRemove.length; i++) {\r
+    noteholder.removeChild(entriesToRemove[i]);\r
+  }\r
+\r
+  // Rebuild footnote entries.\r
+  var cont = document.getElementById("content");\r
+  var spans = cont.getElementsByTagName("span");\r
+  var refs = {};\r
+  var n = 0;\r
+  for (i=0; i<spans.length; i++) {\r
+    if (spans[i].className == "footnote") {\r
+      n++;\r
+      var note = spans[i].getAttribute("data-note");\r
+      if (!note) {\r
+        // Use [\s\S] in place of . so multi-line matches work.\r
+        // Because JavaScript has no s (dotall) regex flag.\r
+        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];\r
+        spans[i].innerHTML =\r
+          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +\r
+          "' title='View footnote' class='footnote'>" + n + "</a>]";\r
+        spans[i].setAttribute("data-note", note);\r
+      }\r
+      noteholder.innerHTML +=\r
+        "<div class='footnote' id='_footnote_" + n + "'>" +\r
+        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +\r
+        n + "</a>. " + note + "</div>";\r
+      var id =spans[i].getAttribute("id");\r
+      if (id != null) refs["#"+id] = n;\r
+    }\r
+  }\r
+  if (n == 0)\r
+    noteholder.parentNode.removeChild(noteholder);\r
+  else {\r
+    // Process footnoterefs.\r
+    for (i=0; i<spans.length; i++) {\r
+      if (spans[i].className == "footnoteref") {\r
+        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");\r
+        href = href.match(/#.*/)[0];  // Because IE return full URL.\r
+        n = refs[href];\r
+        spans[i].innerHTML =\r
+          "[<a href='#_footnote_" + n +\r
+          "' title='View footnote' class='footnote'>" + n + "</a>]";\r
+      }\r
+    }\r
+  }\r
+},\r
+\r
+install: function(toclevels) {\r
+  var timerId;\r
+\r
+  function reinstall() {\r
+    asciidoc.footnotes();\r
+    if (toclevels) {\r
+      asciidoc.toc(toclevels);\r
+    }\r
+  }\r
+\r
+  function reinstallAndRemoveTimer() {\r
+    clearInterval(timerId);\r
+    reinstall();\r
+  }\r
+\r
+  timerId = setInterval(reinstall, 500);\r
+  if (document.addEventListener)\r
+    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);\r
+  else\r
+    window.onload = reinstallAndRemoveTimer;\r
+}\r
+\r
+}\r
+asciidoc.install();\r
+/*]]>*/\r
+</script>\r
+</head>\r
+<body class="manpage">\r
+<div id="header">\r
+<h1>\r
+nvme-copy(1) Manual Page\r
+</h1>\r
+<h2>NAME</h2>\r
+<div class="sectionbody">\r
+<p>nvme-copy -\r
+   Send an NVMe Simple Copy command, provide results\r
+</p>\r
+</div>\r
+</div>\r
+<div id="content">\r
+<div class="sect1">\r
+<h2 id="_synopsis">SYNOPSIS</h2>\r
+<div class="sectionbody">\r
+<div class="verseblock">\r
+<pre class="content"><em>nvme-copy</em> &lt;device&gt; [--sdlba=&lt;sdlba&gt; | -d &lt;sdlba&gt;]\r
+                        [--blocks=&lt;nlb-list,&gt; | -b &lt;nlb-list,&gt;]\r
+                        [--slbs=&lt;slbas,&gt; | -s &lt;slbas,&gt;]\r
+                        [--limited-retry | -l]\r
+                        [--force-unit-access | -f]\r
+                        [--prinfow=&lt;prinfow&gt; | -p &lt;prinfow&gt;]\r
+                        [--prinfor=&lt;prinfor&gt; | -P &lt;prinfor&gt;]\r
+                        [--ref-tag=&lt;reftag&gt; | -r &lt;reftag&gt;]\r
+                        [--expected-ref-tags=&lt;reftag,&gt; | -R &lt;reftag,&gt;]\r
+                        [--app-tag=&lt;apptag&gt; | -a &lt;apptag&gt;]\r
+                        [--expected-app-tags=&lt;apptag,&gt; | -A &lt;apptag,&gt;]\r
+                        [--app-mask=&lt;appmask&gt; | -m &lt;appmask&gt;]\r
+                        [--expected-app-masks=&lt;appmask,&gt; | -M &lt;appmask,&gt;]\r
+                        [--dir-type=&lt;type&gt; | -T &lt;type&gt;]\r
+                        [--dir-spec=&lt;spec&gt; | -S &lt;spec&gt;]\r
+                        [--format=&lt;entry-format&gt; | -F &lt;entry-format&gt;]</pre>\r
+<div class="attribution">\r
+</div></div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
+<h2 id="_description">DESCRIPTION</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>The Copy command is used by the host to copy data from one or more source\r
+logical block ranges to a single consecutive destination logical block range.</p></div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
+<h2 id="_options">OPTIONS</h2>\r
+<div class="sectionbody">\r
+<div class="dlist"><dl>\r
+<dt class="hdlist1">\r
+--sdlba=&lt;sdlba&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-d &lt;sdlba&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        64-bit addr of first destination logical block\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--blocks=&lt;nlb-list,&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-b &lt;nlb-list,&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        Comma separated list of the number of blocks in each range\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--slbs=&lt;slbas,&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-s &lt;slbas,&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        Comma separated list of the starting blocks in each range\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--limited-retry\r
+</dt>\r
+<dt class="hdlist1">\r
+-l\r
+</dt>\r
+<dd>\r
+<p>\r
+        Sets the limited retry flag.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--force-unit-access\r
+</dt>\r
+<dt class="hdlist1">\r
+-f\r
+</dt>\r
+<dd>\r
+<p>\r
+        Set the force-unit access flag.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--prinfow=&lt;prinfow&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-p &lt;prinfow&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        Protection Information field write definition.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--prinfor=&lt;prinfor&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-P &lt;prinfor&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        Protection Information field read definition.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--ref-tag=&lt;reftag&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-r &lt;reftag&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        initial lba reference tag.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--expected-ref-tags=&lt;reftag,&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-R &lt;reftag,&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        expected lba reference tags (comma-separated list).\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--app-tag=&lt;apptag&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-a &lt;apptag&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        lba app tag\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--expected-app-tags=&lt;apptag,&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-A &lt;apptag,&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        expected lba app tags (comma-separated list)\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--app-mask=&lt;appmask&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-m &lt;appmask&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        lba tag mask\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--expected-app-masks=&lt;appmask,&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-M &lt;appmask,&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        expected lba tag masks (comma-separated list)\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--dir-type=&lt;type&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-T &lt;type&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        Optional directive type. The nvme-cli only enforces the value\r
+        be in the defined range for the directive type, though the NVMe\r
+        specifcation (1.3a) defines only one directive, 01h, for write\r
+        stream idenfiers.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--dir-spec=&lt;spec&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-S &lt;spec&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        Optional field for directive specifics. When used with\r
+        write streams, this value is defined to be the write stream\r
+        identifier. The nvme-cli will not validate the stream requested\r
+        is within the controller&#8217;s capabilities.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+--format=&lt;entry-format&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+-F &lt;entry-format&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+        source range entry format\r
+</p>\r
+</dd>\r
+</dl></div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
+<h2 id="_examples">EXAMPLES</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>No examples yet.</p></div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
+<h2 id="_nvme">NVME</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>\r
+</div>\r
+</div>\r
+</div>\r
+<div id="footnotes"><hr /></div>\r
+<div id="footer">\r
+<div id="footer-text">\r
+Last updated\r
+ 2020-05-06 10:35:20 CEST\r
+</div>\r
+</div>\r
+</body>\r
+</html>\r
diff --git a/Documentation/nvme-copy.txt b/Documentation/nvme-copy.txt
new file mode 100644 (file)
index 0000000..d6452ec
--- /dev/null
@@ -0,0 +1,111 @@
+nvme-copy(1)
+============
+
+NAME
+----
+nvme-copy - Send an NVMe Simple Copy command, provide results
+
+SYNOPSIS
+--------
+[verse]
+'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
index 7a6e5ddc0ec45f3b92ff4916b54e0152b4eb6171..7599f04228c58d87835a122f5a0395bac37e686e 100644 (file)
@@ -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
index 5c5226e6c471384f1fdfe9104c5afe5cc30b105f..d417d06f314b1e0a95e6a28c2defb6f07b4959a9 100644 (file)
@@ -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"
                        ;;
index 86782ecefeea5733fafb9204619f76dbc29654bd..a7ab85d03067b312144d5a5fbcbd94898a5f9f69 100644 (file)
@@ -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:
index 6804ffe615f71e23c2a9606a741449c2819666dc..87338b5e5d5b271a0c956671299834d3943ae55f 100644 (file)
@@ -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)
index 4da1d11a68d25792173532cc8ab68cc5c1e7d8c1..0c516b262f28a66aef602da69a8c707dbd17a490 100644 (file)
@@ -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)
 {
index 6be125464240ee1a6fa8305e0875df5a0d60b220..89cb4792f2701d947f03d4f7c24df7fdf89ce818 100644 (file)
@@ -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,
index 22ab8d75211f916185b67dcf28546797d4f12633..f037a28c1c6b91cb0497a58f6be3ed1be095cffd 100644 (file)
@@ -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:
index 1b060dc23b0a61559bf22cd0591ecfcccffd9c82..a78c1fd027976af1305bd6a821ea0eed796540b4 100644 (file)
@@ -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 e08351c027f2f631ebf183c7e7811542d8aff132..f1ea6b7d0ba3ad4e47f3ddd1205b1ab21ab22fde 100644 (file)
--- 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 "\