Am Sun, May 26, 2024 at 10:56:05AM -0400 schrieb Kenneth Westerback: > The diff below enables smartmontools (smartctl & smartd) support for > NVMe disks on -current kernels with the latest nvme(4) passthrough > commits. > > Obvious features tested and work for me on various amd64 boxes and my m1 > macmini. > > ian@ has also succesfully tested it. > > Thoughts? OK? Works on my system as well. (Own only a single nvme driven box)
> -- > .... Ken > > Index: Makefile > =================================================================== > RCS file: /cvs/ports/sysutils/smartmontools/Makefile,v > diff -u -p -u -p -r1.50 Makefile > --- Makefile 27 Sep 2023 17:16:34 -0000 1.50 > +++ Makefile 26 May 2024 14:54:25 -0000 > @@ -2,6 +2,7 @@ COMMENT= control and monitor storage sy > > # XXX at update time check whether C++11 is actually needed > DISTNAME= smartmontools-7.4 > +REVISION= 0 > CATEGORIES= sysutils > > HOMEPAGE= https://www.smartmontools.org/ > Index: patches/patch-openbsd_nvme_ioctl_h > =================================================================== > RCS file: patches/patch-openbsd_nvme_ioctl_h > diff -N patches/patch-openbsd_nvme_ioctl_h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-openbsd_nvme_ioctl_h 26 May 2024 14:54:25 -0000 > @@ -0,0 +1,78 @@ > +Index: openbsd_nvme_ioctl.h > +--- openbsd_nvme_ioctl.h.orig > ++++ openbsd_nvme_ioctl.h > +@@ -0,0 +1,74 @@ > ++/* > ++ * Copyright (c) 2024 Kenneth R Westerback <k...@openbsd.org> > ++ * > ++ * Permission to use, copy, modify, and distribute this software for any > ++ * purpose with or without fee is hereby granted, provided that the above > ++ * copyright notice and this permission notice appear in all copies. > ++ * > ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > ++ */ > ++ > ++#define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct > nvme_pt_cmd) > ++ > ++struct nvme_pt_status { > ++ int ps_dv_unit; > ++ int ps_nsid; > ++ int ps_flags; > ++#define NVME_CQE_SCT(_f) ((_f) & (0x07 << 9)) > ++#define NVME_CQE_SCT_GENERIC (0x00 << 9) > ++#define NVME_CQE_SC(_f) ((_f) & (0xff << 1)) > ++#define NVME_CQE_SC_SUCCESS (0x00 << 1) > ++ uint32_t ps_csts; > ++ uint32_t ps_cc; > ++}; > ++ > ++#define BIO_MSG_COUNT 5 > ++#define BIO_MSG_LEN 128 > ++ > ++struct bio_msg { > ++ int bm_type; > ++ char bm_msg[BIO_MSG_LEN]; > ++}; > ++ > ++struct bio_status { > ++ char bs_controller[16]; > ++ int bs_status; > ++ int bs_msg_count; > ++ struct bio_msg bs_msgs[BIO_MSG_COUNT]; > ++}; > ++ > ++struct bio { > ++ void *bio_cookie; > ++ struct bio_status bio_status; > ++}; > ++ > ++struct nvme_pt_cmd { > ++ /* Commands may arrive via /dev/bio. */ > ++ struct bio pt_bio; > ++ > ++ /* The sqe fields that the caller may specify. */ > ++ uint8_t pt_opcode; > ++ uint32_t pt_nsid; > ++ uint32_t pt_cdw10; > ++ uint32_t pt_cdw11; > ++ uint32_t pt_cdw12; > ++ uint32_t pt_cdw13; > ++ uint32_t pt_cdw14; > ++ uint32_t pt_cdw15; > ++ > ++ caddr_t pt_status; > ++ uint32_t pt_statuslen; > ++ > ++ caddr_t pt_databuf; /* User space address. */ > ++ uint32_t pt_databuflen; /* Length of buffer. */ > ++}; > ++ > ++#define nvme_completion_is_error(_flags) > \ > ++ ((NVME_CQE_SC(_flags) != NVME_CQE_SC_SUCCESS) \ > ++ || (NVME_CQE_SCT(_flags) != NVME_CQE_SCT_GENERIC)) > Index: patches/patch-os_openbsd_cpp > =================================================================== > RCS file: patches/patch-os_openbsd_cpp > diff -N patches/patch-os_openbsd_cpp > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-os_openbsd_cpp 26 May 2024 14:54:25 -0000 > @@ -0,0 +1,196 @@ > +Index: os_openbsd.cpp > +--- os_openbsd.cpp.orig > ++++ os_openbsd.cpp > +@@ -14,6 +14,7 @@ > + > + #include "atacmds.h" > + #include "scsicmds.h" > ++#include "nvmecmds.h" > + #include "utility.h" > + #include "os_openbsd.h" > + > +@@ -22,11 +23,29 @@ > + #include <sys/stat.h> > + #include <util.h> > + > ++// based on OpenBSD "/usr/include/dev/ic/nvmeio.h" && > "/usr/include/dev/biovar.h" > ++#include "openbsd_nvme_ioctl.h" // NVME_PASSTHROUGH_CMD, > nvme_completion_is_error > + const char * os_openbsd_cpp_cvsid = "$Id: os_openbsd.cpp 5393 2022-05-29 > 05:08:10Z dpgilbert $" > + OS_OPENBSD_H_CVSID; > + > + #define ARGUSED(x) ((void)(x)) > + > ++bool sd_is_nvme(const char *dev) > ++{ > ++ struct nvme_pt_cmd pt; > ++ memset(&pt, 0, sizeof(pt)); > ++ pt.pt_opcode = smartmontools::nvme_admin_identify; > ++ > ++ int fd = ::open(dev, O_RDWR); > ++ if (fd == -1) > ++ return false; > ++ > ++ int status = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt); > ++ close(fd); > ++ > ++ return status != -1 || errno != ENOTTY; > ++} > ++ > + > ///////////////////////////////////////////////////////////////////////////// > + > + namespace os_openbsd { // No need to publish anything, name provided for > Doxygen > +@@ -209,6 +228,80 @@ bool openbsd_ata_device::ata_pass_through(const ata_cm > + } > + > + > ///////////////////////////////////////////////////////////////////////////// > ++/// NVMe support > ++ > ++class openbsd_nvme_device > ++: public /*implements*/ nvme_device, > ++ public /*extends*/ openbsd_smart_device > ++{ > ++public: > ++ openbsd_nvme_device(smart_interface * intf, const char * dev_name, > ++ const char * req_type, unsigned nsid); > ++ > ++ virtual bool open() override; > ++ > ++ virtual bool nvme_pass_through(const nvme_cmd_in & in, nvme_cmd_out & > out) override; > ++}; > ++ > ++openbsd_nvme_device::openbsd_nvme_device(smart_interface * intf, const char > * dev_name, > ++ const char * req_type, unsigned nsid) > ++: smart_device(intf, dev_name, "nvme", req_type), > ++ nvme_device(nsid), > ++ openbsd_smart_device() > ++{ > ++} > ++ > ++bool openbsd_nvme_device::open() > ++{ > ++ const char *dev = get_dev_name(); > ++ int fd; > ++ > ++ if ((fd = ::open(dev, O_RDWR)) == -1) { > ++ set_err(errno, "can't open sd device"); > ++ return false; > ++ } > ++ > ++ set_fd(fd); > ++ > ++ return true; > ++} > ++ > ++bool openbsd_nvme_device::nvme_pass_through(const nvme_cmd_in & in, > nvme_cmd_out & out) > ++{ > ++ struct nvme_pt_cmd pt; > ++ struct nvme_pt_status ps; > ++ > ++ memset(&ps, 0, sizeof(ps)); > ++ memset(&pt.pt_bio, 0, sizeof(pt.pt_bio)); > ++ > ++ pt.pt_opcode = in.opcode; > ++ pt.pt_nsid = in.nsid; > ++ pt.pt_databuf = (caddr_t)in.buffer; > ++ pt.pt_databuflen = in.size; > ++ pt.pt_cdw10 = in.cdw10; > ++ pt.pt_cdw11 = in.cdw11; > ++ pt.pt_cdw12 = in.cdw12; > ++ pt.pt_cdw13 = in.cdw13; > ++ pt.pt_cdw14 = in.cdw14; > ++ pt.pt_cdw15 = in.cdw15; > ++ pt.pt_status = (char *)&ps; > ++ pt.pt_statuslen = sizeof(ps); > ++ > ++ int status = ioctl(get_fd(), NVME_PASSTHROUGH_CMD, &pt); > ++ > ++ if (status == -1) > ++ return set_err(errno, "NVME_PASSTHROUGH_CMD: %s", strerror(errno)); > ++ > ++ out.result = 0; // cqe.cdw0 (Command specific result) is not provided > ++ > ++ if (nvme_completion_is_error(ps.ps_flags)) > ++ return set_nvme_err(out, nvme_completion_is_error(ps.ps_flags)); > ++ > ++ return true; > ++} > ++ > ++ > ++///////////////////////////////////////////////////////////////////////////// > + /// Standard SCSI support > + > + class openbsd_scsi_device > +@@ -381,6 +474,9 @@ class openbsd_smart_interface (protected) > + > + virtual scsi_device * get_scsi_device(const char * name, const char * > type) override; > + > ++ virtual nvme_device * get_nvme_device(const char * name, const char * > type, > ++ unsigned nsid) override; > ++ > + virtual smart_device * autodetect_smart_device(const char * name) > override; > + > + virtual smart_device * get_custom_smart_device(const char * name, const > char * type) override; > +@@ -434,6 +530,11 @@ scsi_device * openbsd_smart_interface::get_scsi_device > + return new openbsd_scsi_device(this, name, type); > + } > + > ++nvme_device * openbsd_smart_interface::get_nvme_device(const char * name, > const char * type, unsigned nsid) > ++{ > ++ return new openbsd_nvme_device(this, name, type, nsid); > ++} > ++ > + int openbsd_smart_interface::get_dev_names(char ***names, const char > *prefix) > + { > + char *disknames, *p, **mp; > +@@ -504,6 +605,7 @@ bool openbsd_smart_interface::scan_smart_devices(smart > + > + bool scan_ata = !*type || !strcmp(type, "ata"); > + bool scan_scsi = !*type || !strcmp(type, "scsi") || !strcmp(type, > "sat"); > ++ bool scan_nvme = !*type || !strcmp(type, "nvme"); > + > + // Make namelists > + char * * atanames = 0; int numata = 0; > +@@ -517,7 +619,7 @@ bool openbsd_smart_interface::scan_smart_devices(smart > + > + char * * scsinames = 0; int numscsi = 0; > + char * * scsitapenames = 0; int numscsitape = 0; > +- if (scan_scsi) { > ++ if (scan_scsi || scan_nvme) { > + numscsi = get_dev_names(&scsinames, net_dev_scsi_disk); > + if (numscsi < 0) { > + set_err(ENOMEM); > +@@ -541,9 +643,17 @@ bool openbsd_smart_interface::scan_smart_devices(smart > + if(numata) free(atanames); > + > + for (i = 0; i < numscsi; i++) { > +- scsi_device * scsidev = new openbsd_scsi_device(this, scsinames[i], > type, true /*scanning*/); > +- if (scsidev) > +- devlist.push_back(scsidev); > ++ if (sd_is_nvme(scsinames[i])) { > ++ if (scan_nvme) { > ++ nvme_device * nvmedev = new openbsd_nvme_device(this, > scsinames[i], type, true /*scanning*/); > ++ if (nvmedev) > ++ devlist.push_back(nvmedev); > ++ } > ++ } else if (scan_scsi) { > ++ scsi_device * scsidev = new openbsd_scsi_device(this, scsinames[i], > type, true /*scanning*/); > ++ if (scsidev) > ++ devlist.push_back(scsidev); > ++ } > + free(scsinames[i]); > + } > + if(numscsi) free(scsinames); > +@@ -588,8 +698,11 @@ smart_device * openbsd_smart_interface::autodetect_sma > + // XXX get USB vendor ID, product ID and version from sd(4)/umass(4). > + // XXX check sat device via get_usb_dev_type_by_id(). > + > +- // No USB bridge found, assume regular SCSI or SAT device > +- return get_scsi_device(name, ""); > ++ // No USB bridge found, decide if it's NVME or regular SCSI or SAT > device > ++ if (sd_is_nvme(name)) > ++ return get_nvme_device(name, "nvme", 0); > ++ else > ++ return get_scsi_device(name, ""); > + } > + if (!strncmp(net_dev_scsi_tape, test_name, strlen(net_dev_scsi_tape))) > + return get_scsi_device(name, "scsi"); > Index: patches/patch-smartctl_8_in > =================================================================== > RCS file: patches/patch-smartctl_8_in > diff -N patches/patch-smartctl_8_in > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-smartctl_8_in 26 May 2024 14:54:25 -0000 > @@ -0,0 +1,170 @@ > +Index: smartctl.8.in > +--- smartctl.8.in.orig > ++++ smartctl.8.in > +@@ -233,11 +233,11 @@ in the smartmontools database (see \*(Aq\-v\*(Aq optio > + drive model family may also be printed. > + If \*(Aq\-n\*(Aq (see below) is specified, the power mode of the drive is > + printed. > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + [NVMe] For NVMe devices the information is obtained from the Identify > + Controller and the Identify Namespace data structure. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .TP > + .B \-\-identify[=[w][nvb]] > + [ATA only] Prints an annotated table of the IDENTIFY DEVICE data. > +@@ -266,12 +266,12 @@ the SMART options which require support for 48-bit ATA > + For SCSI, this is equivalent to > + .br > + \*(Aq\-H \-i \-A \-l error \-l selftest\*(Aq. > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + For NVMe, this is equivalent to > + .br > + \*(Aq\-H \-i \-c \-A \-l error \-l selftest\*(Aq. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .TP > + .B \-x, \-\-xall > + Prints all SMART and non-SMART information about the device. > +@@ -290,12 +290,12 @@ For SCSI disks, this is equivalent to > + \-l defects \-l envrep \-l genstats \-l ssd \-l zdevstat\*(Aq > + .br > + and for SCSI tape drives and changers, add \*(Aq\-l tapedevstat\*(Aq. > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + For NVMe, this is equivalent to > + .br > + \*(Aq\-H \-i \-c \-A \-l error \-l selftest\*(Aq. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .TP > + .B \-\-scan > + Scans for devices and prints each device name, device type and protocol > +@@ -1184,11 +1184,11 @@ Prefailure SMART Attribute value is less than or > equal > + [SCSI tape drive or changer] The TapeAlert status is obtained by reading the > + TapeAlert log page, but only if this option is given twice (see > + \fBTAPE DRIVES\fP for the rationale). > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + [NVMe] NVMe status is obtained by reading the "Critical Warning" byte from > + the SMART/Health Information log. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .TP > + .B \-c, \-\-capabilities > + [ATA] Prints only the generic SMART capabilities. These > +@@ -1197,11 +1197,11 @@ respond to some of the different SMART commands. For > + shows if the device logs errors, if it supports offline surface > + scanning, and so on. If the device can carry out self-tests, this > + option also shows the estimated time required to run those tests. > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + [NVMe] Prints various NVMe device capabilities obtained from the Identify > + Controller and the Identify Namespace data structure. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .TP > + .B \-A, \-\-attributes > + [ATA] Prints only the vendor specific SMART Attributes. The Attributes > +@@ -1298,11 +1298,11 @@ and start-stop cycle counter log pages. > + Certain vendor specific attributes are listed if recognised. > + The attributes are output in a relatively free format (compared with ATA > + disk attributes). > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + [NVMe] For NVMe devices the attributes are obtained from the SMART/Health > + Information log. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .TP > + .B \-f FORMAT, \-\-format=FORMAT > + [ATA only] Selects the output format of the attributes: > +@@ -1407,7 +1407,7 @@ receives a command which is not implemented or is not > + \- [SCSI] prints the error counter log pages for reads, write and verifies. > + The verify row is only output if it has an element other than zero. > + .Sp > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .I error[,NUM] > + \- [NVMe] prints the NVMe Error Information log. > + Only the 16 most recent log entries are printed by default. > +@@ -1419,7 +1419,7 @@ Note that the contents of this log is not preserved ac > + controller resets, but the value of \*(AqError Information Log Entries\*(Aq > + from SMART/Health Information log is. > + .Sp > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .I xerror[,NUM][,error] > + \- [ATA only] prints the Extended Comprehensive SMART error log > + (General Purpose Log address 0x03). Unlike the Summary SMART error > +@@ -1472,12 +1472,12 @@ If provided, the SCSI Sense Key (SK), Additional > Sense > + Additional Sense Code Qualifier (ASCQ) are also printed. The self tests > + can be run using the \*(Aq\-t\*(Aq option described below (using the ATA > + test terminology). > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + .I selftest > + \- [NVMe: NEW EXPERIMENTAL SMARTCTL 7.4 FEATURE] > + prints the NVMe self-test log. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + .I xselftest[,NUM][,selftest] > + \- [ATA only] prints the Extended SMART self-test log (General Purpose > +@@ -1663,7 +1663,7 @@ This command: > + writes a binary representation of the one sector log 0x11 > + (SATA Phy Event Counters) to file log.bin. > + .Sp > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .I nvmelog,PAGE,SIZE > + \- [NVMe only] prints a hex dump of the first SIZE bytes from the NVMe > + log with identifier PAGE. > +@@ -1672,7 +1672,7 @@ SIZE is a hexadecimal number in the range from 0x4 to > + \fBWARNING: Do not specify the identifier of an unknown log page. > + Reading a log page may have undesirable side effects.\fP > + .Sp > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .I ssd > + \- [ATA] prints the Solid State Device Statistics log page. > + This has the same effect as \*(Aq\-l devstat,7\*(Aq, see above. > +@@ -2130,12 +2130,12 @@ with other disks use the \*(Aq\-c\*(Aq option to > monit > + .Sp > + .I short > + \- [SCSI] runs the "Background short" self-test. > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + .I short > + \- [NVMe: NEW EXPERIMENTAL SMARTCTL 7.4 FEATURE] > + runs the "Short" self-test for current namespace. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + .I long > + \- [ATA] runs SMART Extended Self Test (tens of minutes to several hours). > +@@ -2146,12 +2146,12 @@ below). > + .Sp > + .I long > + \- [SCSI] runs the "Background long" self-test. > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + .I long > + \- [NVMe: NEW EXPERIMENTAL SMARTCTL 7.4 FEATURE] > + runs the "Extended" self-test for current namespace. > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .Sp > + .I conveyance > + \- [ATA only] runs a SMART Conveyance Self Test (minutes). This > Index: patches/patch-smartd_8_in > =================================================================== > RCS file: patches/patch-smartd_8_in > diff -N patches/patch-smartd_8_in > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-smartd_8_in 26 May 2024 14:54:25 -0000 > @@ -0,0 +1,17 @@ > +Index: smartd.8.in > +--- smartd.8.in.orig > ++++ smartd.8.in > +@@ -458,11 +458,11 @@ this option are: > + .I scsiioctl > + \- report only ioctl() transactions with SCSI devices. > + .Sp > +-.\" %IF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %IF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + .I nvmeioctl > + \- report only ioctl() transactions with NVMe devices. > + .Sp > +-.\" %ENDIF OS Darwin FreeBSD Linux NetBSD Windows Cygwin > ++.\" %ENDIF OS Darwin FreeBSD Linux NetBSD OpenBSD Windows Cygwin > + Any argument may include a positive integer to specify the level of > + detail that should be reported. The argument should be followed by a > + comma then the integer with no spaces. For example, \fIataioctl,2\fP