Index: head/sbin/nvmecontrol/Makefile =================================================================== --- head/sbin/nvmecontrol/Makefile (revision 350598) +++ head/sbin/nvmecontrol/Makefile (revision 350599) @@ -1,18 +1,18 @@ # $FreeBSD$ PACKAGE=runtime PROG= nvmecontrol SRCS= comnd.c nvmecontrol.c SRCS+= devlist.c firmware.c format.c identify.c logpage.c ns.c nsid.c -SRCS+= perftest.c power.c reset.c sanitize.c +SRCS+= perftest.c power.c reset.c resv.c sanitize.c #SRCS+= passthru.c SRCS+= identify_ext.c nvme_util.c nc_util.c MAN= nvmecontrol.8 LDFLAGS+= -rdynamic LIBADD+= util SUBDIR= modules .PATH: ${SRCTOP}/sys/dev/nvme .include .include Index: head/sbin/nvmecontrol/nvmecontrol.8 =================================================================== --- head/sbin/nvmecontrol/nvmecontrol.8 (revision 350598) +++ head/sbin/nvmecontrol/nvmecontrol.8 (revision 350599) @@ -1,411 +1,528 @@ .\" .\" Copyright (c) 2018-2019 Alexander Motin .\" Copyright (c) 2012 Intel Corporation .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions, and the following disclaimer, .\" without modification. .\" 2. Redistributions in binary form must reproduce at minimum a disclaimer .\" substantially similar to the "NO WARRANTY" disclaimer below .\" ("Disclaimer") and any redistribution must be conditioned upon .\" including a substantially similar Disclaimer requirement for further .\" binary redistribution. .\" .\" NO WARRANTY .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT .\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGES. .\" .\" nvmecontrol man page. .\" .\" Author: Jim Harris .\" .\" $FreeBSD$ .\" -.Dd August 3, 2019 +.Dd August 5, 2019 .Dt NVMECONTROL 8 .Os .Sh NAME .Nm nvmecontrol .Nd NVM Express control utility .Sh SYNOPSIS .Nm .Ic devlist .Nm .Ic identify .Op Fl v .Op Fl x .Aq device id .Aq namespace id .Nm .Ic perftest .Aq Fl n Ar num_threads .Aq Fl o Ar read|write .Op Fl p .Aq Fl s Ar size_in_bytes .Aq Fl t Ar time_in_sec .Aq namespace id .Nm .Ic reset .Aq controller id .Nm .Ic logpage .Aq Fl p Ar page_id .Op Fl x .Op Fl v Ar vendor-string .Op Fl b .Op Fl f Ar LSP .Op Fl i Ar LSI .Op Fl r .Aq device id .Aq namespace id .Nm .Ic ns active .Aq device id .Nm .Ic ns allocated .Aq device id .Nm .Ic ns attach .Aq Fl n Ar nsid .Aq Fl c Ar cntid .Aq device id .Nm .Ic ns attached .Aq Fl n Ar nsid .Aq device id .Nm .Ic ns controllers .Aq device id .Nm .Ic ns create .Aq Fl s Ar nsze .Op Fl c Ar ncap .Op Fl f Ar lbaf .Op Fl m Ar mset .Op Fl n Ar nmic .Op Fl p Ar pi .Op Fl l Ar pil .Op Fl L Ar flbas .Op Fl d Ar dps .Aq device id .Nm .Ic ns delete .Aq Fl n Ar nsid .Aq device id .Nm .Ic ns detach .Aq Fl n Ar nsid .Aq Fl c Ar cntid .Aq device id .Nm .Ic ns identify .Op Fl v .Op Fl x .Aq Fl n Ar nsid .Aq device id .Nm .Ic nsid .Aq device id .Aq namespace id .Nm +.Ic resv acquire +.Aq Fl c Ar crkey +.Op Fl p Ar prkey +.Aq Fl t Ar rtype +.Aq Fl a Ar racqa +.Aq namespace id +.Nm +.Ic resv register +.Op Fl c Ar crkey +.Aq Fl k Ar nrkey +.Aq Fl r Ar rrega +.Op Fl i Ar iekey +.Op Fl p Ar cptpl +.Aq namespace id +.Nm +.Ic resv release +.Aq Fl c Ar crkey +.Aq Fl t Ar rtype +.Aq Fl a Ar rrela +.Aq namespace id +.Nm +.Ic resv report +.Op Fl e +.Op Fl v +.Op Fl x +.Aq namespace id +.Nm .Ic firmware .Op Fl s Ar slot .Op Fl f Ar path_to_firmware .Op Fl a .Aq device id .Nm .Ic format .Op Fl f Ar fmt .Op Fl m Ar mset .Op Fl o Ar pi .Op Fl l Ar pil .Op Fl E .Op Fl C .Aq device id .Aq namespace id .Nm .Ic sanitize .Aq Fl a Ar sanact .Op Fl c Ar owpass +.Op Fl d .Op Fl p Ar ovrpat .Op Fl r -.Op Fl D .Op Fl I .Op Fl U .Aq device id .Nm .Ic power .Op Fl l .Op Fl p power_state .Op Fl w workload_hint .Nm .Ic wdc cap-diag .Op Fl o path_template .Aq device id .Nm .Ic wdc drive-log .Op Fl o path_template .Aq device id .Nm .Ic wdc get-crash-dump .Op Fl o path_template .Aq device id .\" .Nm .\" .Ic wdc purge .\" .Aq device id .\" .Nm .\" .Ic wdc purge-monitor .\" .Aq device id .Sh DESCRIPTION NVM Express (NVMe) is a storage protocol standard, for SSDs and other high-speed storage devices over PCI Express. .Pp .Ss logpage The logpage command knows how to print log pages of various types. It also knows about vendor specific log pages from hgst/wdc and intel. Note that some vendors use the same log page numbers for different data. .Pp .Bl -tag -compact -width "Page 0x00" .It Dv Page 0x01 Drive Error Log .It Dv Page 0x02 Health/SMART Data .It Dv Page 0x03 Firmware Information .It Dv Page 0x04 Changed Namespace List .It Dv Page 0x05 Commands Supported and Effects .It Dv Page 0x80 Reservation Notification .It Dv Page 0x81 Sanitize Status .It Dv Page 0xc1 Advanced SMART information (WDC/HGST) .It Dv Page 0xc1 Read latency stats (Intel) .It Dv Page 0xc2 Wite latency stats (Intel) .It Dv Page 0xc5 Temperature stats (Intel) .It Dv Page 0xca Advanced SMART information (Intel) .El .Pp Specifying .Fl v .Ic help will list all valid vendors and pages. .Fl x will print the page as hex. .Fl b will print the binary data for the page. .Fl s will set Log Specific Field. .Fl i will set Log Specific Identifier. .Fl r will set Retain Asynchronous Event. .Ss ns Various namespace management commands. If namespace management is supported by device, allow list, create and delete namespaces, list, attach and detach controllers to namespaces. +.Ss resv acquire +Acquire or preempt namespace reservation, using specified parameters: +.Bl -tag -width 6n +.It Fl a +Acquire action: +.Bl -tag -compact -width 6n +.It Dv 0 +Acquire +.It Dv 1 +Preempt +.It Dv 2 +Preempt and abort +.El +.It Fl c +Current reservation key. +.It Fl p +Preempt reservation key. +.It Fl t +Reservation type: +.Bl -tag -compact -width 6n +.It Dv 1 +Write Exclusive +.It Dv 2 +Exclusive Access +.It Dv 3 +Write Exclusive - Registrants Only +.It Dv 4 +Exclusive Access - Registrants Only +.It Dv 5 +Write Exclusive - All Registrants +.It Dv 6 +Exclusive Access - All Registrants +.El +.El +.Ss resv register +Register, unregister or replace reservation key, using specified parameters: +.Bl -tag -width 6n +.It Fl c +Current reservation key. +.It Fl k +New reservation key. +.It Fl r +Register action: +.Bl -tag -compact -width 6n +.It Dv 0 +Register +.It Dv 1 +Unregister +.It Dv 2 +Replace +.El +.It Fl i +Ignore Existing Key +.It Fl p +Change Persist Through Power Loss State: +.Bl -tag -compact -width 6n +.It Dv 0 +No change to PTPL state +.It Dv 2 +Set PTPL state to ‘0’. +Reservations are released and registrants are cleared on a power on. +.It Dv 3 +Set PTPL state to ‘1’. +Reservations and registrants persist across a power loss. +.El +.El +.Ss resv release +Release or clear reservation, using specified parameters: +.Bl -tag -width 6n +.It Fl c +Current reservation key. +.It Fl t +Reservation type. +.It Fl a +Release action: +.Bl -tag -compact -width 6n +.It Dv 0 +Release +.It Dv 1 +Clean +.El +.El +.Ss resv report +Print reservation status, using specified parameters: +.Bl -tag -width 6n +.It Fl x +Print reservation status in hex. +.It Fl e +Use Extended Data Structure. +.El .Ss format Format either specified namespace, or all namespaces of specified controller, using specified parameters: .Ar fmt LBA Format, .Ar mset Metadata Settings, .Ar pi Protection Information, .Ar pil Protection Information Location. When formatting specific namespace, existing values are used as defaults. When formatting all namespaces, all parameters should be specified. Some controllers may not support formatting or erasing specific or all namespaces. Option .Fl E enables User Data Erase during format. Option .Fl C enables Cryptographic Erase during format. .Ss sanitize Sanitize NVM subsystem of specified controller, using specified parameters: .Bl -tag -width 6n .It Fl a Ar operation Specify the sanitize operation to perform. .Bl -tag -width 16n .It overwrite Perform an overwrite operation by writing a user supplied data pattern to the device one or more times. The pattern is given by the .Fl p argument. The number of times is given by the .Fl c argument. .It block Perform a block erase operation. All the device's blocks are set to a vendor defined value, typically zero. .It crypto Perform a cryptographic erase operation. The encryption keys are changed to prevent the decryption of the data. .It exitfailure Exits a previously failed sanitize operation. A failed sanitize operation can only be exited if it was run in the unrestricted completion mode, as provided by the .Fl U argument. .El .It Fl c Ar passes The number of passes when performing an .Sq overwrite operation. Valid values are between 1 and 16. The default is 1. -.It Fl D +.It Fl d No Deallocate After Sanitize. .It Fl I When performing an .Sq overwrite operation, the pattern is inverted between consecutive passes. .It Fl p Ar pattern 32 bits of pattern to use when performing an .Sq overwrite operation. The pattern is repeated as needed to fill each block. .It Fl U Perform the sanitize in the unrestricted completion mode. If the operation fails, it can later be exited with the .Sq exitfailure operation. .It Fl r Run in .Dq report only mode. This will report status on a sanitize that is already running on the drive. .El .Ss wdc The various wdc command retrieve log data from the wdc/hgst drives. The .Fl o flag specifies a path template to use to output the files. Each file takes the path template (which defaults to nothing), appends the drive's serial number and the type of dump it is followed by .bin. These logs must be sent to the vendor for analysis. This tool only provides a way to extract them. .Sh EXAMPLES .Dl nvmecontrol devlist .Pp Display a list of NVMe controllers and namespaces along with their device nodes. .Pp .Dl nvmecontrol identify nvme0 .Pp Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data. .Pp .Dl nvmecontrol identify -x -v nvme0ns1 .Pp Display an hexadecimal dump of the nvme0 IDENTIFY_NAMESPACE data for namespace 1. .Pp .Dl nvmecontrol perftest -n 32 -o read -s 512 -t 30 nvme0ns1 .Pp Run a performance test on nvme0ns1 using 32 kernel threads for 30 seconds. Each thread will issue a single 512 byte read command. Results are printed to stdout when 30 seconds expires. .Pp .Dl nvmecontrol reset nvme0 .Pp Perform a controller-level reset of the nvme0 controller. .Pp .Dl nvmecontrol logpage -p 1 nvme0 .Pp Display a human-readable summary of the nvme0 controller's Error Information Log. Log pages defined by the NVMe specification include Error Information Log (ID=1), SMART/Health Information Log (ID=2), and Firmware Slot Log (ID=3). .Pp .Dl nvmecontrol logpage -p 0xc1 -v wdc nvme0 .Pp Display a human-readable summary of the nvme0's wdc-specific advanced SMART data. .Pp .Dl nvmecontrol logpage -p 1 -x nvme0 .Pp Display a hexadecimal dump of the nvme0 controller's Error Information Log. .Pp .Dl nvmecontrol logpage -p 0xcb -b nvme0 > /tmp/page-cb.bin .Pp Print the contents of vendor specific page 0xcb as binary data on standard out. Redirect it to a temporary file. .Pp .Dl nvmecontrol firmware -s 2 -f /tmp/nvme_firmware nvme0 .Pp Download the firmware image contained in "/tmp/nvme_firmware" to slot 2 of the nvme0 controller, but do not activate the image. .Pp .Dl nvmecontrol firmware -s 4 -a nvme0 .Pp Activate the firmware in slot 4 of the nvme0 controller on the next reset. .Pp .Dl nvmecontrol firmware -s 7 -f /tmp/nvme_firmware -a nvme0 .Pp Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the nvme0 controller and activate it on the next reset. .Pp .Dl nvmecontrol power -l nvme0 .Pp List all the current power modes. .Pp .Dl nvmecontrol power -p 3 nvme0 .Pp Set the current power mode. .Pp .Dl nvmecontrol power nvme0 .Pp Get the current power mode. .Sh DYNAMIC LOADING The directories .Pa /lib/nvmecontrol and .Pa /usr/local/lib/nvmecontrol are scanned for any .so files. These files are loaded. The members of the .Va top linker set are added to the top-level commands. The members of the .Va logpage linker set are added to the logpage parsers. .Sh HISTORY The .Nm utility appeared in .Fx 9.2 . .Sh AUTHORS .An -nosplit .Nm was developed by Intel and originally written by .An Jim Harris Aq Mt jimharris@FreeBSD.org . .Pp This man page was written by .An Jim Harris Aq Mt jimharris@FreeBSD.org . Index: head/sbin/nvmecontrol/resv.c =================================================================== --- head/sbin/nvmecontrol/resv.c (nonexistent) +++ head/sbin/nvmecontrol/resv.c (revision 350599) @@ -0,0 +1,442 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2019 Alexander Motin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nvmecontrol.h" + +/* Tables for command line parsing */ + +static cmd_fn_t resv; +static cmd_fn_t resvacquire; +static cmd_fn_t resvregister; +static cmd_fn_t resvrelease; +static cmd_fn_t resvreport; + +#define NONE 0xffffffffu +#define NONE64 0xffffffffffffffffull +#define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } +#define OPT_END { NULL, 0, arg_none, NULL, NULL } + +static struct cmd resv_cmd = { + .name = "resv", + .fn = resv, + .descr = "Reservation commands", + .ctx_size = 0, + .opts = NULL, + .args = NULL, +}; + +CMD_COMMAND(resv_cmd); + +static struct acquire_options { + uint64_t crkey; + uint64_t prkey; + uint8_t rtype; + uint8_t racqa; + const char *dev; +} acquire_opt = { + .crkey = 0, + .prkey = 0, + .rtype = 0, + .racqa = 0, + .dev = NULL, +}; + +static const struct opts acquire_opts[] = { + OPT("crkey", 'c', arg_uint64, acquire_opt, crkey, + "Current Reservation Key"), + OPT("prkey", 'p', arg_uint64, acquire_opt, prkey, + "Preempt Reservation Key"), + OPT("rtype", 't', arg_uint8, acquire_opt, rtype, + "Reservation Type"), + OPT("racqa", 'a', arg_uint8, acquire_opt, racqa, + "Acquire Action (0=acq, 1=pre, 2=pre+ab)"), + { NULL, 0, arg_none, NULL, NULL } +}; + +static const struct args acquire_args[] = { + { arg_string, &acquire_opt.dev, "namespace-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd acquire_cmd = { + .name = "acquire", + .fn = resvacquire, + .descr = "Acquire/preempt reservation", + .ctx_size = sizeof(acquire_opt), + .opts = acquire_opts, + .args = acquire_args, +}; + +CMD_SUBCOMMAND(resv_cmd, acquire_cmd); + +static struct register_options { + uint64_t crkey; + uint64_t nrkey; + uint8_t rrega; + bool iekey; + uint8_t cptpl; + const char *dev; +} register_opt = { + .crkey = 0, + .nrkey = 0, + .rrega = 0, + .iekey = false, + .cptpl = 0, + .dev = NULL, +}; + +static const struct opts register_opts[] = { + OPT("crkey", 'c', arg_uint64, register_opt, crkey, + "Current Reservation Key"), + OPT("nrkey", 'k', arg_uint64, register_opt, nrkey, + "New Reservation Key"), + OPT("rrega", 'r', arg_uint8, register_opt, rrega, + "Register Action (0=reg, 1=unreg, 2=replace)"), + OPT("iekey", 'i', arg_none, register_opt, iekey, + "Ignore Existing Key"), + OPT("cptpl", 'p', arg_uint8, register_opt, cptpl, + "Change Persist Through Power Loss State"), + { NULL, 0, arg_none, NULL, NULL } +}; + +static const struct args register_args[] = { + { arg_string, ®ister_opt.dev, "namespace-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd register_cmd = { + .name = "register", + .fn = resvregister, + .descr = "Register/unregister reservation", + .ctx_size = sizeof(register_opt), + .opts = register_opts, + .args = register_args, +}; + +CMD_SUBCOMMAND(resv_cmd, register_cmd); + +static struct release_options { + uint64_t crkey; + uint8_t rtype; + uint8_t rrela; + const char *dev; +} release_opt = { + .crkey = 0, + .rtype = 0, + .rrela = 0, + .dev = NULL, +}; + +static const struct opts release_opts[] = { + OPT("crkey", 'c', arg_uint64, release_opt, crkey, + "Current Reservation Key"), + OPT("rtype", 't', arg_uint8, release_opt, rtype, + "Reservation Type"), + OPT("rrela", 'a', arg_uint8, release_opt, rrela, + "Release Action (0=release, 1=clear)"), + { NULL, 0, arg_none, NULL, NULL } +}; + +static const struct args release_args[] = { + { arg_string, &release_opt.dev, "namespace-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd release_cmd = { + .name = "release", + .fn = resvrelease, + .descr = "Release/clear reservation", + .ctx_size = sizeof(release_opt), + .opts = release_opts, + .args = release_args, +}; + +CMD_SUBCOMMAND(resv_cmd, release_cmd); + +static struct report_options { + bool hex; + bool verbose; + bool eds; + const char *dev; +} report_opt = { + .hex = false, + .verbose = false, + .eds = false, + .dev = NULL, +}; + +static const struct opts report_opts[] = { + OPT("hex", 'x', arg_none, report_opt, hex, + "Print reservation status in hex"), + OPT("verbose", 'v', arg_none, report_opt, verbose, + "More verbosity"), + OPT("eds", 'e', arg_none, report_opt, eds, + "Extended Data Structure"), + { NULL, 0, arg_none, NULL, NULL } +}; + +static const struct args report_args[] = { + { arg_string, &report_opt.dev, "namespace-id" }, + { arg_none, NULL, NULL }, +}; + +static struct cmd report_cmd = { + .name = "report", + .fn = resvreport, + .descr = "Print reservation status", + .ctx_size = sizeof(report_opt), + .opts = report_opts, + .args = report_args, +}; + +CMD_SUBCOMMAND(resv_cmd, report_cmd); + +/* handles NVME_OPC_RESERVATION_* NVM commands */ + +static void +resvacquire(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + uint64_t data[2]; + int fd; + uint32_t nsid; + + if (arg_parse(argc, argv, f)) + return; + open_dev(acquire_opt.dev, &fd, 1, 1); + get_nsid(fd, NULL, &nsid); + if (nsid == 0) { + fprintf(stderr, "This command require namespace-id\n"); + arg_help(argc, argv, f); + } + + data[0] = htole64(acquire_opt.crkey); + data[1] = htole64(acquire_opt.prkey); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_RESERVATION_ACQUIRE; + pt.cmd.cdw10 = htole32((acquire_opt.racqa & 7) | + (acquire_opt.rtype << 8)); + pt.buf = &data; + pt.len = sizeof(data); + pt.is_read = 0; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "acquire request failed"); + + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "acquire request returned error"); + + close(fd); + exit(0); +} + +static void +resvregister(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + uint64_t data[2]; + int fd; + uint32_t nsid; + + if (arg_parse(argc, argv, f)) + return; + open_dev(register_opt.dev, &fd, 1, 1); + get_nsid(fd, NULL, &nsid); + if (nsid == 0) { + fprintf(stderr, "This command require namespace-id\n"); + arg_help(argc, argv, f); + } + + data[0] = htole64(register_opt.crkey); + data[1] = htole64(register_opt.nrkey); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_RESERVATION_REGISTER; + pt.cmd.cdw10 = htole32((register_opt.rrega & 7) | + (register_opt.iekey << 3) | (register_opt.cptpl << 30)); + pt.buf = &data; + pt.len = sizeof(data); + pt.is_read = 0; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "register request failed"); + + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "register request returned error"); + + close(fd); + exit(0); +} + +static void +resvrelease(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + uint64_t data[1]; + int fd; + uint32_t nsid; + + if (arg_parse(argc, argv, f)) + return; + open_dev(release_opt.dev, &fd, 1, 1); + get_nsid(fd, NULL, &nsid); + if (nsid == 0) { + fprintf(stderr, "This command require namespace-id\n"); + arg_help(argc, argv, f); + } + + data[0] = htole64(release_opt.crkey); + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_RESERVATION_RELEASE; + pt.cmd.cdw10 = htole32((release_opt.rrela & 7) | + (release_opt.rtype << 8)); + pt.buf = &data; + pt.len = sizeof(data); + pt.is_read = 0; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "release request failed"); + + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "release request returned error"); + + close(fd); + exit(0); +} + +static void +resvreport(const struct cmd *f, int argc, char *argv[]) +{ + struct nvme_pt_command pt; + struct nvme_resv_status *s; + struct nvme_resv_status_ext *e; + uint8_t data[4096]; + int fd; + u_int i, n; + uint32_t nsid; + + if (arg_parse(argc, argv, f)) + return; + open_dev(report_opt.dev, &fd, 1, 1); + get_nsid(fd, NULL, &nsid); + if (nsid == 0) { + fprintf(stderr, "This command require namespace-id\n"); + arg_help(argc, argv, f); + } + + bzero(data, sizeof(data)); + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_RESERVATION_REPORT; + pt.cmd.cdw10 = htole32(sizeof(data) / 4 - 1); + pt.cmd.cdw11 = htole32(report_opt.eds); /* EDS */ + pt.buf = &data; + pt.len = sizeof(data); + pt.is_read = 1; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + err(1, "report request failed"); + + if (nvme_completion_is_error(&pt.cpl)) + errx(1, "report request returned error"); + + close(fd); + + if (report_opt.eds) + nvme_resv_status_ext_swapbytes((void *)data, sizeof(data)); + else + nvme_resv_status_swapbytes((void *)data, sizeof(data)); + + if (report_opt.hex) { + i = sizeof(data); + if (!report_opt.verbose) { + for (; i > 64; i--) { + if (data[i - 1] != 0) + break; + } + } + print_hex(&data, i); + exit(0); + } + + s = (struct nvme_resv_status *)data; + n = (s->regctl[1] << 8) | s->regctl[0]; + printf("Generation: %u\n", s->gen); + printf("Reservation Type: %u\n", s->rtype); + printf("Number of Registered Controllers: %u\n", n); + printf("Persist Through Power Loss State: %u\n", s->ptpls); + if (report_opt.eds) { + e = (struct nvme_resv_status_ext *)data; + n = MIN(n, (sizeof(data) - sizeof(e)) / sizeof(e->ctrlr[0])); + for (i = 0; i < n; i++) { + printf("Controller ID: 0x%04x\n", + e->ctrlr[i].ctrlr_id); + printf(" Reservation Status: %u\n", + e->ctrlr[i].rcsts); + printf(" Reservation Key: 0x%08jx\n", + e->ctrlr[i].rkey); + printf(" Host Identifier: 0x%08jx%08jx\n", + e->ctrlr[i].hostid[0], e->ctrlr[i].hostid[1]); + } + } else { + n = MIN(n, (sizeof(data) - sizeof(s)) / sizeof(s->ctrlr[0])); + for (i = 0; i < n; i++) { + printf("Controller ID: 0x%04x\n", + s->ctrlr[i].ctrlr_id); + printf(" Reservation Status: %u\n", + s->ctrlr[i].rcsts); + printf(" Host Identifier: 0x%08jx\n", + s->ctrlr[i].hostid); + printf(" Reservation Key: 0x%08jx\n", + s->ctrlr[i].rkey); + } + } + exit(0); +} + +static void +resv(const struct cmd *nf __unused, int argc, char *argv[]) +{ + + cmd_dispatch(argc, argv, &resv_cmd); +} Property changes on: head/sbin/nvmecontrol/resv.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sbin/nvmecontrol/sanitize.c =================================================================== --- head/sbin/nvmecontrol/sanitize.c (revision 350598) +++ head/sbin/nvmecontrol/sanitize.c (revision 350599) @@ -1,222 +1,222 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (C) 2019 Alexander Motin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "nvmecontrol.h" /* Tables for command line parsing */ static cmd_fn_t sanitize; static struct options { bool ause; bool ndas; bool oipbp; bool reportonly; uint8_t owpass; uint32_t ovrpat; const char *sanact; const char *dev; } opt = { .ause = false, .ndas = false, .oipbp = false, .reportonly = false, .owpass = 1, .ovrpat = 0, .sanact = NULL, .dev = NULL, }; static const struct opts sanitize_opts[] = { #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } OPT("ause", 'U', arg_none, opt, ause, "Allow Unrestricted Sanitize Exit"), - OPT("ndas", 'D', arg_none, opt, ndas, + OPT("ndas", 'd', arg_none, opt, ndas, "No Deallocate After Sanitize"), OPT("oipbp", 'I', arg_none, opt, oipbp, "Overwrite Invert Pattern Between Passes"), OPT("reportonly", 'r', arg_none, opt, reportonly, "Report previous sanitize status"), OPT("owpass", 'c', arg_uint8, opt, owpass, "Overwrite Pass Count"), OPT("ovrpat", 'p', arg_uint32, opt, ovrpat, "Overwrite Pattern"), OPT("sanact", 'a', arg_string, opt, sanact, "Sanitize Action (block, overwrite, crypto)"), { NULL, 0, arg_none, NULL, NULL } }; #undef OPT static const struct args sanitize_args[] = { { arg_string, &opt.dev, "controller-id" }, { arg_none, NULL, NULL }, }; static struct cmd sanitize_cmd = { .name = "sanitize", .fn = sanitize, .descr = "Sanitize NVM subsystem", .ctx_size = sizeof(opt), .opts = sanitize_opts, .args = sanitize_args, }; CMD_COMMAND(sanitize_cmd); /* End of tables for command line parsing */ static void sanitize(const struct cmd *f, int argc, char *argv[]) { struct nvme_controller_data cd; struct nvme_pt_command pt; struct nvme_sanitize_status_page ss; char *path; uint32_t nsid; int sanact = 0, fd, delay = 1; if (arg_parse(argc, argv, f)) return; if (opt.sanact == NULL) { if (!opt.reportonly) { fprintf(stderr, "Sanitize Action is not specified\n"); arg_help(argc, argv, f); } } else { if (strcmp(opt.sanact, "exitfailure") == 0) sanact = 1; else if (strcmp(opt.sanact, "block") == 0) sanact = 2; else if (strcmp(opt.sanact, "overwrite") == 0) sanact = 3; else if (strcmp(opt.sanact, "crypto") == 0) sanact = 4; else { fprintf(stderr, "Incorrect Sanitize Action value\n"); arg_help(argc, argv, f); } } if (opt.owpass == 0 || opt.owpass > 16) { fprintf(stderr, "Incorrect Overwrite Pass Count value\n"); arg_help(argc, argv, f); } open_dev(opt.dev, &fd, 1, 1); get_nsid(fd, &path, &nsid); if (nsid != 0) { close(fd); open_dev(path, &fd, 1, 1); } free(path); if (opt.reportonly) goto wait; /* Check that controller can execute this command. */ read_controller_data(fd, &cd); if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_BES_SHIFT) & NVME_CTRLR_DATA_SANICAP_BES_MASK) == 0 && sanact == 2) errx(1, "controller does not support Block Erase"); if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_OWS_SHIFT) & NVME_CTRLR_DATA_SANICAP_OWS_MASK) == 0 && sanact == 3) errx(1, "controller does not support Overwrite"); if (((cd.sanicap >> NVME_CTRLR_DATA_SANICAP_CES_SHIFT) & NVME_CTRLR_DATA_SANICAP_CES_MASK) == 0 && sanact == 4) errx(1, "controller does not support Crypto Erase"); /* * If controller supports only one namespace, we may sanitize it. * If there can be more, make user explicit in his commands. */ if (nsid != 0 && cd.nn > 1) errx(1, "can't sanitize one of namespaces, specify controller"); memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_SANITIZE; pt.cmd.cdw10 = htole32((opt.ndas << 9) | (opt.oipbp << 8) | ((opt.owpass & 0xf) << 4) | (opt.ause << 3) | sanact); pt.cmd.cdw11 = htole32(opt.ovrpat); if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "sanitize request failed"); if (nvme_completion_is_error(&pt.cpl)) errx(1, "sanitize request returned error"); wait: read_logpage(fd, NVME_LOG_SANITIZE_STATUS, NVME_GLOBAL_NAMESPACE_TAG, 0, 0, 0, &ss, sizeof(ss)); switch ((ss.sstat >> NVME_SS_PAGE_SSTAT_STATUS_SHIFT) & NVME_SS_PAGE_SSTAT_STATUS_MASK) { case NVME_SS_PAGE_SSTAT_STATUS_NEVER: printf("Never sanitized"); break; case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED: printf("Sanitize completed"); break; case NVME_SS_PAGE_SSTAT_STATUS_INPROG: printf("Sanitize in progress: %u%% (%u/65535)\r", (ss.sprog * 100 + 32768) / 65536, ss.sprog); fflush(stdout); if (delay < 16) delay++; sleep(delay); goto wait; case NVME_SS_PAGE_SSTAT_STATUS_FAILED: printf("Sanitize failed"); break; case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD: printf("Sanitize completed with deallocation"); break; default: printf("Sanitize status unknown"); break; } if (delay > 1) printf(" "); printf("\n"); close(fd); exit(0); } Index: head/sys/dev/nvme/nvme.h =================================================================== --- head/sys/dev/nvme/nvme.h (revision 350598) +++ head/sys/dev/nvme/nvme.h (revision 350599) @@ -1,1864 +1,1944 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (C) 2012-2013 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __NVME_H__ #define __NVME_H__ #ifdef _KERNEL #include #endif #include #include #define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command) #define NVME_RESET_CONTROLLER _IO('n', 1) #define NVME_GET_NSID _IOR('n', 2, struct nvme_get_nsid) #define NVME_IO_TEST _IOWR('n', 100, struct nvme_io_test) #define NVME_BIO_TEST _IOWR('n', 101, struct nvme_io_test) /* * Macros to deal with NVME revisions, as defined VS register */ #define NVME_REV(x, y) (((x) << 16) | ((y) << 8)) #define NVME_MAJOR(r) (((r) >> 16) & 0xffff) #define NVME_MINOR(r) (((r) >> 8) & 0xff) /* * Use to mark a command to apply to all namespaces, or to retrieve global * log pages. */ #define NVME_GLOBAL_NAMESPACE_TAG ((uint32_t)0xFFFFFFFF) /* Cap nvme to 1MB transfers driver explodes with larger sizes */ #define NVME_MAX_XFER_SIZE (MAXPHYS < (1<<20) ? MAXPHYS : (1<<20)) /* Register field definitions */ #define NVME_CAP_LO_REG_MQES_SHIFT (0) #define NVME_CAP_LO_REG_MQES_MASK (0xFFFF) #define NVME_CAP_LO_REG_CQR_SHIFT (16) #define NVME_CAP_LO_REG_CQR_MASK (0x1) #define NVME_CAP_LO_REG_AMS_SHIFT (17) #define NVME_CAP_LO_REG_AMS_MASK (0x3) #define NVME_CAP_LO_REG_TO_SHIFT (24) #define NVME_CAP_LO_REG_TO_MASK (0xFF) #define NVME_CAP_LO_MQES(x) \ (((x) >> NVME_CAP_LO_REG_MQES_SHIFT) & NVME_CAP_LO_REG_MQES_MASK) #define NVME_CAP_LO_CQR(x) \ (((x) >> NVME_CAP_LO_REG_CQR_SHIFT) & NVME_CAP_LO_REG_CQR_MASK) #define NVME_CAP_LO_AMS(x) \ (((x) >> NVME_CAP_LO_REG_AMS_SHIFT) & NVME_CAP_LO_REG_AMS_MASK) #define NVME_CAP_LO_TO(x) \ (((x) >> NVME_CAP_LO_REG_TO_SHIFT) & NVME_CAP_LO_REG_TO_MASK) #define NVME_CAP_HI_REG_DSTRD_SHIFT (0) #define NVME_CAP_HI_REG_DSTRD_MASK (0xF) #define NVME_CAP_HI_REG_NSSRS_SHIFT (4) #define NVME_CAP_HI_REG_NSSRS_MASK (0x1) #define NVME_CAP_HI_REG_CSS_NVM_SHIFT (5) #define NVME_CAP_HI_REG_CSS_NVM_MASK (0x1) #define NVME_CAP_HI_REG_BPS_SHIFT (13) #define NVME_CAP_HI_REG_BPS_MASK (0x1) #define NVME_CAP_HI_REG_MPSMIN_SHIFT (16) #define NVME_CAP_HI_REG_MPSMIN_MASK (0xF) #define NVME_CAP_HI_REG_MPSMAX_SHIFT (20) #define NVME_CAP_HI_REG_MPSMAX_MASK (0xF) #define NVME_CAP_HI_REG_PMRS_SHIFT (24) #define NVME_CAP_HI_REG_PMRS_MASK (0x1) #define NVME_CAP_HI_REG_CMBS_SHIFT (25) #define NVME_CAP_HI_REG_CMBS_MASK (0x1) #define NVME_CAP_HI_DSTRD(x) \ (((x) >> NVME_CAP_HI_REG_DSTRD_SHIFT) & NVME_CAP_HI_REG_DSTRD_MASK) #define NVME_CAP_HI_CSS_NVM(x) \ (((x) >> NVME_CAP_HI_REG_CSS_NVM_SHIFT) & NVME_CAP_HI_REG_CSS_NVM_MASK) #define NVME_CAP_HI_MPSMIN(x) \ (((x) >> NVME_CAP_HI_REG_MPSMIN_SHIFT) & NVME_CAP_HI_REG_MPSMIN_MASK) #define NVME_CAP_HI_MPSMAX(x) \ (((x) >> NVME_CAP_HI_REG_MPSMAX_SHIFT) & NVME_CAP_HI_REG_MPSMAX_MASK) #define NVME_CC_REG_EN_SHIFT (0) #define NVME_CC_REG_EN_MASK (0x1) #define NVME_CC_REG_CSS_SHIFT (4) #define NVME_CC_REG_CSS_MASK (0x7) #define NVME_CC_REG_MPS_SHIFT (7) #define NVME_CC_REG_MPS_MASK (0xF) #define NVME_CC_REG_AMS_SHIFT (11) #define NVME_CC_REG_AMS_MASK (0x7) #define NVME_CC_REG_SHN_SHIFT (14) #define NVME_CC_REG_SHN_MASK (0x3) #define NVME_CC_REG_IOSQES_SHIFT (16) #define NVME_CC_REG_IOSQES_MASK (0xF) #define NVME_CC_REG_IOCQES_SHIFT (20) #define NVME_CC_REG_IOCQES_MASK (0xF) #define NVME_CSTS_REG_RDY_SHIFT (0) #define NVME_CSTS_REG_RDY_MASK (0x1) #define NVME_CSTS_REG_CFS_SHIFT (1) #define NVME_CSTS_REG_CFS_MASK (0x1) #define NVME_CSTS_REG_SHST_SHIFT (2) #define NVME_CSTS_REG_SHST_MASK (0x3) #define NVME_CSTS_REG_NVSRO_SHIFT (4) #define NVME_CSTS_REG_NVSRO_MASK (0x1) #define NVME_CSTS_REG_PP_SHIFT (5) #define NVME_CSTS_REG_PP_MASK (0x1) #define NVME_CSTS_GET_SHST(csts) (((csts) >> NVME_CSTS_REG_SHST_SHIFT) & NVME_CSTS_REG_SHST_MASK) #define NVME_AQA_REG_ASQS_SHIFT (0) #define NVME_AQA_REG_ASQS_MASK (0xFFF) #define NVME_AQA_REG_ACQS_SHIFT (16) #define NVME_AQA_REG_ACQS_MASK (0xFFF) /* Command field definitions */ #define NVME_CMD_FUSE_SHIFT (8) #define NVME_CMD_FUSE_MASK (0x3) #define NVME_STATUS_P_SHIFT (0) #define NVME_STATUS_P_MASK (0x1) #define NVME_STATUS_SC_SHIFT (1) #define NVME_STATUS_SC_MASK (0xFF) #define NVME_STATUS_SCT_SHIFT (9) #define NVME_STATUS_SCT_MASK (0x7) #define NVME_STATUS_CRD_SHIFT (12) #define NVME_STATUS_CRD_MASK (0x3) #define NVME_STATUS_M_SHIFT (14) #define NVME_STATUS_M_MASK (0x1) #define NVME_STATUS_DNR_SHIFT (15) #define NVME_STATUS_DNR_MASK (0x1) #define NVME_STATUS_GET_P(st) (((st) >> NVME_STATUS_P_SHIFT) & NVME_STATUS_P_MASK) #define NVME_STATUS_GET_SC(st) (((st) >> NVME_STATUS_SC_SHIFT) & NVME_STATUS_SC_MASK) #define NVME_STATUS_GET_SCT(st) (((st) >> NVME_STATUS_SCT_SHIFT) & NVME_STATUS_SCT_MASK) #define NVME_STATUS_GET_M(st) (((st) >> NVME_STATUS_M_SHIFT) & NVME_STATUS_M_MASK) #define NVME_STATUS_GET_DNR(st) (((st) >> NVME_STATUS_DNR_SHIFT) & NVME_STATUS_DNR_MASK) #define NVME_PWR_ST_MPS_SHIFT (0) #define NVME_PWR_ST_MPS_MASK (0x1) #define NVME_PWR_ST_NOPS_SHIFT (1) #define NVME_PWR_ST_NOPS_MASK (0x1) #define NVME_PWR_ST_RRT_SHIFT (0) #define NVME_PWR_ST_RRT_MASK (0x1F) #define NVME_PWR_ST_RRL_SHIFT (0) #define NVME_PWR_ST_RRL_MASK (0x1F) #define NVME_PWR_ST_RWT_SHIFT (0) #define NVME_PWR_ST_RWT_MASK (0x1F) #define NVME_PWR_ST_RWL_SHIFT (0) #define NVME_PWR_ST_RWL_MASK (0x1F) #define NVME_PWR_ST_IPS_SHIFT (6) #define NVME_PWR_ST_IPS_MASK (0x3) #define NVME_PWR_ST_APW_SHIFT (0) #define NVME_PWR_ST_APW_MASK (0x7) #define NVME_PWR_ST_APS_SHIFT (6) #define NVME_PWR_ST_APS_MASK (0x3) /** Controller Multi-path I/O and Namespace Sharing Capabilities */ /* More then one port */ #define NVME_CTRLR_DATA_MIC_MPORTS_SHIFT (0) #define NVME_CTRLR_DATA_MIC_MPORTS_MASK (0x1) /* More then one controller */ #define NVME_CTRLR_DATA_MIC_MCTRLRS_SHIFT (1) #define NVME_CTRLR_DATA_MIC_MCTRLRS_MASK (0x1) /* SR-IOV Virtual Function */ #define NVME_CTRLR_DATA_MIC_SRIOVVF_SHIFT (2) #define NVME_CTRLR_DATA_MIC_SRIOVVF_MASK (0x1) /* Asymmetric Namespace Access Reporting */ #define NVME_CTRLR_DATA_MIC_ANAR_SHIFT (3) #define NVME_CTRLR_DATA_MIC_ANAR_MASK (0x1) /** OACS - optional admin command support */ /* supports security send/receive commands */ #define NVME_CTRLR_DATA_OACS_SECURITY_SHIFT (0) #define NVME_CTRLR_DATA_OACS_SECURITY_MASK (0x1) /* supports format nvm command */ #define NVME_CTRLR_DATA_OACS_FORMAT_SHIFT (1) #define NVME_CTRLR_DATA_OACS_FORMAT_MASK (0x1) /* supports firmware activate/download commands */ #define NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT (2) #define NVME_CTRLR_DATA_OACS_FIRMWARE_MASK (0x1) /* supports namespace management commands */ #define NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT (3) #define NVME_CTRLR_DATA_OACS_NSMGMT_MASK (0x1) /* supports Device Self-test command */ #define NVME_CTRLR_DATA_OACS_SELFTEST_SHIFT (4) #define NVME_CTRLR_DATA_OACS_SELFTEST_MASK (0x1) /* supports Directives */ #define NVME_CTRLR_DATA_OACS_DIRECTIVES_SHIFT (5) #define NVME_CTRLR_DATA_OACS_DIRECTIVES_MASK (0x1) /* supports NVMe-MI Send/Receive */ #define NVME_CTRLR_DATA_OACS_NVMEMI_SHIFT (6) #define NVME_CTRLR_DATA_OACS_NVMEMI_MASK (0x1) /* supports Virtualization Management */ #define NVME_CTRLR_DATA_OACS_VM_SHIFT (7) #define NVME_CTRLR_DATA_OACS_VM_MASK (0x1) /* supports Doorbell Buffer Config */ #define NVME_CTRLR_DATA_OACS_DBBUFFER_SHIFT (8) #define NVME_CTRLR_DATA_OACS_DBBUFFER_MASK (0x1) /* supports Get LBA Status */ #define NVME_CTRLR_DATA_OACS_GETLBA_SHIFT (9) #define NVME_CTRLR_DATA_OACS_GETLBA_MASK (0x1) /** firmware updates */ /* first slot is read-only */ #define NVME_CTRLR_DATA_FRMW_SLOT1_RO_SHIFT (0) #define NVME_CTRLR_DATA_FRMW_SLOT1_RO_MASK (0x1) /* number of firmware slots */ #define NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT (1) #define NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK (0x7) /* firmware activation without reset */ #define NVME_CTRLR_DATA_FRMW_ACT_WO_RESET_SHIFT (4) #define NVME_CTRLR_DATA_FRMW_ACT_WO_RESET_MASK (0x1) /** log page attributes */ /* per namespace smart/health log page */ #define NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT (0) #define NVME_CTRLR_DATA_LPA_NS_SMART_MASK (0x1) /** AVSCC - admin vendor specific command configuration */ /* admin vendor specific commands use spec format */ #define NVME_CTRLR_DATA_AVSCC_SPEC_FORMAT_SHIFT (0) #define NVME_CTRLR_DATA_AVSCC_SPEC_FORMAT_MASK (0x1) /** Autonomous Power State Transition Attributes */ /* Autonomous Power State Transitions supported */ #define NVME_CTRLR_DATA_APSTA_APST_SUPP_SHIFT (0) #define NVME_CTRLR_DATA_APSTA_APST_SUPP_MASK (0x1) /** Sanitize Capabilities */ /* Crypto Erase Support */ #define NVME_CTRLR_DATA_SANICAP_CES_SHIFT (0) #define NVME_CTRLR_DATA_SANICAP_CES_MASK (0x1) /* Block Erase Support */ #define NVME_CTRLR_DATA_SANICAP_BES_SHIFT (1) #define NVME_CTRLR_DATA_SANICAP_BES_MASK (0x1) /* Overwrite Support */ #define NVME_CTRLR_DATA_SANICAP_OWS_SHIFT (2) #define NVME_CTRLR_DATA_SANICAP_OWS_MASK (0x1) /* No-Deallocate Inhibited */ #define NVME_CTRLR_DATA_SANICAP_NDI_SHIFT (29) #define NVME_CTRLR_DATA_SANICAP_NDI_MASK (0x1) /* No-Deallocate Modifies Media After Sanitize */ #define NVME_CTRLR_DATA_SANICAP_NODMMAS_SHIFT (30) #define NVME_CTRLR_DATA_SANICAP_NODMMAS_MASK (0x3) #define NVME_CTRLR_DATA_SANICAP_NODMMAS_UNDEF (0) #define NVME_CTRLR_DATA_SANICAP_NODMMAS_NO (1) #define NVME_CTRLR_DATA_SANICAP_NODMMAS_YES (2) /** submission queue entry size */ #define NVME_CTRLR_DATA_SQES_MIN_SHIFT (0) #define NVME_CTRLR_DATA_SQES_MIN_MASK (0xF) #define NVME_CTRLR_DATA_SQES_MAX_SHIFT (4) #define NVME_CTRLR_DATA_SQES_MAX_MASK (0xF) /** completion queue entry size */ #define NVME_CTRLR_DATA_CQES_MIN_SHIFT (0) #define NVME_CTRLR_DATA_CQES_MIN_MASK (0xF) #define NVME_CTRLR_DATA_CQES_MAX_SHIFT (4) #define NVME_CTRLR_DATA_CQES_MAX_MASK (0xF) /** optional nvm command support */ #define NVME_CTRLR_DATA_ONCS_COMPARE_SHIFT (0) #define NVME_CTRLR_DATA_ONCS_COMPARE_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_WRITE_UNC_SHIFT (1) #define NVME_CTRLR_DATA_ONCS_WRITE_UNC_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_DSM_SHIFT (2) #define NVME_CTRLR_DATA_ONCS_DSM_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_WRZERO_SHIFT (3) #define NVME_CTRLR_DATA_ONCS_WRZERO_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_SAVEFEAT_SHIFT (4) #define NVME_CTRLR_DATA_ONCS_SAVEFEAT_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_RESERV_SHIFT (5) #define NVME_CTRLR_DATA_ONCS_RESERV_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_TIMESTAMP_SHIFT (6) #define NVME_CTRLR_DATA_ONCS_TIMESTAMP_MASK (0x1) #define NVME_CTRLR_DATA_ONCS_VERIFY_SHIFT (7) #define NVME_CTRLR_DATA_ONCS_VERIFY_MASK (0x1) /** Fused Operation Support */ #define NVME_CTRLR_DATA_FUSES_CNW_SHIFT (0) #define NVME_CTRLR_DATA_FUSES_CNW_MASK (0x1) /** Format NVM Attributes */ #define NVME_CTRLR_DATA_FNA_FORMAT_ALL_SHIFT (0) #define NVME_CTRLR_DATA_FNA_FORMAT_ALL_MASK (0x1) #define NVME_CTRLR_DATA_FNA_ERASE_ALL_SHIFT (1) #define NVME_CTRLR_DATA_FNA_ERASE_ALL_MASK (0x1) #define NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_SHIFT (2) #define NVME_CTRLR_DATA_FNA_CRYPTO_ERASE_MASK (0x1) /** volatile write cache */ /* volatile write cache present */ #define NVME_CTRLR_DATA_VWC_PRESENT_SHIFT (0) #define NVME_CTRLR_DATA_VWC_PRESENT_MASK (0x1) /* flush all namespaces supported */ #define NVME_CTRLR_DATA_VWC_ALL_SHIFT (1) #define NVME_CTRLR_DATA_VWC_ALL_MASK (0x3) #define NVME_CTRLR_DATA_VWC_ALL_UNKNOWN (0) #define NVME_CTRLR_DATA_VWC_ALL_NO (2) #define NVME_CTRLR_DATA_VWC_ALL_YES (3) /** namespace features */ /* thin provisioning */ #define NVME_NS_DATA_NSFEAT_THIN_PROV_SHIFT (0) #define NVME_NS_DATA_NSFEAT_THIN_PROV_MASK (0x1) /* NAWUN, NAWUPF, and NACWU fields are valid */ #define NVME_NS_DATA_NSFEAT_NA_FIELDS_SHIFT (1) #define NVME_NS_DATA_NSFEAT_NA_FIELDS_MASK (0x1) /* Deallocated or Unwritten Logical Block errors supported */ #define NVME_NS_DATA_NSFEAT_DEALLOC_SHIFT (2) #define NVME_NS_DATA_NSFEAT_DEALLOC_MASK (0x1) /* NGUID and EUI64 fields are not reusable */ #define NVME_NS_DATA_NSFEAT_NO_ID_REUSE_SHIFT (3) #define NVME_NS_DATA_NSFEAT_NO_ID_REUSE_MASK (0x1) /* NPWG, NPWA, NPDG, NPDA, and NOWS are valid */ #define NVME_NS_DATA_NSFEAT_NPVALID_SHIFT (4) #define NVME_NS_DATA_NSFEAT_NPVALID_MASK (0x1) /** formatted lba size */ #define NVME_NS_DATA_FLBAS_FORMAT_SHIFT (0) #define NVME_NS_DATA_FLBAS_FORMAT_MASK (0xF) #define NVME_NS_DATA_FLBAS_EXTENDED_SHIFT (4) #define NVME_NS_DATA_FLBAS_EXTENDED_MASK (0x1) /** metadata capabilities */ /* metadata can be transferred as part of data prp list */ #define NVME_NS_DATA_MC_EXTENDED_SHIFT (0) #define NVME_NS_DATA_MC_EXTENDED_MASK (0x1) /* metadata can be transferred with separate metadata pointer */ #define NVME_NS_DATA_MC_POINTER_SHIFT (1) #define NVME_NS_DATA_MC_POINTER_MASK (0x1) /** end-to-end data protection capabilities */ /* protection information type 1 */ #define NVME_NS_DATA_DPC_PIT1_SHIFT (0) #define NVME_NS_DATA_DPC_PIT1_MASK (0x1) /* protection information type 2 */ #define NVME_NS_DATA_DPC_PIT2_SHIFT (1) #define NVME_NS_DATA_DPC_PIT2_MASK (0x1) /* protection information type 3 */ #define NVME_NS_DATA_DPC_PIT3_SHIFT (2) #define NVME_NS_DATA_DPC_PIT3_MASK (0x1) /* first eight bytes of metadata */ #define NVME_NS_DATA_DPC_MD_START_SHIFT (3) #define NVME_NS_DATA_DPC_MD_START_MASK (0x1) /* last eight bytes of metadata */ #define NVME_NS_DATA_DPC_MD_END_SHIFT (4) #define NVME_NS_DATA_DPC_MD_END_MASK (0x1) /** end-to-end data protection type settings */ /* protection information type */ #define NVME_NS_DATA_DPS_PIT_SHIFT (0) #define NVME_NS_DATA_DPS_PIT_MASK (0x7) /* 1 == protection info transferred at start of metadata */ /* 0 == protection info transferred at end of metadata */ #define NVME_NS_DATA_DPS_MD_START_SHIFT (3) #define NVME_NS_DATA_DPS_MD_START_MASK (0x1) /** Namespace Multi-path I/O and Namespace Sharing Capabilities */ /* the namespace may be attached to two or more controllers */ #define NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT (0) #define NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK (0x1) /** Reservation Capabilities */ /* Persist Through Power Loss */ #define NVME_NS_DATA_RESCAP_PTPL_SHIFT (0) #define NVME_NS_DATA_RESCAP_PTPL_MASK (0x1) /* supports the Write Exclusive */ #define NVME_NS_DATA_RESCAP_WR_EX_SHIFT (1) #define NVME_NS_DATA_RESCAP_WR_EX_MASK (0x1) /* supports the Exclusive Access */ #define NVME_NS_DATA_RESCAP_EX_AC_SHIFT (2) #define NVME_NS_DATA_RESCAP_EX_AC_MASK (0x1) /* supports the Write Exclusive – Registrants Only */ #define NVME_NS_DATA_RESCAP_WR_EX_RO_SHIFT (3) #define NVME_NS_DATA_RESCAP_WR_EX_RO_MASK (0x1) /* supports the Exclusive Access - Registrants Only */ #define NVME_NS_DATA_RESCAP_EX_AC_RO_SHIFT (4) #define NVME_NS_DATA_RESCAP_EX_AC_RO_MASK (0x1) /* supports the Write Exclusive – All Registrants */ #define NVME_NS_DATA_RESCAP_WR_EX_AR_SHIFT (5) #define NVME_NS_DATA_RESCAP_WR_EX_AR_MASK (0x1) /* supports the Exclusive Access - All Registrants */ #define NVME_NS_DATA_RESCAP_EX_AC_AR_SHIFT (6) #define NVME_NS_DATA_RESCAP_EX_AC_AR_MASK (0x1) /* Ignore Existing Key is used as defined in revision 1.3 or later */ #define NVME_NS_DATA_RESCAP_IEKEY13_SHIFT (7) #define NVME_NS_DATA_RESCAP_IEKEY13_MASK (0x1) /** Format Progress Indicator */ /* percentage of the Format NVM command that remains to be completed */ #define NVME_NS_DATA_FPI_PERC_SHIFT (0) #define NVME_NS_DATA_FPI_PERC_MASK (0x7f) /* namespace supports the Format Progress Indicator */ #define NVME_NS_DATA_FPI_SUPP_SHIFT (7) #define NVME_NS_DATA_FPI_SUPP_MASK (0x1) /** Deallocate Logical Block Features */ /* deallocated logical block read behavior */ #define NVME_NS_DATA_DLFEAT_READ_SHIFT (0) #define NVME_NS_DATA_DLFEAT_READ_MASK (0x07) #define NVME_NS_DATA_DLFEAT_READ_NR (0x00) #define NVME_NS_DATA_DLFEAT_READ_00 (0x01) #define NVME_NS_DATA_DLFEAT_READ_FF (0x02) /* supports the Deallocate bit in the Write Zeroes */ #define NVME_NS_DATA_DLFEAT_DWZ_SHIFT (3) #define NVME_NS_DATA_DLFEAT_DWZ_MASK (0x01) /* Guard field for deallocated logical blocks is set to the CRC */ #define NVME_NS_DATA_DLFEAT_GCRC_SHIFT (4) #define NVME_NS_DATA_DLFEAT_GCRC_MASK (0x01) /** lba format support */ /* metadata size */ #define NVME_NS_DATA_LBAF_MS_SHIFT (0) #define NVME_NS_DATA_LBAF_MS_MASK (0xFFFF) /* lba data size */ #define NVME_NS_DATA_LBAF_LBADS_SHIFT (16) #define NVME_NS_DATA_LBAF_LBADS_MASK (0xFF) /* relative performance */ #define NVME_NS_DATA_LBAF_RP_SHIFT (24) #define NVME_NS_DATA_LBAF_RP_MASK (0x3) enum nvme_critical_warning_state { NVME_CRIT_WARN_ST_AVAILABLE_SPARE = 0x1, NVME_CRIT_WARN_ST_TEMPERATURE = 0x2, NVME_CRIT_WARN_ST_DEVICE_RELIABILITY = 0x4, NVME_CRIT_WARN_ST_READ_ONLY = 0x8, NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP = 0x10, }; #define NVME_CRIT_WARN_ST_RESERVED_MASK (0xE0) /* slot for current FW */ #define NVME_FIRMWARE_PAGE_AFI_SLOT_SHIFT (0) #define NVME_FIRMWARE_PAGE_AFI_SLOT_MASK (0x7) /* Commands Supported and Effects */ #define NVME_CE_PAGE_CSUP_SHIFT (0) #define NVME_CE_PAGE_CSUP_MASK (0x1) #define NVME_CE_PAGE_LBCC_SHIFT (1) #define NVME_CE_PAGE_LBCC_MASK (0x1) #define NVME_CE_PAGE_NCC_SHIFT (2) #define NVME_CE_PAGE_NCC_MASK (0x1) #define NVME_CE_PAGE_NIC_SHIFT (3) #define NVME_CE_PAGE_NIC_MASK (0x1) #define NVME_CE_PAGE_CCC_SHIFT (4) #define NVME_CE_PAGE_CCC_MASK (0x1) #define NVME_CE_PAGE_CSE_SHIFT (16) #define NVME_CE_PAGE_CSE_MASK (0x7) #define NVME_CE_PAGE_UUID_SHIFT (19) #define NVME_CE_PAGE_UUID_MASK (0x1) /* Sanitize Status */ #define NVME_SS_PAGE_SSTAT_STATUS_SHIFT (0) #define NVME_SS_PAGE_SSTAT_STATUS_MASK (0x7) #define NVME_SS_PAGE_SSTAT_STATUS_NEVER (0) #define NVME_SS_PAGE_SSTAT_STATUS_COMPLETED (1) #define NVME_SS_PAGE_SSTAT_STATUS_INPROG (2) #define NVME_SS_PAGE_SSTAT_STATUS_FAILED (3) #define NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD (4) #define NVME_SS_PAGE_SSTAT_PASSES_SHIFT (3) #define NVME_SS_PAGE_SSTAT_PASSES_MASK (0x1f) #define NVME_SS_PAGE_SSTAT_GDE_SHIFT (8) #define NVME_SS_PAGE_SSTAT_GDE_MASK (0x1) /* CC register SHN field values */ enum shn_value { NVME_SHN_NORMAL = 0x1, NVME_SHN_ABRUPT = 0x2, }; /* CSTS register SHST field values */ enum shst_value { NVME_SHST_NORMAL = 0x0, NVME_SHST_OCCURRING = 0x1, NVME_SHST_COMPLETE = 0x2, }; struct nvme_registers { uint32_t cap_lo; /* controller capabilities */ uint32_t cap_hi; uint32_t vs; /* version */ uint32_t intms; /* interrupt mask set */ uint32_t intmc; /* interrupt mask clear */ uint32_t cc; /* controller configuration */ uint32_t reserved1; uint32_t csts; /* controller status */ uint32_t nssr; /* NVM Subsystem Reset */ uint32_t aqa; /* admin queue attributes */ uint64_t asq; /* admin submission queue base addr */ uint64_t acq; /* admin completion queue base addr */ uint32_t cmbloc; /* Controller Memory Buffer Location */ uint32_t cmbsz; /* Controller Memory Buffer Size */ uint32_t bpinfo; /* Boot Partition Information */ uint32_t bprsel; /* Boot Partition Read Select */ uint64_t bpmbl; /* Boot Partition Memory Buffer Location */ uint64_t cmbmsc; /* Controller Memory Buffer Memory Space Control */ uint32_t cmbsts; /* Controller Memory Buffer Status */ uint8_t reserved3[3492]; /* 5Ch - DFFh */ uint32_t pmrcap; /* Persistent Memory Capabilities */ uint32_t pmrctl; /* Persistent Memory Region Control */ uint32_t pmrsts; /* Persistent Memory Region Status */ uint32_t pmrebs; /* Persistent Memory Region Elasticity Buffer Size */ uint32_t pmrswtp; /* Persistent Memory Region Sustained Write Throughput */ uint32_t pmrmsc_lo; /* Persistent Memory Region Controller Memory Space Control */ uint32_t pmrmsc_hi; uint8_t reserved4[484]; /* E1Ch - FFFh */ struct { uint32_t sq_tdbl; /* submission queue tail doorbell */ uint32_t cq_hdbl; /* completion queue head doorbell */ } doorbell[1] __packed; } __packed; _Static_assert(sizeof(struct nvme_registers) == 0x1008, "bad size for nvme_registers"); struct nvme_command { /* dword 0 */ uint8_t opc; /* opcode */ uint8_t fuse; /* fused operation */ uint16_t cid; /* command identifier */ /* dword 1 */ uint32_t nsid; /* namespace identifier */ /* dword 2-3 */ uint32_t rsvd2; uint32_t rsvd3; /* dword 4-5 */ uint64_t mptr; /* metadata pointer */ /* dword 6-7 */ uint64_t prp1; /* prp entry 1 */ /* dword 8-9 */ uint64_t prp2; /* prp entry 2 */ /* dword 10-15 */ uint32_t cdw10; /* command-specific */ uint32_t cdw11; /* command-specific */ uint32_t cdw12; /* command-specific */ uint32_t cdw13; /* command-specific */ uint32_t cdw14; /* command-specific */ uint32_t cdw15; /* command-specific */ } __packed; _Static_assert(sizeof(struct nvme_command) == 16 * 4, "bad size for nvme_command"); struct nvme_completion { /* dword 0 */ uint32_t cdw0; /* command-specific */ /* dword 1 */ uint32_t rsvd1; /* dword 2 */ uint16_t sqhd; /* submission queue head pointer */ uint16_t sqid; /* submission queue identifier */ /* dword 3 */ uint16_t cid; /* command identifier */ uint16_t status; } __packed; _Static_assert(sizeof(struct nvme_completion) == 4 * 4, "bad size for nvme_completion"); struct nvme_dsm_range { uint32_t attributes; uint32_t length; uint64_t starting_lba; } __packed; /* Largest DSM Trim that can be done */ #define NVME_MAX_DSM_TRIM 4096 _Static_assert(sizeof(struct nvme_dsm_range) == 16, "bad size for nvme_dsm_ranage"); /* status code types */ enum nvme_status_code_type { NVME_SCT_GENERIC = 0x0, NVME_SCT_COMMAND_SPECIFIC = 0x1, NVME_SCT_MEDIA_ERROR = 0x2, NVME_SCT_PATH_RELATED = 0x3, /* 0x3-0x6 - reserved */ NVME_SCT_VENDOR_SPECIFIC = 0x7, }; /* generic command status codes */ enum nvme_generic_command_status_code { NVME_SC_SUCCESS = 0x00, NVME_SC_INVALID_OPCODE = 0x01, NVME_SC_INVALID_FIELD = 0x02, NVME_SC_COMMAND_ID_CONFLICT = 0x03, NVME_SC_DATA_TRANSFER_ERROR = 0x04, NVME_SC_ABORTED_POWER_LOSS = 0x05, NVME_SC_INTERNAL_DEVICE_ERROR = 0x06, NVME_SC_ABORTED_BY_REQUEST = 0x07, NVME_SC_ABORTED_SQ_DELETION = 0x08, NVME_SC_ABORTED_FAILED_FUSED = 0x09, NVME_SC_ABORTED_MISSING_FUSED = 0x0a, NVME_SC_INVALID_NAMESPACE_OR_FORMAT = 0x0b, NVME_SC_COMMAND_SEQUENCE_ERROR = 0x0c, NVME_SC_INVALID_SGL_SEGMENT_DESCR = 0x0d, NVME_SC_INVALID_NUMBER_OF_SGL_DESCR = 0x0e, NVME_SC_DATA_SGL_LENGTH_INVALID = 0x0f, NVME_SC_METADATA_SGL_LENGTH_INVALID = 0x10, NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID = 0x11, NVME_SC_INVALID_USE_OF_CMB = 0x12, NVME_SC_PRP_OFFET_INVALID = 0x13, NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED = 0x14, NVME_SC_OPERATION_DENIED = 0x15, NVME_SC_SGL_OFFSET_INVALID = 0x16, /* 0x17 - reserved */ NVME_SC_HOST_ID_INCONSISTENT_FORMAT = 0x18, NVME_SC_KEEP_ALIVE_TIMEOUT_EXPIRED = 0x19, NVME_SC_KEEP_ALIVE_TIMEOUT_INVALID = 0x1a, NVME_SC_ABORTED_DUE_TO_PREEMPT = 0x1b, NVME_SC_SANITIZE_FAILED = 0x1c, NVME_SC_SANITIZE_IN_PROGRESS = 0x1d, NVME_SC_SGL_DATA_BLOCK_GRAN_INVALID = 0x1e, NVME_SC_NOT_SUPPORTED_IN_CMB = 0x1f, NVME_SC_NAMESPACE_IS_WRITE_PROTECTED = 0x20, NVME_SC_COMMAND_INTERRUPTED = 0x21, NVME_SC_TRANSIENT_TRANSPORT_ERROR = 0x22, NVME_SC_LBA_OUT_OF_RANGE = 0x80, NVME_SC_CAPACITY_EXCEEDED = 0x81, NVME_SC_NAMESPACE_NOT_READY = 0x82, NVME_SC_RESERVATION_CONFLICT = 0x83, NVME_SC_FORMAT_IN_PROGRESS = 0x84, }; /* command specific status codes */ enum nvme_command_specific_status_code { NVME_SC_COMPLETION_QUEUE_INVALID = 0x00, NVME_SC_INVALID_QUEUE_IDENTIFIER = 0x01, NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED = 0x02, NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED = 0x03, /* 0x04 - reserved */ NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED = 0x05, NVME_SC_INVALID_FIRMWARE_SLOT = 0x06, NVME_SC_INVALID_FIRMWARE_IMAGE = 0x07, NVME_SC_INVALID_INTERRUPT_VECTOR = 0x08, NVME_SC_INVALID_LOG_PAGE = 0x09, NVME_SC_INVALID_FORMAT = 0x0a, NVME_SC_FIRMWARE_REQUIRES_RESET = 0x0b, NVME_SC_INVALID_QUEUE_DELETION = 0x0c, NVME_SC_FEATURE_NOT_SAVEABLE = 0x0d, NVME_SC_FEATURE_NOT_CHANGEABLE = 0x0e, NVME_SC_FEATURE_NOT_NS_SPECIFIC = 0x0f, NVME_SC_FW_ACT_REQUIRES_NVMS_RESET = 0x10, NVME_SC_FW_ACT_REQUIRES_RESET = 0x11, NVME_SC_FW_ACT_REQUIRES_TIME = 0x12, NVME_SC_FW_ACT_PROHIBITED = 0x13, NVME_SC_OVERLAPPING_RANGE = 0x14, NVME_SC_NS_INSUFFICIENT_CAPACITY = 0x15, NVME_SC_NS_ID_UNAVAILABLE = 0x16, /* 0x17 - reserved */ NVME_SC_NS_ALREADY_ATTACHED = 0x18, NVME_SC_NS_IS_PRIVATE = 0x19, NVME_SC_NS_NOT_ATTACHED = 0x1a, NVME_SC_THIN_PROV_NOT_SUPPORTED = 0x1b, NVME_SC_CTRLR_LIST_INVALID = 0x1c, NVME_SC_SELT_TEST_IN_PROGRESS = 0x1d, NVME_SC_BOOT_PART_WRITE_PROHIB = 0x1e, NVME_SC_INVALID_CTRLR_ID = 0x1f, NVME_SC_INVALID_SEC_CTRLR_STATE = 0x20, NVME_SC_INVALID_NUM_OF_CTRLR_RESRC = 0x21, NVME_SC_INVALID_RESOURCE_ID = 0x22, NVME_SC_SANITIZE_PROHIBITED_WPMRE = 0x23, NVME_SC_ANA_GROUP_ID_INVALID = 0x24, NVME_SC_ANA_ATTACH_FAILED = 0x25, NVME_SC_CONFLICTING_ATTRIBUTES = 0x80, NVME_SC_INVALID_PROTECTION_INFO = 0x81, NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE = 0x82, }; /* media error status codes */ enum nvme_media_error_status_code { NVME_SC_WRITE_FAULTS = 0x80, NVME_SC_UNRECOVERED_READ_ERROR = 0x81, NVME_SC_GUARD_CHECK_ERROR = 0x82, NVME_SC_APPLICATION_TAG_CHECK_ERROR = 0x83, NVME_SC_REFERENCE_TAG_CHECK_ERROR = 0x84, NVME_SC_COMPARE_FAILURE = 0x85, NVME_SC_ACCESS_DENIED = 0x86, NVME_SC_DEALLOCATED_OR_UNWRITTEN = 0x87, }; /* path related status codes */ enum nvme_path_related_status_code { NVME_SC_INTERNAL_PATH_ERROR = 0x00, NVME_SC_ASYMMETRIC_ACCESS_PERSISTENT_LOSS = 0x01, NVME_SC_ASYMMETRIC_ACCESS_INACCESSIBLE = 0x02, NVME_SC_ASYMMETRIC_ACCESS_TRANSITION = 0x03, NVME_SC_CONTROLLER_PATHING_ERROR = 0x60, NVME_SC_HOST_PATHING_ERROR = 0x70, NVME_SC_COMMAND_ABOTHED_BY_HOST = 0x71, }; /* admin opcodes */ enum nvme_admin_opcode { NVME_OPC_DELETE_IO_SQ = 0x00, NVME_OPC_CREATE_IO_SQ = 0x01, NVME_OPC_GET_LOG_PAGE = 0x02, /* 0x03 - reserved */ NVME_OPC_DELETE_IO_CQ = 0x04, NVME_OPC_CREATE_IO_CQ = 0x05, NVME_OPC_IDENTIFY = 0x06, /* 0x07 - reserved */ NVME_OPC_ABORT = 0x08, NVME_OPC_SET_FEATURES = 0x09, NVME_OPC_GET_FEATURES = 0x0a, /* 0x0b - reserved */ NVME_OPC_ASYNC_EVENT_REQUEST = 0x0c, NVME_OPC_NAMESPACE_MANAGEMENT = 0x0d, /* 0x0e-0x0f - reserved */ NVME_OPC_FIRMWARE_ACTIVATE = 0x10, NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD = 0x11, /* 0x12-0x13 - reserved */ NVME_OPC_DEVICE_SELF_TEST = 0x14, NVME_OPC_NAMESPACE_ATTACHMENT = 0x15, /* 0x16-0x17 - reserved */ NVME_OPC_KEEP_ALIVE = 0x18, NVME_OPC_DIRECTIVE_SEND = 0x19, NVME_OPC_DIRECTIVE_RECEIVE = 0x1a, /* 0x1b - reserved */ NVME_OPC_VIRTUALIZATION_MANAGEMENT = 0x1c, NVME_OPC_NVME_MI_SEND = 0x1d, NVME_OPC_NVME_MI_RECEIVE = 0x1e, /* 0x1f-0x7b - reserved */ NVME_OPC_DOORBELL_BUFFER_CONFIG = 0x7c, NVME_OPC_FORMAT_NVM = 0x80, NVME_OPC_SECURITY_SEND = 0x81, NVME_OPC_SECURITY_RECEIVE = 0x82, /* 0x83 - reserved */ NVME_OPC_SANITIZE = 0x84, /* 0x85 - reserved */ NVME_OPC_GET_LBA_STATUS = 0x86, }; /* nvme nvm opcodes */ enum nvme_nvm_opcode { NVME_OPC_FLUSH = 0x00, NVME_OPC_WRITE = 0x01, NVME_OPC_READ = 0x02, /* 0x03 - reserved */ NVME_OPC_WRITE_UNCORRECTABLE = 0x04, NVME_OPC_COMPARE = 0x05, /* 0x06-0x07 - reserved */ NVME_OPC_WRITE_ZEROES = 0x08, NVME_OPC_DATASET_MANAGEMENT = 0x09, /* 0x0a-0x0b - reserved */ NVME_OPC_VERIFY = 0x0c, NVME_OPC_RESERVATION_REGISTER = 0x0d, NVME_OPC_RESERVATION_REPORT = 0x0e, /* 0x0f-0x10 - reserved */ NVME_OPC_RESERVATION_ACQUIRE = 0x11, /* 0x12-0x14 - reserved */ NVME_OPC_RESERVATION_RELEASE = 0x15, }; enum nvme_feature { /* 0x00 - reserved */ NVME_FEAT_ARBITRATION = 0x01, NVME_FEAT_POWER_MANAGEMENT = 0x02, NVME_FEAT_LBA_RANGE_TYPE = 0x03, NVME_FEAT_TEMPERATURE_THRESHOLD = 0x04, NVME_FEAT_ERROR_RECOVERY = 0x05, NVME_FEAT_VOLATILE_WRITE_CACHE = 0x06, NVME_FEAT_NUMBER_OF_QUEUES = 0x07, NVME_FEAT_INTERRUPT_COALESCING = 0x08, NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09, NVME_FEAT_WRITE_ATOMICITY = 0x0A, NVME_FEAT_ASYNC_EVENT_CONFIGURATION = 0x0B, NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C, NVME_FEAT_HOST_MEMORY_BUFFER = 0x0D, NVME_FEAT_TIMESTAMP = 0x0E, NVME_FEAT_KEEP_ALIVE_TIMER = 0x0F, NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT = 0x10, NVME_FEAT_NON_OP_POWER_STATE_CONFIG = 0x11, NVME_FEAT_READ_RECOVERY_LEVEL_CONFIG = 0x12, NVME_FEAT_PREDICTABLE_LATENCY_MODE_CONFIG = 0x13, NVME_FEAT_PREDICTABLE_LATENCY_MODE_WINDOW = 0x14, NVME_FEAT_LBA_STATUS_INFORMATION_ATTRIBUTES = 0x15, NVME_FEAT_HOST_BEHAVIOR_SUPPORT = 0x16, NVME_FEAT_SANITIZE_CONFIG = 0x17, NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION = 0x18, /* 0x19-0x77 - reserved */ /* 0x78-0x7f - NVMe Management Interface */ NVME_FEAT_SOFTWARE_PROGRESS_MARKER = 0x80, NVME_FEAT_HOST_IDENTIFIER = 0x81, NVME_FEAT_RESERVATION_NOTIFICATION_MASK = 0x82, NVME_FEAT_RESERVATION_PERSISTENCE = 0x83, NVME_FEAT_NAMESPACE_WRITE_PROTECTION_CONFIG = 0x84, /* 0x85-0xBF - command set specific (reserved) */ /* 0xC0-0xFF - vendor specific */ }; enum nvme_dsm_attribute { NVME_DSM_ATTR_INTEGRAL_READ = 0x1, NVME_DSM_ATTR_INTEGRAL_WRITE = 0x2, NVME_DSM_ATTR_DEALLOCATE = 0x4, }; enum nvme_activate_action { NVME_AA_REPLACE_NO_ACTIVATE = 0x0, NVME_AA_REPLACE_ACTIVATE = 0x1, NVME_AA_ACTIVATE = 0x2, }; struct nvme_power_state { /** Maximum Power */ uint16_t mp; /* Maximum Power */ uint8_t ps_rsvd1; uint8_t mps_nops; /* Max Power Scale, Non-Operational State */ uint32_t enlat; /* Entry Latency */ uint32_t exlat; /* Exit Latency */ uint8_t rrt; /* Relative Read Throughput */ uint8_t rrl; /* Relative Read Latency */ uint8_t rwt; /* Relative Write Throughput */ uint8_t rwl; /* Relative Write Latency */ uint16_t idlp; /* Idle Power */ uint8_t ips; /* Idle Power Scale */ uint8_t ps_rsvd8; uint16_t actp; /* Active Power */ uint8_t apw_aps; /* Active Power Workload, Active Power Scale */ uint8_t ps_rsvd10[9]; } __packed; _Static_assert(sizeof(struct nvme_power_state) == 32, "bad size for nvme_power_state"); #define NVME_SERIAL_NUMBER_LENGTH 20 #define NVME_MODEL_NUMBER_LENGTH 40 #define NVME_FIRMWARE_REVISION_LENGTH 8 struct nvme_controller_data { /* bytes 0-255: controller capabilities and features */ /** pci vendor id */ uint16_t vid; /** pci subsystem vendor id */ uint16_t ssvid; /** serial number */ uint8_t sn[NVME_SERIAL_NUMBER_LENGTH]; /** model number */ uint8_t mn[NVME_MODEL_NUMBER_LENGTH]; /** firmware revision */ uint8_t fr[NVME_FIRMWARE_REVISION_LENGTH]; /** recommended arbitration burst */ uint8_t rab; /** ieee oui identifier */ uint8_t ieee[3]; /** multi-interface capabilities */ uint8_t mic; /** maximum data transfer size */ uint8_t mdts; /** Controller ID */ uint16_t ctrlr_id; /** Version */ uint32_t ver; /** RTD3 Resume Latency */ uint32_t rtd3r; /** RTD3 Enter Latency */ uint32_t rtd3e; /** Optional Asynchronous Events Supported */ uint32_t oaes; /* bitfield really */ /** Controller Attributes */ uint32_t ctratt; /* bitfield really */ /** Read Recovery Levels Supported */ uint16_t rrls; uint8_t reserved1[9]; /** Controller Type */ uint8_t cntrltype; /** FRU Globally Unique Identifier */ uint8_t fguid[16]; /** Command Retry Delay Time 1 */ uint16_t crdt1; /** Command Retry Delay Time 2 */ uint16_t crdt2; /** Command Retry Delay Time 3 */ uint16_t crdt3; uint8_t reserved2[122]; /* bytes 256-511: admin command set attributes */ /** optional admin command support */ uint16_t oacs; /** abort command limit */ uint8_t acl; /** asynchronous event request limit */ uint8_t aerl; /** firmware updates */ uint8_t frmw; /** log page attributes */ uint8_t lpa; /** error log page entries */ uint8_t elpe; /** number of power states supported */ uint8_t npss; /** admin vendor specific command configuration */ uint8_t avscc; /** Autonomous Power State Transition Attributes */ uint8_t apsta; /** Warning Composite Temperature Threshold */ uint16_t wctemp; /** Critical Composite Temperature Threshold */ uint16_t cctemp; /** Maximum Time for Firmware Activation */ uint16_t mtfa; /** Host Memory Buffer Preferred Size */ uint32_t hmpre; /** Host Memory Buffer Minimum Size */ uint32_t hmmin; /** Name space capabilities */ struct { /* if nsmgmt, report tnvmcap and unvmcap */ uint8_t tnvmcap[16]; uint8_t unvmcap[16]; } __packed untncap; /** Replay Protected Memory Block Support */ uint32_t rpmbs; /* Really a bitfield */ /** Extended Device Self-test Time */ uint16_t edstt; /** Device Self-test Options */ uint8_t dsto; /* Really a bitfield */ /** Firmware Update Granularity */ uint8_t fwug; /** Keep Alive Support */ uint16_t kas; /** Host Controlled Thermal Management Attributes */ uint16_t hctma; /* Really a bitfield */ /** Minimum Thermal Management Temperature */ uint16_t mntmt; /** Maximum Thermal Management Temperature */ uint16_t mxtmt; /** Sanitize Capabilities */ uint32_t sanicap; /* Really a bitfield */ /** Host Memory Buffer Minimum Descriptor Entry Size */ uint32_t hmminds; /** Host Memory Maximum Descriptors Entries */ uint16_t hmmaxd; /** NVM Set Identifier Maximum */ uint16_t nsetidmax; /** Endurance Group Identifier Maximum */ uint16_t endgidmax; /** ANA Transition Time */ uint8_t anatt; /** Asymmetric Namespace Access Capabilities */ uint8_t anacap; /** ANA Group Identifier Maximum */ uint32_t anagrpmax; /** Number of ANA Group Identifiers */ uint32_t nanagrpid; /** Persistent Event Log Size */ uint32_t pels; uint8_t reserved3[156]; /* bytes 512-703: nvm command set attributes */ /** submission queue entry size */ uint8_t sqes; /** completion queue entry size */ uint8_t cqes; /** Maximum Outstanding Commands */ uint16_t maxcmd; /** number of namespaces */ uint32_t nn; /** optional nvm command support */ uint16_t oncs; /** fused operation support */ uint16_t fuses; /** format nvm attributes */ uint8_t fna; /** volatile write cache */ uint8_t vwc; /** Atomic Write Unit Normal */ uint16_t awun; /** Atomic Write Unit Power Fail */ uint16_t awupf; /** NVM Vendor Specific Command Configuration */ uint8_t nvscc; /** Namespace Write Protection Capabilities */ uint8_t nwpc; /** Atomic Compare & Write Unit */ uint16_t acwu; uint16_t reserved6; /** SGL Support */ uint32_t sgls; /** Maximum Number of Allowed Namespaces */ uint32_t mnan; /* bytes 540-767: Reserved */ uint8_t reserved7[224]; /** NVM Subsystem NVMe Qualified Name */ uint8_t subnqn[256]; /* bytes 1024-1791: Reserved */ uint8_t reserved8[768]; /* bytes 1792-2047: NVMe over Fabrics specification */ uint8_t reserved9[256]; /* bytes 2048-3071: power state descriptors */ struct nvme_power_state power_state[32]; /* bytes 3072-4095: vendor specific */ uint8_t vs[1024]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_controller_data) == 4096, "bad size for nvme_controller_data"); struct nvme_namespace_data { /** namespace size */ uint64_t nsze; /** namespace capacity */ uint64_t ncap; /** namespace utilization */ uint64_t nuse; /** namespace features */ uint8_t nsfeat; /** number of lba formats */ uint8_t nlbaf; /** formatted lba size */ uint8_t flbas; /** metadata capabilities */ uint8_t mc; /** end-to-end data protection capabilities */ uint8_t dpc; /** end-to-end data protection type settings */ uint8_t dps; /** Namespace Multi-path I/O and Namespace Sharing Capabilities */ uint8_t nmic; /** Reservation Capabilities */ uint8_t rescap; /** Format Progress Indicator */ uint8_t fpi; /** Deallocate Logical Block Features */ uint8_t dlfeat; /** Namespace Atomic Write Unit Normal */ uint16_t nawun; /** Namespace Atomic Write Unit Power Fail */ uint16_t nawupf; /** Namespace Atomic Compare & Write Unit */ uint16_t nacwu; /** Namespace Atomic Boundary Size Normal */ uint16_t nabsn; /** Namespace Atomic Boundary Offset */ uint16_t nabo; /** Namespace Atomic Boundary Size Power Fail */ uint16_t nabspf; /** Namespace Optimal IO Boundary */ uint16_t noiob; /** NVM Capacity */ uint8_t nvmcap[16]; /** Namespace Preferred Write Granularity */ uint16_t npwg; /** Namespace Preferred Write Alignment */ uint16_t npwa; /** Namespace Preferred Deallocate Granularity */ uint16_t npdg; /** Namespace Preferred Deallocate Alignment */ uint16_t npda; /** Namespace Optimal Write Size */ uint16_t nows; /* bytes 74-91: Reserved */ uint8_t reserved5[18]; /** ANA Group Identifier */ uint32_t anagrpid; /* bytes 96-98: Reserved */ uint8_t reserved6[3]; /** Namespace Attributes */ uint8_t nsattr; /** NVM Set Identifier */ uint16_t nvmsetid; /** Endurance Group Identifier */ uint16_t endgid; /** Namespace Globally Unique Identifier */ uint8_t nguid[16]; /** IEEE Extended Unique Identifier */ uint8_t eui64[8]; /** lba format support */ uint32_t lbaf[16]; uint8_t reserved7[192]; uint8_t vendor_specific[3712]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_namespace_data) == 4096, "bad size for nvme_namepsace_data"); enum nvme_log_page { /* 0x00 - reserved */ NVME_LOG_ERROR = 0x01, NVME_LOG_HEALTH_INFORMATION = 0x02, NVME_LOG_FIRMWARE_SLOT = 0x03, NVME_LOG_CHANGED_NAMESPACE = 0x04, NVME_LOG_COMMAND_EFFECT = 0x05, NVME_LOG_DEVICE_SELF_TEST = 0x06, NVME_LOG_TELEMETRY_HOST_INITIATED = 0x07, NVME_LOG_TELEMETRY_CONTROLLER_INITIATED = 0x08, NVME_LOG_ENDURANCE_GROUP_INFORMATION = 0x09, NVME_LOG_PREDICTABLE_LATENCY_PER_NVM_SET = 0x0a, NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE = 0x0b, NVME_LOG_ASYMMETRIC_NAMESPAVE_ACCESS = 0x0c, NVME_LOG_PERSISTENT_EVENT_LOG = 0x0d, NVME_LOG_LBA_STATUS_INFORMATION = 0x0e, NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE = 0x0f, /* 0x06-0x7F - reserved */ /* 0x80-0xBF - I/O command set specific */ NVME_LOG_RES_NOTIFICATION = 0x80, NVME_LOG_SANITIZE_STATUS = 0x81, /* 0x82-0xBF - reserved */ /* 0xC0-0xFF - vendor specific */ /* * The following are Intel Specific log pages, but they seem * to be widely implemented. */ INTEL_LOG_READ_LAT_LOG = 0xc1, INTEL_LOG_WRITE_LAT_LOG = 0xc2, INTEL_LOG_TEMP_STATS = 0xc5, INTEL_LOG_ADD_SMART = 0xca, INTEL_LOG_DRIVE_MKT_NAME = 0xdd, /* * HGST log page, with lots ofs sub pages. */ HGST_INFO_LOG = 0xc1, }; struct nvme_error_information_entry { uint64_t error_count; uint16_t sqid; uint16_t cid; uint16_t status; uint16_t error_location; uint64_t lba; uint32_t nsid; uint8_t vendor_specific; uint8_t trtype; uint16_t reserved30; uint64_t csi; uint16_t ttsi; uint8_t reserved[22]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_error_information_entry) == 64, "bad size for nvme_error_information_entry"); struct nvme_health_information_page { uint8_t critical_warning; uint16_t temperature; uint8_t available_spare; uint8_t available_spare_threshold; uint8_t percentage_used; uint8_t reserved[26]; /* * Note that the following are 128-bit values, but are * defined as an array of 2 64-bit values. */ /* Data Units Read is always in 512-byte units. */ uint64_t data_units_read[2]; /* Data Units Written is always in 512-byte units. */ uint64_t data_units_written[2]; /* For NVM command set, this includes Compare commands. */ uint64_t host_read_commands[2]; uint64_t host_write_commands[2]; /* Controller Busy Time is reported in minutes. */ uint64_t controller_busy_time[2]; uint64_t power_cycles[2]; uint64_t power_on_hours[2]; uint64_t unsafe_shutdowns[2]; uint64_t media_errors[2]; uint64_t num_error_info_log_entries[2]; uint32_t warning_temp_time; uint32_t error_temp_time; uint16_t temp_sensor[8]; /* Thermal Management Temperature 1 Transition Count */ uint32_t tmt1tc; /* Thermal Management Temperature 2 Transition Count */ uint32_t tmt2tc; /* Total Time For Thermal Management Temperature 1 */ uint32_t ttftmt1; /* Total Time For Thermal Management Temperature 2 */ uint32_t ttftmt2; uint8_t reserved2[280]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_health_information_page) == 512, "bad size for nvme_health_information_page"); struct nvme_firmware_page { uint8_t afi; uint8_t reserved[7]; uint64_t revision[7]; /* revisions for 7 slots */ uint8_t reserved2[448]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_firmware_page) == 512, "bad size for nvme_firmware_page"); struct nvme_ns_list { uint32_t ns[1024]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_ns_list) == 4096, "bad size for nvme_ns_list"); struct nvme_command_effects_page { uint32_t acs[256]; uint32_t iocs[256]; uint8_t reserved[2048]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_command_effects_page) == 4096, "bad size for nvme_command_effects_page"); struct nvme_res_notification_page { uint64_t log_page_count; uint8_t log_page_type; uint8_t available_log_pages; uint8_t reserved2; uint32_t nsid; uint8_t reserved[48]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_res_notification_page) == 64, "bad size for nvme_res_notification_page"); struct nvme_sanitize_status_page { uint16_t sprog; uint16_t sstat; uint32_t scdw10; uint32_t etfo; uint32_t etfbe; uint32_t etfce; uint32_t etfownd; uint32_t etfbewnd; uint32_t etfcewnd; uint8_t reserved[480]; } __packed __aligned(4); _Static_assert(sizeof(struct nvme_sanitize_status_page) == 512, "bad size for nvme_sanitize_status_page"); struct intel_log_temp_stats { uint64_t current; uint64_t overtemp_flag_last; uint64_t overtemp_flag_life; uint64_t max_temp; uint64_t min_temp; uint64_t _rsvd[5]; uint64_t max_oper_temp; uint64_t min_oper_temp; uint64_t est_offset; } __packed __aligned(4); _Static_assert(sizeof(struct intel_log_temp_stats) == 13 * 8, "bad size for intel_log_temp_stats"); +struct nvme_resv_reg_ctrlr +{ + uint16_t ctrlr_id; /* Controller ID */ + uint8_t rcsts; /* Reservation Status */ + uint8_t reserved3[5]; + uint64_t hostid; /* Host Identifier */ + uint64_t rkey; /* Reservation Key */ +} __packed __aligned(4); + +_Static_assert(sizeof(struct nvme_resv_reg_ctrlr) == 24, "bad size for nvme_resv_reg_ctrlr"); + +struct nvme_resv_reg_ctrlr_ext +{ + uint16_t ctrlr_id; /* Controller ID */ + uint8_t rcsts; /* Reservation Status */ + uint8_t reserved3[5]; + uint64_t rkey; /* Reservation Key */ + uint64_t hostid[2]; /* Host Identifier */ + uint8_t reserved32[32]; +} __packed __aligned(4); + +_Static_assert(sizeof(struct nvme_resv_reg_ctrlr_ext) == 64, "bad size for nvme_resv_reg_ctrlr_ext"); + +struct nvme_resv_status +{ + uint32_t gen; /* Generation */ + uint8_t rtype; /* Reservation Type */ + uint8_t regctl[2]; /* Number of Registered Controllers */ + uint8_t reserved7[2]; + uint8_t ptpls; /* Persist Through Power Loss State */ + uint8_t reserved10[14]; + struct nvme_resv_reg_ctrlr ctrlr[0]; +} __packed __aligned(4); + +_Static_assert(sizeof(struct nvme_resv_status) == 24, "bad size for nvme_resv_status"); + +struct nvme_resv_status_ext +{ + uint32_t gen; /* Generation */ + uint8_t rtype; /* Reservation Type */ + uint8_t regctl[2]; /* Number of Registered Controllers */ + uint8_t reserved7[2]; + uint8_t ptpls; /* Persist Through Power Loss State */ + uint8_t reserved10[14]; + uint8_t reserved24[40]; + struct nvme_resv_reg_ctrlr_ext ctrlr[0]; +} __packed __aligned(4); + +_Static_assert(sizeof(struct nvme_resv_status_ext) == 64, "bad size for nvme_resv_status_ext"); + #define NVME_TEST_MAX_THREADS 128 struct nvme_io_test { enum nvme_nvm_opcode opc; uint32_t size; uint32_t time; /* in seconds */ uint32_t num_threads; uint32_t flags; uint64_t io_completed[NVME_TEST_MAX_THREADS]; }; enum nvme_io_test_flags { /* * Specifies whether dev_refthread/dev_relthread should be * called during NVME_BIO_TEST. Ignored for other test * types. */ NVME_TEST_FLAG_REFTHREAD = 0x1, }; struct nvme_pt_command { /* * cmd is used to specify a passthrough command to a controller or * namespace. * * The following fields from cmd may be specified by the caller: * * opc (opcode) * * nsid (namespace id) - for admin commands only * * cdw10-cdw15 * * Remaining fields must be set to 0 by the caller. */ struct nvme_command cmd; /* * cpl returns completion status for the passthrough command * specified by cmd. * * The following fields will be filled out by the driver, for * consumption by the caller: * * cdw0 * * status (except for phase) * * Remaining fields will be set to 0 by the driver. */ struct nvme_completion cpl; /* buf is the data buffer associated with this passthrough command. */ void * buf; /* * len is the length of the data buffer associated with this * passthrough command. */ uint32_t len; /* * is_read = 1 if the passthrough command will read data into the * supplied buffer from the controller. * * is_read = 0 if the passthrough command will write data from the * supplied buffer to the controller. */ uint32_t is_read; /* * driver_lock is used by the driver only. It must be set to 0 * by the caller. */ struct mtx * driver_lock; }; struct nvme_get_nsid { char cdev[SPECNAMELEN + 1]; uint32_t nsid; }; #define nvme_completion_is_error(cpl) \ (NVME_STATUS_GET_SC((cpl)->status) != 0 || NVME_STATUS_GET_SCT((cpl)->status) != 0) void nvme_strvis(uint8_t *dst, const uint8_t *src, int dstlen, int srclen); #ifdef _KERNEL struct bio; struct thread; struct nvme_namespace; struct nvme_controller; struct nvme_consumer; typedef void (*nvme_cb_fn_t)(void *, const struct nvme_completion *); typedef void *(*nvme_cons_ns_fn_t)(struct nvme_namespace *, void *); typedef void *(*nvme_cons_ctrlr_fn_t)(struct nvme_controller *); typedef void (*nvme_cons_async_fn_t)(void *, const struct nvme_completion *, uint32_t, void *, uint32_t); typedef void (*nvme_cons_fail_fn_t)(void *); enum nvme_namespace_flags { NVME_NS_DEALLOCATE_SUPPORTED = 0x1, NVME_NS_FLUSH_SUPPORTED = 0x2, }; int nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr, struct nvme_pt_command *pt, uint32_t nsid, int is_user_buffer, int is_admin_cmd); /* Admin functions */ void nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature, uint32_t cdw11, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, void *cb_arg); void nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature, uint32_t cdw11, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, void *cb_arg); void nvme_ctrlr_cmd_get_log_page(struct nvme_controller *ctrlr, uint8_t log_page, uint32_t nsid, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, void *cb_arg); /* NVM I/O functions */ int nvme_ns_cmd_write(struct nvme_namespace *ns, void *payload, uint64_t lba, uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_write_bio(struct nvme_namespace *ns, struct bio *bp, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_read(struct nvme_namespace *ns, void *payload, uint64_t lba, uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_read_bio(struct nvme_namespace *ns, struct bio *bp, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload, uint8_t num_ranges, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_dump(struct nvme_namespace *ns, void *virt, off_t offset, size_t len); /* Registration functions */ struct nvme_consumer * nvme_register_consumer(nvme_cons_ns_fn_t ns_fn, nvme_cons_ctrlr_fn_t ctrlr_fn, nvme_cons_async_fn_t async_fn, nvme_cons_fail_fn_t fail_fn); void nvme_unregister_consumer(struct nvme_consumer *consumer); /* Controller helper functions */ device_t nvme_ctrlr_get_device(struct nvme_controller *ctrlr); const struct nvme_controller_data * nvme_ctrlr_get_data(struct nvme_controller *ctrlr); static inline bool nvme_ctrlr_has_dataset_mgmt(const struct nvme_controller_data *cd) { /* Assumes cd was byte swapped by nvme_controller_data_swapbytes() */ return ((cd->oncs >> NVME_CTRLR_DATA_ONCS_DSM_SHIFT) & NVME_CTRLR_DATA_ONCS_DSM_MASK); } /* Namespace helper functions */ uint32_t nvme_ns_get_max_io_xfer_size(struct nvme_namespace *ns); uint32_t nvme_ns_get_sector_size(struct nvme_namespace *ns); uint64_t nvme_ns_get_num_sectors(struct nvme_namespace *ns); uint64_t nvme_ns_get_size(struct nvme_namespace *ns); uint32_t nvme_ns_get_flags(struct nvme_namespace *ns); const char * nvme_ns_get_serial_number(struct nvme_namespace *ns); const char * nvme_ns_get_model_number(struct nvme_namespace *ns); const struct nvme_namespace_data * nvme_ns_get_data(struct nvme_namespace *ns); uint32_t nvme_ns_get_stripesize(struct nvme_namespace *ns); int nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp, nvme_cb_fn_t cb_fn); int nvme_ns_ioctl_process(struct nvme_namespace *ns, u_long cmd, caddr_t arg, int flag, struct thread *td); /* * Command building helper functions -- shared with CAM * These functions assume allocator zeros out cmd structure * CAM's xpt_get_ccb and the request allocator for nvme both * do zero'd allocations. */ static inline void nvme_ns_flush_cmd(struct nvme_command *cmd, uint32_t nsid) { cmd->opc = NVME_OPC_FLUSH; cmd->nsid = htole32(nsid); } static inline void nvme_ns_rw_cmd(struct nvme_command *cmd, uint32_t rwcmd, uint32_t nsid, uint64_t lba, uint32_t count) { cmd->opc = rwcmd; cmd->nsid = htole32(nsid); cmd->cdw10 = htole32(lba & 0xffffffffu); cmd->cdw11 = htole32(lba >> 32); cmd->cdw12 = htole32(count-1); } static inline void nvme_ns_write_cmd(struct nvme_command *cmd, uint32_t nsid, uint64_t lba, uint32_t count) { nvme_ns_rw_cmd(cmd, NVME_OPC_WRITE, nsid, lba, count); } static inline void nvme_ns_read_cmd(struct nvme_command *cmd, uint32_t nsid, uint64_t lba, uint32_t count) { nvme_ns_rw_cmd(cmd, NVME_OPC_READ, nsid, lba, count); } static inline void nvme_ns_trim_cmd(struct nvme_command *cmd, uint32_t nsid, uint32_t num_ranges) { cmd->opc = NVME_OPC_DATASET_MANAGEMENT; cmd->nsid = htole32(nsid); cmd->cdw10 = htole32(num_ranges - 1); cmd->cdw11 = htole32(NVME_DSM_ATTR_DEALLOCATE); } extern int nvme_use_nvd; #endif /* _KERNEL */ /* Endianess conversion functions for NVMe structs */ static inline void nvme_completion_swapbytes(struct nvme_completion *s) { s->cdw0 = le32toh(s->cdw0); /* omit rsvd1 */ s->sqhd = le16toh(s->sqhd); s->sqid = le16toh(s->sqid); /* omit cid */ s->status = le16toh(s->status); } static inline void nvme_power_state_swapbytes(struct nvme_power_state *s) { s->mp = le16toh(s->mp); s->enlat = le32toh(s->enlat); s->exlat = le32toh(s->exlat); s->idlp = le16toh(s->idlp); s->actp = le16toh(s->actp); } static inline void nvme_controller_data_swapbytes(struct nvme_controller_data *s) { int i; s->vid = le16toh(s->vid); s->ssvid = le16toh(s->ssvid); s->ctrlr_id = le16toh(s->ctrlr_id); s->ver = le32toh(s->ver); s->rtd3r = le32toh(s->rtd3r); s->rtd3e = le32toh(s->rtd3e); s->oaes = le32toh(s->oaes); s->ctratt = le32toh(s->ctratt); s->rrls = le16toh(s->rrls); s->crdt1 = le16toh(s->crdt1); s->crdt2 = le16toh(s->crdt2); s->crdt3 = le16toh(s->crdt3); s->oacs = le16toh(s->oacs); s->wctemp = le16toh(s->wctemp); s->cctemp = le16toh(s->cctemp); s->mtfa = le16toh(s->mtfa); s->hmpre = le32toh(s->hmpre); s->hmmin = le32toh(s->hmmin); s->rpmbs = le32toh(s->rpmbs); s->edstt = le16toh(s->edstt); s->kas = le16toh(s->kas); s->hctma = le16toh(s->hctma); s->mntmt = le16toh(s->mntmt); s->mxtmt = le16toh(s->mxtmt); s->sanicap = le32toh(s->sanicap); s->hmminds = le32toh(s->hmminds); s->hmmaxd = le16toh(s->hmmaxd); s->nsetidmax = le16toh(s->nsetidmax); s->endgidmax = le16toh(s->endgidmax); s->anagrpmax = le32toh(s->anagrpmax); s->nanagrpid = le32toh(s->nanagrpid); s->pels = le32toh(s->pels); s->maxcmd = le16toh(s->maxcmd); s->nn = le32toh(s->nn); s->oncs = le16toh(s->oncs); s->fuses = le16toh(s->fuses); s->awun = le16toh(s->awun); s->awupf = le16toh(s->awupf); s->acwu = le16toh(s->acwu); s->sgls = le32toh(s->sgls); s->mnan = le32toh(s->mnan); for (i = 0; i < 32; i++) nvme_power_state_swapbytes(&s->power_state[i]); } static inline void nvme_namespace_data_swapbytes(struct nvme_namespace_data *s) { int i; s->nsze = le64toh(s->nsze); s->ncap = le64toh(s->ncap); s->nuse = le64toh(s->nuse); s->nawun = le16toh(s->nawun); s->nawupf = le16toh(s->nawupf); s->nacwu = le16toh(s->nacwu); s->nabsn = le16toh(s->nabsn); s->nabo = le16toh(s->nabo); s->nabspf = le16toh(s->nabspf); s->noiob = le16toh(s->noiob); s->npwg = le16toh(s->npwg); s->npwa = le16toh(s->npwa); s->npdg = le16toh(s->npdg); s->npda = le16toh(s->npda); s->nows = le16toh(s->nows); s->anagrpid = le32toh(s->anagrpid); s->nvmsetid = le16toh(s->nvmsetid); s->endgid = le16toh(s->endgid); for (i = 0; i < 16; i++) s->lbaf[i] = le32toh(s->lbaf[i]); } static inline void nvme_error_information_entry_swapbytes(struct nvme_error_information_entry *s) { s->error_count = le64toh(s->error_count); s->sqid = le16toh(s->sqid); s->cid = le16toh(s->cid); s->status = le16toh(s->status); s->error_location = le16toh(s->error_location); s->lba = le64toh(s->lba); s->nsid = le32toh(s->nsid); s->csi = le64toh(s->csi); s->ttsi = le16toh(s->ttsi); } static inline void nvme_le128toh(void *p) { #if _BYTE_ORDER != _LITTLE_ENDIAN /* Swap 16 bytes in place */ char *tmp = (char*)p; char b; int i; for (i = 0; i < 8; i++) { b = tmp[i]; tmp[i] = tmp[15-i]; tmp[15-i] = b; } #else (void)p; #endif } static inline void nvme_health_information_page_swapbytes(struct nvme_health_information_page *s) { int i; s->temperature = le16toh(s->temperature); nvme_le128toh((void *)s->data_units_read); nvme_le128toh((void *)s->data_units_written); nvme_le128toh((void *)s->host_read_commands); nvme_le128toh((void *)s->host_write_commands); nvme_le128toh((void *)s->controller_busy_time); nvme_le128toh((void *)s->power_cycles); nvme_le128toh((void *)s->power_on_hours); nvme_le128toh((void *)s->unsafe_shutdowns); nvme_le128toh((void *)s->media_errors); nvme_le128toh((void *)s->num_error_info_log_entries); s->warning_temp_time = le32toh(s->warning_temp_time); s->error_temp_time = le32toh(s->error_temp_time); for (i = 0; i < 8; i++) s->temp_sensor[i] = le16toh(s->temp_sensor[i]); s->tmt1tc = le32toh(s->tmt1tc); s->tmt2tc = le32toh(s->tmt2tc); s->ttftmt1 = le32toh(s->ttftmt1); s->ttftmt2 = le32toh(s->ttftmt2); } static inline void nvme_firmware_page_swapbytes(struct nvme_firmware_page *s) { int i; for (i = 0; i < 7; i++) s->revision[i] = le64toh(s->revision[i]); } static inline void nvme_ns_list_swapbytes(struct nvme_ns_list *s) { int i; for (i = 0; i < 1024; i++) s->ns[i] = le32toh(s->ns[i]); } static inline void nvme_command_effects_page_swapbytes(struct nvme_command_effects_page *s) { int i; for (i = 0; i < 256; i++) s->acs[i] = le32toh(s->acs[i]); for (i = 0; i < 256; i++) s->iocs[i] = le32toh(s->iocs[i]); } static inline void nvme_res_notification_page_swapbytes(struct nvme_res_notification_page *s) { s->log_page_count = le64toh(s->log_page_count); s->nsid = le32toh(s->nsid); } static inline void nvme_sanitize_status_page_swapbytes(struct nvme_sanitize_status_page *s) { s->sprog = le16toh(s->sprog); s->sstat = le16toh(s->sstat); s->scdw10 = le32toh(s->scdw10); s->etfo = le32toh(s->etfo); s->etfbe = le32toh(s->etfbe); s->etfce = le32toh(s->etfce); s->etfownd = le32toh(s->etfownd); s->etfbewnd = le32toh(s->etfbewnd); s->etfcewnd = le32toh(s->etfcewnd); } static inline void intel_log_temp_stats_swapbytes(struct intel_log_temp_stats *s) { s->current = le64toh(s->current); s->overtemp_flag_last = le64toh(s->overtemp_flag_last); s->overtemp_flag_life = le64toh(s->overtemp_flag_life); s->max_temp = le64toh(s->max_temp); s->min_temp = le64toh(s->min_temp); /* omit _rsvd[] */ s->max_oper_temp = le64toh(s->max_oper_temp); s->min_oper_temp = le64toh(s->min_oper_temp); s->est_offset = le64toh(s->est_offset); +} + +static inline +void nvme_resv_status_swapbytes(struct nvme_resv_status *s, size_t size) +{ + u_int i, n; + + s->gen = le32toh(s->gen); + n = (s->regctl[1] << 8) | s->regctl[0]; + n = MIN(n, (size - sizeof(s)) / sizeof(s->ctrlr[0])); + for (i = 0; i < n; i++) { + s->ctrlr[i].ctrlr_id = le16toh(s->ctrlr[i].ctrlr_id); + s->ctrlr[i].hostid = le64toh(s->ctrlr[i].hostid); + s->ctrlr[i].rkey = le64toh(s->ctrlr[i].rkey); + } +} + +static inline +void nvme_resv_status_ext_swapbytes(struct nvme_resv_status_ext *s, size_t size) +{ + u_int i, n; + + s->gen = le32toh(s->gen); + n = (s->regctl[1] << 8) | s->regctl[0]; + n = MIN(n, (size - sizeof(s)) / sizeof(s->ctrlr[0])); + for (i = 0; i < n; i++) { + s->ctrlr[i].ctrlr_id = le16toh(s->ctrlr[i].ctrlr_id); + s->ctrlr[i].rkey = le64toh(s->ctrlr[i].rkey); + nvme_le128toh((void *)s->ctrlr[i].hostid); + } } #endif /* __NVME_H__ */