]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
nvme: add support for predictable latency per NVM set log page
authorGollu Appalanaidu <anaidu.gollu@samsung.com>
Wed, 13 Jan 2021 16:27:13 +0000 (21:57 +0530)
committerKeith Busch <kbusch@kernel.org>
Wed, 13 Jan 2021 16:41:36 +0000 (09:41 -0700)
This is to add support for LID = 0x0A, Predictable Latency per
NVM Set, used to determine the current window for the specified
NVM Set when Predictable Latency Mode is enabled and any events
that have occurred for the specified NVM Set. For More details
see NVM Express 1.4 Spec. Section 5.14.1.10 ("Predictable Latency
Per NVM Set (Log Identifier 0Ah)")

Signed-off-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
Co-Authored-By: Karthik Balan <karthik.b82@samsung.com>
Reviewed-by: Steven Seungcheol Lee <sc108.lee@samsung.com>
12 files changed:
Documentation/nvme-predictable-lat-log.1 [new file with mode: 0644]
Documentation/nvme-predictable-lat-log.html [new file with mode: 0644]
Documentation/nvme-predictable-lat-log.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-print.h
nvme.c

diff --git a/Documentation/nvme-predictable-lat-log.1 b/Documentation/nvme-predictable-lat-log.1
new file mode 100644 (file)
index 0000000..41dd16c
--- /dev/null
@@ -0,0 +1,112 @@
+'\" t
+.\"     Title: nvme-predictable-lat-log
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\"      Date: 01/13/2021
+.\"    Manual: NVMe Manual
+.\"    Source: NVMe
+.\"  Language: English
+.\"
+.TH "NVME\-PREDICTABLE\-L" "1" "01/13/2021" "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-predictable-lat-log \- Send Predectible latency per NVM set log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme predictable\-lat\-log\fR <device> [\-\-nvmset\-id=<nvmset_id> | \-i <nvmset_id>]
+                        [\-\-raw\-binary | \-b]
+                        [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Predectible latency per NVM set log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned Predectible latency per NVM set log structure may be returned in one ofseveral ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-i <nvmset_id>, \-\-nvmset\-id=<nvmset_id>
+.RS 4
+Retrieve the Predectible latency per NVM set log for the given nvmset id\&. This argument is mandatory and its success may depend on the device\(cqs statistics to provide this log For More details see NVM Express 1\&.4 Spec\&. Section 5\&.14\&.1\&.10\&. The default nvmset id to use is 1 for the device\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw Predectible latency per NVM set log buffer to stdout\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Predectible latency per NVM set log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme predictable\-lat\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the raw Predectible latency per NVM set log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme predictable\-lat\-log /dev/nvme0 \-\-raw\-binary > nvmset_log\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-predictable-lat-log.html b/Documentation/nvme-predictable-lat-log.html
new file mode 100644 (file)
index 0000000..42dfda8
--- /dev/null
@@ -0,0 +1,857 @@
+<?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-predictable-lat-log(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-predictable-lat-log(1) Manual Page\r
+</h1>\r
+<h2>NAME</h2>\r
+<div class="sectionbody">\r
+<p>nvme-predictable-lat-log -\r
+   Send Predectible latency per NVM set log page request, returns result and log\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 predictable-lat-log</em> &lt;device&gt; [--nvmset-id=&lt;nvmset_id&gt; | -i &lt;nvmset_id&gt;]\r
+                        [--raw-binary | -b]\r
+                        [--output-format=&lt;fmt&gt; | -o &lt;fmt&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>Retrieves the NVMe Predectible latency per NVM set log page from an NVMe device\r
+and provides the returned structure.</p></div>\r
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character\r
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>\r
+<div class="paragraph"><p>On success, the returned Predectible latency per NVM set log structure\r
+may be returned in one ofseveral ways depending on the option flags; the\r
+structure may parsed by the program and printed in a readable format or\r
+the raw buffer may be printed to stdout for another program to parse.</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
+-i &lt;nvmset_id&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+--nvmset-id=&lt;nvmset_id&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+    Retrieve the Predectible latency per NVM set log for the given nvmset id.\r
+    This argument is mandatory and its success may depend on the device&#8217;s\r
+    statistics to provide this log For More details see NVM Express 1.4 Spec.\r
+    Section 5.14.1.10. The default nvmset id to use is 1 for the device.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+-b\r
+</dt>\r
+<dt class="hdlist1">\r
+--raw-binary\r
+</dt>\r
+<dd>\r
+<p>\r
+        Print the raw Predectible latency per NVM set log buffer to stdout.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
+-o &lt;format&gt;\r
+</dt>\r
+<dt class="hdlist1">\r
+--output-format=&lt;format&gt;\r
+</dt>\r
+<dd>\r
+<p>\r
+              Set the reporting format to <em>normal</em>, <em>json</em>, or\r
+              <em>binary</em>. Only one output format can be used at a time.\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="ulist"><ul>\r
+<li>\r
+<p>\r
+Print the Predectible latency per NVM set log page in a human readable format:\r
+</p>\r
+<div class="listingblock">\r
+<div class="content">\r
+<pre><code># nvme predictable-lat-log /dev/nvme0</code></pre>\r
+</div></div>\r
+</li>\r
+<li>\r
+<p>\r
+Print the raw Predectible latency per NVM set log to a file:\r
+</p>\r
+<div class="listingblock">\r
+<div class="content">\r
+<pre><code># nvme predictable-lat-log /dev/nvme0 --raw-binary &gt; nvmset_log.raw</code></pre>\r
+</div></div>\r
+<div class="paragraph"><p>It is probably a bad idea to not redirect stdout when using this mode.</p></div>\r
+</li>\r
+</ul></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
+ 2021-01-13 21:53:55 IST\r
+</div>\r
+</div>\r
+</body>\r
+</html>\r
diff --git a/Documentation/nvme-predictable-lat-log.txt b/Documentation/nvme-predictable-lat-log.txt
new file mode 100644 (file)
index 0000000..b4d7335
--- /dev/null
@@ -0,0 +1,66 @@
+nvme-predictable-lat-log(1)
+===========================
+
+NAME
+----
+nvme-predictable-lat-log - Send Predectible latency per NVM set log page request,
+returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme predictable-lat-log' <device> [--nvmset-id=<nvmset_id> | -i <nvmset_id>]
+                       [--raw-binary | -b]
+                       [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Predectible latency per NVM set log page from an NVMe device
+and provides the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned Predectible latency per NVM set log structure
+may be returned in one ofseveral ways depending on the option flags; the
+structure may parsed by the program and printed in a readable format or
+the raw buffer may be printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-i <nvmset_id>::
+--nvmset-id=<nvmset_id>::
+    Retrieve the Predectible latency per NVM set log for the given nvmset id.
+    This argument is mandatory and its success may depend on the device's
+    statistics to provide this log For More details see NVM Express 1.4 Spec.
+    Section 5.14.1.10. The default nvmset id to use is 1 for the device.
+
+-b::
+--raw-binary::
+       Print the raw Predectible latency per NVM set log buffer to stdout.
+
+-o <format>::
+--output-format=<format>::
+              Set the reporting format to 'normal', 'json', or
+              'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the Predectible latency per NVM set log page in a human readable format:
++
+------------
+# nvme predictable-lat-log /dev/nvme0
+------------
++
+
+* Print the raw Predectible latency per NVM set log to a file:
++
+------------
+# nvme predictable-lat-log /dev/nvme0 --raw-binary > nvmset_log.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+NVME
+----
+Part of the nvme-user suite
index 94ce3fbe7b2637bf3d6e3331ca17928f36611640..afa5bab8ad2ef33c867b6467d1e56e2039654199 100644 (file)
@@ -18,6 +18,7 @@ _nvme () {
        'list-ctrl:identify all controller(s) attached'
        'get-ns-id:get namespace id of opened block device'
        'get-log:retrieve any log in raw format'
+       'predictable-lat-log:retrieve predictable latency per nvmset log'
        'pred-lat-event-agg-log:retrieve predictable latency event aggregate log'
        'persistent-event-log:retrieve presistent event log'
        'fw-log:retrieve fw log'
@@ -226,6 +227,18 @@ _nvme () {
                        _arguments '*:: :->subcmds'
                        _describe -t commands "nvme pred-lat-event-agg-log options" _predlateventagglog
                        ;;
+               (predictablelatlog)
+                       local _predictablelatlog
+                       _predictablelatlog=(
+                       /dev/nvme':supply a device to use (required)'
+                       --nvmset-id=': NVM Set Identifier on which log page retrieve info'
+                       -i':alias to --nvmset-id'
+                       --raw-binary':dump infos in binary format'
+                       -b':alias of --raw-binary'
+                       )
+                       _arguments '*:: :->subcmds'
+                       _describe -t commands "nvme predictable-lat-log options" _predictablelatlog
+                       ;;
                (fw-log)
                        local _fwlog
                        _fwlog=(
index ba87f4b776a56062887b59d075ddd37c9bff3977..d669e9b289af334771a3e5b67d94524acc6975ca 100644 (file)
@@ -5,7 +5,7 @@
 _cmds="list id-ctrl id-ns list-ns id-iocs create-ns delete-ns \
        attach-ns detach-ns list-ctrl get-ns-id get-log persistent-event-log \
        pred-lat-event-agg-log fw-log smart-log smart-log-add error-log \
-       get-feature set-feature format fw-activate \
+       predictable-lat-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 dsm flush compare read write write-zeroes \
@@ -79,6 +79,10 @@ nvme_list_opts () {
                opts+=" --log-entries= -e  --rae -r \
                        --raw-binary -b --output-format= -o"
                        ;;
+               "predictable-lat-log")
+               opts+=" --nvmset-id= -i --raw-binary -b \
+                       --output-format= -o"
+                       ;;
                "fw-log")
                opts+=" --raw-binary -b --output-format= -o"
                        ;;
index deb1f392b607e765f184c4dbc8e7c0c7bcfabb2f..025f6380c1399073c92be222560e7d9a2247977c 100644 (file)
@@ -885,6 +885,23 @@ struct nvme_predlat_event_agg_log_page {
        __le16  entries[];
 };
 
+struct nvme_predlat_per_nvmset_log_page {
+       __u8    status;
+       __u8    rsvd1;
+       __le16  event_type;
+       __u8    rsvd4[28];
+       __le64  dtwin_rtyp;
+       __le64  dtwin_wtyp;
+       __le64  dtwin_timemax;
+       __le64  ndwin_timemin_high;
+       __le64  ndwin_timemin_low;
+       __u8    rsvd72[56];
+       __le64  dtwin_restimate;
+       __le64  dtwin_westimate;
+       __le64  dtwin_testimate;
+       __u8    rsvd152[360];
+};
+
 enum {
        NVME_SMART_CRIT_SPARE           = 1 << 0,
        NVME_SMART_CRIT_TEMPERATURE     = 1 << 1,
@@ -1183,6 +1200,7 @@ enum {
        NVME_LOG_TELEMETRY_HOST = 0x07,
        NVME_LOG_TELEMETRY_CTRL = 0x08,
        NVME_LOG_ENDURANCE_GROUP = 0x09,
+       NVME_LOG_PRELAT_PER_NVMSET      = 0x0a,
        NVME_LOG_ANA            = 0x0c,
        NVME_LOG_PRELAT_EVENT_AGG       = 0x0b,
        NVME_LOG_PERSISTENT_EVENT   = 0x0d,
index 15545cf0579d3c8303d89a81c7cce06479869b84..59896dc0b9ea469d88c6192a057a12f7d8704639 100644 (file)
@@ -33,6 +33,7 @@ COMMAND_LIST(
        ENTRY("error-log", "Retrieve Error Log, show it", get_error_log)
        ENTRY("effects-log", "Retrieve Command Effects Log, show it", get_effects_log)
        ENTRY("endurance-log", "Retrieve Endurance Group Log, show it", get_endurance_log)
+       ENTRY("predictable-lat-log", "Retrieve Predictable Latency per Nvmset Log, show it", get_pred_lat_per_nvmset_log)
        ENTRY("pred-lat-event-agg-log", "Retrieve Predictable Latency Event Aggregate Log, show it", get_pred_lat_event_agg_log)
        ENTRY("persistent-event-log", "Retrieve Presistent Event Log, show it", get_persistent_event_log)
        ENTRY("get-feature", "Get feature and show the resulting value", get_feature)
index 24ba95b527a20db3d9f8069f96e4ba1ece3f7828..7e0ec155a6d8aca50cb4d17544c78ae86ffce51c 100644 (file)
@@ -614,6 +614,15 @@ int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log)
                        NVME_NO_LOG_LSP, sizeof(*sanitize_log), sanitize_log);
 }
 
+int nvme_predictable_latency_per_nvmset_log(int fd,
+               __u16 nvmset_id,
+               struct nvme_predlat_per_nvmset_log_page *plpns_log)
+{
+       return nvme_get_log13(fd, NVME_NSID_ALL,
+                       NVME_LOG_PRELAT_PER_NVMSET, 0, 0, nvmset_id,
+                       false, sizeof(*plpns_log), plpns_log);
+}
+
 int nvme_predictable_latency_event_agg_log(int fd,
                void *pea_log, bool rae, __u32 size)
 {
index e7bf14fc5543f796c619da8edd6f5c4754e72174..24eb2eb71b5fe4b2b1c852793ed6b8b9379d8d38 100644 (file)
@@ -115,6 +115,8 @@ int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo);
 int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log);
 int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size);
 int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log);
+int nvme_predictable_latency_per_nvmset_log(int fd,
+               __u16 nvmset_id, struct nvme_predlat_per_nvmset_log_page *plpns_log);
 int nvme_predictable_latency_event_agg_log(int fd, void *pea_log,
                bool rae, __u32 size);
 int nvme_persistent_event_log(int fd, __u8 action, __u32 size,
index df728e2265903b465ce866cb3707e3349ca31f26..e7eac50e1ed0cac79d6e68f920ed1d51c480615e 100644 (file)
@@ -866,6 +866,78 @@ static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log,
        json_free_object(root);
 }
 
+void json_predictable_latency_per_nvmset(
+       struct nvme_predlat_per_nvmset_log_page *plpns_log,
+       __u16 nvmset_id)
+{
+       struct json_object *root;
+
+       root = json_create_object();
+       json_object_add_value_uint(root, "nvmset_id",
+               le16_to_cpu(nvmset_id));
+       json_object_add_value_uint(root, "status",
+               plpns_log->status);
+       json_object_add_value_uint(root, "event_type",
+               le16_to_cpu(plpns_log->event_type));
+       json_object_add_value_uint(root, "dtwin_reads_typical",
+               le64_to_cpu(plpns_log->dtwin_rtyp));
+       json_object_add_value_uint(root, "dtwin_writes_typical",
+               le64_to_cpu(plpns_log->dtwin_wtyp));
+       json_object_add_value_uint(root, "dtwin_time_maximum",
+               le64_to_cpu(plpns_log->dtwin_timemax));
+       json_object_add_value_uint(root, "ndwin_time_minimum_high",
+               le64_to_cpu(plpns_log->ndwin_timemin_high));
+       json_object_add_value_uint(root, "ndwin_time_minimum_low",
+               le64_to_cpu(plpns_log->ndwin_timemin_low));
+       json_object_add_value_uint(root, "dtwin_reads_estimate",
+               le64_to_cpu(plpns_log->dtwin_restimate));
+       json_object_add_value_uint(root, "dtwin_writes_estimate",
+               le64_to_cpu(plpns_log->dtwin_westimate));
+       json_object_add_value_uint(root, "dtwin_time_estimate",
+               le64_to_cpu(plpns_log->dtwin_testimate));
+
+       json_print_object(root, NULL);
+       printf("\n");
+       json_free_object(root);
+}
+
+void nvme_show_predictable_latency_per_nvmset(
+       struct nvme_predlat_per_nvmset_log_page *plpns_log,
+       __u16 nvmset_id, const char *devname,
+       enum nvme_print_flags flags)
+{
+       if (flags & BINARY)
+               return d_raw((unsigned char *)plpns_log,
+                       sizeof(*plpns_log));
+       if (flags & JSON)
+               return json_predictable_latency_per_nvmset(plpns_log,
+                       nvmset_id);
+
+       printf("Predictable Latency Per NVM Set Log for device: %s\n",
+               devname);
+       printf("Predictable Latency Per NVM Set Log for NVM Set ID: %u\n",
+               le16_to_cpu(nvmset_id));
+       printf("Status: %u\n", plpns_log->status);
+       printf("Event Type: %u\n",
+               le16_to_cpu(plpns_log->event_type));
+       printf("DTWIN Reads Typical: %"PRIu64"\n",
+               le64_to_cpu(plpns_log->dtwin_rtyp));
+       printf("DTWIN Writes Typical: %"PRIu64"\n",
+               le64_to_cpu(plpns_log->dtwin_wtyp));
+       printf("DTWIN Time Maximum: %"PRIu64"\n",
+               le64_to_cpu(plpns_log->dtwin_timemax));
+       printf("NDWIN Time Minimum High: %"PRIu64" \n",
+               le64_to_cpu(plpns_log->ndwin_timemin_high));
+       printf("NDWIN Time Minimum Low: %"PRIu64"\n",
+               le64_to_cpu(plpns_log->ndwin_timemin_low));
+       printf("DTWIN Reads Estimate: %"PRIu64"\n",
+               le64_to_cpu(plpns_log->dtwin_restimate));
+       printf("DTWIN Writes Estimate: %"PRIu64"\n",
+               le64_to_cpu(plpns_log->dtwin_westimate));
+       printf("DTWIN Time Estimate: %"PRIu64"\n\n\n",
+               le64_to_cpu(plpns_log->dtwin_testimate));
+}
+
 void json_predictable_latency_event_agg_log(
        struct nvme_predlat_event_agg_log_page *pea_log,
        __u64 log_entries)
index ee1223afa40735726b672072aed083f6dac9a99e..368434c52b3ce26d29ebc85d2dd3fdf0d0b2cdc1 100644 (file)
@@ -37,6 +37,12 @@ void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log,
        __u16 group_id, const char *devname, enum nvme_print_flags flags);
 void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize,
        const char *devname, enum nvme_print_flags flags);
+void json_predictable_latency_per_nvmset(
+       struct nvme_predlat_per_nvmset_log_page *plpns_log,
+       __u16 nvmset_id);
+void nvme_show_predictable_latency_per_nvmset(
+       struct nvme_predlat_per_nvmset_log_page *plpns_log,
+       __u16 nvmset_id, const char *devname, enum nvme_print_flags flags);
 void json_predictable_latency_event_agg_log(
        struct nvme_predlat_event_agg_log_page *pea_log,
        __u64 log_entries);
diff --git a/nvme.c b/nvme.c
index 59555f1631c0f375ce66f85c4dd127c23014ea4a..72064e130e6ec6bcf24b295d8fa56b9acfa500b8 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -747,6 +747,62 @@ ret:
        return nvme_status_to_errno(err, false);
 }
 
+static int get_pred_lat_per_nvmset_log(int argc, char **argv,
+       struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Retrieve Predictable latency per nvm set log "\
+                       "page and prints it for the given device in either decoded " \
+                       "format(default),json or binary.";
+       const char *nvmset_id = "NVM Set Identifier";
+       const char *raw = "use binary output";
+       struct nvme_predlat_per_nvmset_log_page plpns_log;
+       enum nvme_print_flags flags;
+       int err, fd;
+
+       struct config {
+               __u16 nvmset_id;
+               char *output_format;
+               int raw_binary;
+       };
+
+       struct config cfg = {
+               .nvmset_id = 1,
+               .output_format = "normal",
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("nvmset-id",    'i', &cfg.nvmset_id,     nvmset_id),
+               OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+               OPT_FLAG("raw-binary",   'b', &cfg.raw_binary,    raw),
+               OPT_END()
+       };
+
+       err = fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0)
+               goto ret;
+
+       err = flags = validate_output_format(cfg.output_format);
+       if (flags < 0)
+               goto close_fd;
+       if (cfg.raw_binary)
+               flags = BINARY;
+
+       err = nvme_predictable_latency_per_nvmset_log(fd,
+               cfg.nvmset_id, &plpns_log);
+       if (!err)
+               nvme_show_predictable_latency_per_nvmset(&plpns_log,
+                       cfg.nvmset_id, devicename, flags);
+       else if (err > 0)
+               nvme_show_status(err);
+       else
+               perror("predictable latency per nvm set");
+
+close_fd:
+       close(fd);
+ret:
+       return nvme_status_to_errno(err, false);
+}
+
 static int get_pred_lat_event_agg_log(int argc, char **argv,
                struct command *cmd, struct plugin *plugin)
 {