Module Name: src
Committed By: nonaka
Date: Sat Jun 4 16:29:35 UTC 2016
Modified Files:
src/distrib/sets/lists/base: mi
src/distrib/sets/lists/debug: mi
src/distrib/sets/lists/man: mi
src/sbin: Makefile
src/sys/dev/ic: nvmereg.h
Added Files:
src/sbin/nvmectl: Makefile devlist.c firmware.c identify.c logpage.c
nvme.h nvmectl.8 nvmectl.c nvmectl.h perftest.c power.c reset.c
Log Message:
nvmectl(8): Added NVM Express control utility.
Ported from FreeBSD nvmecontrol(8).
To generate a diff of this commit:
cvs rdiff -u -r1.1126 -r1.1127 src/distrib/sets/lists/base/mi
cvs rdiff -u -r1.154 -r1.155 src/distrib/sets/lists/debug/mi
cvs rdiff -u -r1.1525 -r1.1526 src/distrib/sets/lists/man/mi
cvs rdiff -u -r1.127 -r1.128 src/sbin/Makefile
cvs rdiff -u -r0 -r1.1 src/sbin/nvmectl/Makefile src/sbin/nvmectl/devlist.c \
src/sbin/nvmectl/firmware.c src/sbin/nvmectl/identify.c \
src/sbin/nvmectl/logpage.c src/sbin/nvmectl/nvme.h \
src/sbin/nvmectl/nvmectl.8 src/sbin/nvmectl/nvmectl.c \
src/sbin/nvmectl/nvmectl.h src/sbin/nvmectl/perftest.c \
src/sbin/nvmectl/power.c src/sbin/nvmectl/reset.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/ic/nvmereg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/distrib/sets/lists/base/mi
diff -u src/distrib/sets/lists/base/mi:1.1126 src/distrib/sets/lists/base/mi:1.1127
--- src/distrib/sets/lists/base/mi:1.1126 Sat Jun 4 15:27:11 2016
+++ src/distrib/sets/lists/base/mi Sat Jun 4 16:29:35 2016
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1126 2016/06/04 15:27:11 agc Exp $
+# $NetBSD: mi,v 1.1127 2016/06/04 16:29:35 nonaka Exp $
#
# Note: Don't delete entries from here - mark them as "obsolete" instead,
# unless otherwise stated below.
@@ -527,6 +527,7 @@
./sbin/nfsiod base-obsolete obsolete
./sbin/nologin base-sysutil-root
./sbin/npfctl base-npf-bin npf
+./sbin/nvmectl base-sysutil-root
./sbin/pdisk base-sysutil-root
./sbin/pfctl base-pf-root pf
./sbin/pflogd base-pf-root pf
Index: src/distrib/sets/lists/debug/mi
diff -u src/distrib/sets/lists/debug/mi:1.154 src/distrib/sets/lists/debug/mi:1.155
--- src/distrib/sets/lists/debug/mi:1.154 Wed Jun 1 23:59:21 2016
+++ src/distrib/sets/lists/debug/mi Sat Jun 4 16:29:35 2016
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.154 2016/06/01 23:59:21 joerg Exp $
+# $NetBSD: mi,v 1.155 2016/06/04 16:29:35 nonaka Exp $
./etc/mtree/set.debug comp-sys-root
./usr/lib comp-sys-usr compatdir
./usr/lib/i18n/libBIG5_g.a comp-c-debuglib debuglib,compatfile
@@ -377,6 +377,7 @@
./usr/libdata/debug/sbin/newfs_udf.debug comp-sysutil-debug debug
./usr/libdata/debug/sbin/newfs_v7fs.debug comp-sysutil-debug debug
./usr/libdata/debug/sbin/npfctl.debug comp-npf-debug npf,debug
+./usr/libdata/debug/sbin/nvmectl.debug comp-sysutil-debug debug
./usr/libdata/debug/sbin/pdisk.debug comp-sysutil-debug debug
./usr/libdata/debug/sbin/pfctl.debug comp-pf-debug pf,debug
./usr/libdata/debug/sbin/pflogd.debug comp-pf-debug pf,debug
Index: src/distrib/sets/lists/man/mi
diff -u src/distrib/sets/lists/man/mi:1.1525 src/distrib/sets/lists/man/mi:1.1526
--- src/distrib/sets/lists/man/mi:1.1525 Sat Jun 4 15:27:11 2016
+++ src/distrib/sets/lists/man/mi Sat Jun 4 16:29:35 2016
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1525 2016/06/04 15:27:11 agc Exp $
+# $NetBSD: mi,v 1.1526 2016/06/04 16:29:35 nonaka Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@@ -2779,6 +2779,7 @@
./usr/share/man/cat8/ntpq.0 man-ntp-catman .cat
./usr/share/man/cat8/ntptime.0 man-ntp-catman .cat
./usr/share/man/cat8/ntptrace.0 man-ntp-catman .cat
+./usr/share/man/cat8/nvmectl.0 man-sysutil-catman .cat
./usr/share/man/cat8/ofctl.0 man-sysutil-catman .cat
./usr/share/man/cat8/ofppc/MAKEDEV.0 man-obsolete obsolete
./usr/share/man/cat8/ofppc/makedev.0 man-obsolete obsolete
@@ -5630,6 +5631,7 @@
./usr/share/man/html8/ntpq.html man-ntp-htmlman html
./usr/share/man/html8/ntptime.html man-ntp-htmlman html
./usr/share/man/html8/ntptrace.html man-ntp-htmlman html
+./usr/share/man/html8/nvmectl.html man-sysutil-htmlman html
./usr/share/man/html8/ofctl.html man-sysutil-htmlman html
./usr/share/man/html8/oqmgr.html man-postfix-htmlman postfix,html
./usr/share/man/html8/pac.html man-sysutil-htmlman html
@@ -8705,6 +8707,7 @@
./usr/share/man/man8/ntpq.8 man-ntp-man .man
./usr/share/man/man8/ntptime.8 man-ntp-man .man
./usr/share/man/man8/ntptrace.8 man-ntp-man .man
+./usr/share/man/man8/nvmectl.8 man-sysutil-man .man
./usr/share/man/man8/ofctl.8 man-sysutil-man .man
./usr/share/man/man8/ofppc/MAKEDEV.8 man-obsolete obsolete
./usr/share/man/man8/ofppc/makedev.8 man-obsolete obsolete
Index: src/sbin/Makefile
diff -u src/sbin/Makefile:1.127 src/sbin/Makefile:1.128
--- src/sbin/Makefile:1.127 Thu Sep 11 13:10:03 2014
+++ src/sbin/Makefile Sat Jun 4 16:29:35 2016
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.127 2014/09/11 13:10:03 roy Exp $
+# $NetBSD: Makefile,v 1.128 2016/06/04 16:29:35 nonaka Exp $
# @(#)Makefile 8.5 (Berkeley) 3/31/94
# Not ported: XNSrouted enpload scsiformat startslip
@@ -9,7 +9,8 @@
SUBDIR= amrctl apmlabel atactl badsect bioctl brconfig ccdconfig \
chown devpubd disklabel dkctl dkscan_bsdlabel dmesg dmctl \
drvctl fastboot fdisk fsck fsirand gpt ifconfig init ldconfig luactl \
- mbrlabel mknod modload modstat modunload mount newbtconf nologin \
+ mbrlabel mknod modload modstat modunload mount \
+ newbtconf nologin nvmectl \
ping pppoectl raidctl reboot rcorder rndctl route routed \
savecore scan_ffs scsictl shutdown slattach svhlabel swapctl sysctl \
ttyflags umount veriexecctl wdogctl wsconsctl
Index: src/sys/dev/ic/nvmereg.h
diff -u src/sys/dev/ic/nvmereg.h:1.2 src/sys/dev/ic/nvmereg.h:1.3
--- src/sys/dev/ic/nvmereg.h:1.2 Sat Jun 4 16:11:51 2016
+++ src/sys/dev/ic/nvmereg.h Sat Jun 4 16:29:35 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: nvmereg.h,v 1.2 2016/06/04 16:11:51 nonaka Exp $ */
+/* $NetBSD: nvmereg.h,v 1.3 2016/06/04 16:29:35 nonaka Exp $ */
/* $OpenBSD: nvmereg.h,v 1.10 2016/04/14 11:18:32 dlg Exp $ */
/*
@@ -211,12 +211,15 @@ struct nvme_cqe {
uint16_t flags;
#define NVME_CQE_DNR __BIT(15)
#define NVME_CQE_M __BIT(14)
+#define NVME_CQE_SCT_MASK __BITS(8, 10)
#define NVME_CQE_SCT(_f) ((_f) & (0x07 << 8))
#define NVME_CQE_SCT_GENERIC (0x00 << 8)
#define NVME_CQE_SCT_COMMAND (0x01 << 8)
#define NVME_CQE_SCT_MEDIAERR (0x02 << 8)
#define NVME_CQE_SCT_VENDOR (0x07 << 8)
+#define NVME_CQE_SC_MASK __BITS(1, 7)
#define NVME_CQE_SC(_f) ((_f) & (0x7f << 1))
+/* generic command status codes */
#define NVME_CQE_SC_SUCCESS (0x00 << 1)
#define NVME_CQE_SC_INVALID_OPCODE (0x01 << 1)
#define NVME_CQE_SC_INVALID_FIELD (0x02 << 1)
@@ -237,8 +240,36 @@ struct nvme_cqe {
#define NVME_CQE_SC_SGL_TYPE_INVALID (0x11 << 1)
#define NVME_CQE_SC_LBA_RANGE (0x80 << 1)
#define NVME_CQE_SC_CAP_EXCEEDED (0x81 << 1)
-#define NVME_CQE_NS_NOT_RDY (0x82 << 1)
-#define NVME_CQE_RSV_CONFLICT (0x83 << 1)
+#define NVME_CQE_SC_NS_NOT_RDY (0x82 << 1)
+#define NVME_CQE_SC_RSV_CONFLICT (0x83 << 1)
+/* command specific status codes */
+#define NVME_CQE_SC_CQE_INVALID (0x00 << 1)
+#define NVME_CQE_SC_INVALID_QID (0x01 << 1)
+#define NVME_CQE_SC_MAX_Q_SIZE (0x02 << 1)
+#define NVME_CQE_SC_ABORT_LIMIT (0x03 << 1)
+#define NVME_CQE_SC_ASYNC_EV_REQ_LIMIT (0x05 << 1)
+#define NVME_CQE_SC_INVALID_FW_SLOT (0x06 << 1)
+#define NVME_CQE_SC_INVALID_FW_IMAGE (0x07 << 1)
+#define NVME_CQE_SC_INVALID_INT_VEC (0x08 << 1)
+#define NVME_CQE_SC_INVALID_LOG_PAGE (0x09 << 1)
+#define NVME_CQE_SC_INVALID_FORMAT (0x0a << 1)
+#define NVME_CQE_SC_FW_REQ_CNV_RESET (0x0b << 1)
+#define NVME_CQE_SC_FW_REQ_NVM_RESET (0x10 << 1)
+#define NVME_CQE_SC_FW_REQ_RESET (0x11 << 1)
+#define NVME_CQE_SC_FW_MAX_TIME_VIO (0x12 << 1)
+#define NVME_CQE_SC_FW_PROHIBIT (0x13 << 1)
+#define NVME_CQE_SC_OVERLAP_RANGE (0x14 << 1)
+#define NVME_CQE_SC_CONFLICT_ATTRS (0x80 << 1)
+#define NVME_CQE_SC_INVALID_PROT_INFO (0x81 << 1)
+#define NVME_CQE_SC_ATT_WR_TO_RO_PAGE (0x82 << 1)
+/* media error status codes */
+#define NVME_CQE_SC_WRITE_FAULTS (0x80 << 1)
+#define NVME_CQE_SC_UNRECV_READ_ERR (0x81 << 1)
+#define NVME_CQE_SC_GUARD_CHECK_ERR (0x82 << 1)
+#define NVME_CQE_SC_APPL_TAG_CHECK_ERR (0x83 << 1)
+#define NVME_CQE_SC_REF_TAG_CHECK_ERR (0x84 << 1)
+#define NVME_CQE_SC_CMP_FAIL (0x85 << 1)
+#define NVME_CQE_SC_ACCESS_DENIED (0x86 << 1)
#define NVME_CQE_PHASE __BIT(0)
} __packed __aligned(8);
@@ -252,7 +283,7 @@ struct nvme_cqe {
#define NVM_ADMIN_SET_FEATURES 0x09 /* Set Features */
#define NVM_ADMIN_GET_FEATURES 0x0a /* Get Features */
#define NVM_ADMIN_ASYNC_EV_REQ 0x0c /* Asynchronous Event Request */
-#define NVM_ADMIN_FW_ACTIVATE 0x10 /* Firmware Activate */
+#define NVM_ADMIN_FW_COMMIT 0x10 /* Firmware Commit */
#define NVM_ADMIN_FW_DOWNLOAD 0x11 /* Firmware Image Download */
#define NVM_CMD_FLUSH 0x00 /* Flush */
@@ -265,18 +296,34 @@ struct nvme_cqe {
/* Power State Descriptor Data */
struct nvm_identify_psd {
uint16_t mp; /* Max Power */
- uint16_t flags;
+ uint8_t _reserved1;
+ uint8_t flags;
+#define NVME_PSD_NOPS __BIT(1)
+#define NVME_PSD_MPS __BIT(0)
uint32_t enlat; /* Entry Latency */
uint32_t exlat; /* Exit Latency */
uint8_t rrt; /* Relative Read Throughput */
+#define NVME_PSD_RRT_MASK __BITS(0, 4)
uint8_t rrl; /* Relative Read Latency */
+#define NVME_PSD_RRL_MASK __BITS(0, 4)
uint8_t rwt; /* Relative Write Throughput */
+#define NVME_PSD_RWT_MASK __BITS(0, 4)
uint8_t rwl; /* Relative Write Latency */
+#define NVME_PSD_RWL_MASK __BITS(0, 4)
- uint8_t _reserved[16];
+ uint16_t idlp; /* Idle Power */
+ uint8_t ips; /* Idle Power Scale */
+#define NVME_PSD_IPS_MASK __BITS(0, 1)
+ uint8_t _reserved2;
+ uint16_t actp; /* Active Power */
+ uint16_t ap; /* Active Power Workload/Scale */
+#define NVME_PSD_APW_MASK __BITS(0, 2)
+#define NVME_PSD_APS_MASK __BITS(6, 7)
+
+ uint8_t _reserved[8];
} __packed __aligned(8);
struct nvm_identify_controller {
@@ -302,11 +349,20 @@ struct nvm_identify_controller {
/* Admin Command Set Attributes & Optional Controller Capabilities */
uint16_t oacs; /* Optional Admin Command Support */
+#define NVME_ID_CTRLR_OACS_NS __BIT(3)
+#define NVME_ID_CTRLR_OACS_FW __BIT(2)
+#define NVME_ID_CTRLR_OACS_FORMAT __BIT(1)
+#define NVME_ID_CTRLR_OACS_SECURITY __BIT(0)
uint8_t acl; /* Abort Command Limit */
uint8_t aerl; /* Asynchronous Event Request Limit */
uint8_t frmw; /* Firmware Updates */
+#define NVME_ID_CTRLR_FRMW_NOREQ_RESET __BIT(4)
+#define NVME_ID_CTRLR_FRMW_NSLOT __BITS(1, 3)
+#define NVME_ID_CTRLR_FRMW_SLOT1_RO __BIT(0)
uint8_t lpa; /* Log Page Attributes */
+#define NVME_ID_CTRLR_LPA_CMD_EFFECT __BIT(1)
+#define NVME_ID_CTRLR_LPA_NS_SMART __BIT(0)
uint8_t elpe; /* Error Log Page Entries */
uint8_t npss; /* Number of Power States Support */
@@ -320,16 +376,27 @@ struct nvm_identify_controller {
/* NVM Command Set Attributes */
uint8_t sqes; /* Submission Queue Entry Size */
+#define NVME_ID_CTRLR_SQES_MAX __BITS(4, 7)
+#define NVME_ID_CTRLR_SQES_MIN __BITS(0, 3)
uint8_t cqes; /* Completion Queue Entry Size */
+#define NVME_ID_CTRLR_CQES_MAX __BITS(4, 7)
+#define NVME_ID_CTRLR_CQES_MIN __BITS(0, 3)
uint8_t _reserved3[2];
uint32_t nn; /* Number of Namespaces */
uint16_t oncs; /* Optional NVM Command Support */
+#define NVME_ID_CTRLR_ONCS_RESERVATION __BIT(5)
+#define NVME_ID_CTRLR_ONCS_SET_FEATURES __BIT(4)
+#define NVME_ID_CTRLR_ONCS_WRITE_ZERO __BIT(3)
+#define NVME_ID_CTRLR_ONCS_DSM __BIT(2)
+#define NVME_ID_CTRLR_ONCS_WRITE_UNC __BIT(1)
+#define NVME_ID_CTRLR_ONCS_COMPARE __BIT(0)
uint16_t fuses; /* Fused Operation Support */
uint8_t fna; /* Format NVM Attributes */
uint8_t vwc; /* Volatile Write Cache */
+#define NVME_ID_CTRLR_VWC_PRESENT __BIT(0)
uint16_t awun; /* Atomic Write Unit Normal */
uint16_t awupf; /* Atomic Write Unit Power Fail */
@@ -370,6 +437,9 @@ struct nvm_identify_namespace {
uint64_t nuse; /* Namespace Utilization */
uint8_t nsfeat; /* Namespace Features */
+#define NVME_ID_NS_NSFEAT_LOGICAL_BLK_ERR __BIT(2)
+#define NVME_ID_NS_NSFEAT_NS __BIT(1)
+#define NVME_ID_NS_NSFEAT_THIN_PROV __BIT(0)
uint8_t nlbaf; /* Number of LBA Formats */
uint8_t flbas; /* Formatted LBA Size */
#define NVME_ID_NS_FLBAS(_f) ((_f) & 0x0f)
Added files:
Index: src/sbin/nvmectl/Makefile
diff -u /dev/null src/sbin/nvmectl/Makefile:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/Makefile Sat Jun 4 16:29:35 2016
@@ -0,0 +1,19 @@
+# $NetBSD: Makefile,v 1.1 2016/06/04 16:29:35 nonaka Exp $
+
+.include <bsd.own.mk>
+
+PROG= nvmectl
+SRCS= nvmectl.c
+SRCS+= devlist.c
+SRCS+= firmware.c
+SRCS+= identify.c
+SRCS+= logpage.c
+SRCS+= perftest.c
+SRCS+= power.c
+SRCS+= reset.c
+MAN= nvmectl.8
+
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
+
+.include <bsd.prog.mk>
Index: src/sbin/nvmectl/devlist.c
diff -u /dev/null src/sbin/nvmectl/devlist.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/devlist.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,123 @@
+/* $NetBSD: devlist.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: devlist.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/devlist.c 260381 2014-01-06 23:48:47Z jimharris $");
+#endif
+#endif
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+static void
+devlist_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, DEVLIST_USAGE);
+ exit(1);
+}
+
+static inline uint32_t
+ns_get_sector_size(struct nvm_identify_namespace *nsdata)
+{
+
+ return 1 << nsdata->lbaf[NVME_ID_NS_FLBAS(nsdata->flbas)].lbads;
+}
+
+void
+devlist(int argc, char *argv[])
+{
+ struct nvm_identify_controller cdata;
+ struct nvm_identify_namespace nsdata;
+ char name[64];
+ uint8_t mn[64];
+ uint32_t i;
+ int ch, ctrlr, fd, found, ret;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ devlist_usage();
+ }
+ }
+
+ ctrlr = -1;
+ found = 0;
+
+ while (1) {
+ ctrlr++;
+ sprintf(name, "%s%d", NVME_CTRLR_PREFIX, ctrlr);
+
+ ret = open_dev(name, &fd, 0, 0);
+
+ if (ret != 0) {
+ if (ret == EACCES) {
+ warnx("could not open "_PATH_DEV"%s\n", name);
+ continue;
+ } else
+ break;
+ }
+
+ found++;
+ read_controller_data(fd, &cdata);
+ nvme_strvis(mn, sizeof(mn), cdata.mn, sizeof(cdata.mn));
+ printf("%6s: %s\n", name, mn);
+
+ for (i = 0; i < cdata.nn; i++) {
+ sprintf(name, "%s%d%s%d", NVME_CTRLR_PREFIX, ctrlr,
+ NVME_NS_PREFIX, i+1);
+ read_namespace_data(fd, i+1, &nsdata);
+ printf(" %10s (%lldMB)\n",
+ name,
+ nsdata.nsze *
+ (long long)ns_get_sector_size(&nsdata) /
+ 1024 / 1024);
+ }
+
+ close(fd);
+ }
+
+ if (found == 0)
+ printf("No NVMe controllers found.\n");
+
+ exit(1);
+}
Index: src/sbin/nvmectl/firmware.c
diff -u /dev/null src/sbin/nvmectl/firmware.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/firmware.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,333 @@
+/* $NetBSD: firmware.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * Copyright (c) 2013 EMC Corp.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: firmware.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/firmware.c 258071 2013-11-12 21:14:19Z jimharris $");
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+#ifdef FIRMWARE_USAGE
+static int
+slot_has_valid_firmware(int fd, int slot)
+{
+ struct nvme_firmware_page fw;
+ int has_fw = false;
+
+ read_logpage(fd, NVME_LOG_FIRMWARE_SLOT, 0xffffffff, &fw, sizeof(fw));
+
+ if (fw.revision[slot-1] != 0LLU)
+ has_fw = true;
+
+ return (has_fw);
+}
+
+static void
+read_image_file(char *path, void **buf, int32_t *size)
+{
+ struct stat sb;
+ int32_t filesize;
+ int fd;
+
+ *size = 0;
+ *buf = NULL;
+
+ if ((fd = open(path, O_RDONLY)) < 0)
+ err(1, "unable to open '%s'", path);
+ if (fstat(fd, &sb) < 0)
+ err(1, "unable to stat '%s'", path);
+
+ /*
+ * The NVMe spec does not explicitly state a maximum firmware image
+ * size, although one can be inferred from the dword size limitation
+ * for the size and offset fields in the Firmware Image Download
+ * command.
+ *
+ * Technically, the max is UINT32_MAX * sizeof(uint32_t), since the
+ * size and offsets are specified in terms of dwords (not bytes), but
+ * realistically INT32_MAX is sufficient here and simplifies matters
+ * a bit.
+ */
+ if (sb.st_size > INT32_MAX)
+ errx(1, "size of file '%s' is too large (%jd bytes)",
+ path, (intmax_t)sb.st_size);
+ filesize = (int32_t)sb.st_size;
+ if ((*buf = malloc(filesize)) == NULL)
+ errx(1, "unable to malloc %d bytes", filesize);
+ if ((*size = read(fd, *buf, filesize)) < 0)
+ err(1, "error reading '%s'", path);
+ /* XXX assuming no short reads */
+ if (*size != filesize)
+ errx(1,
+ "error reading '%s' (read %d bytes, requested %d bytes)",
+ path, *size, filesize);
+}
+
+static void
+update_firmware(int fd, uint8_t *payload, int32_t payload_size)
+{
+ struct nvme_pt_command pt;
+ int32_t off, resid, size;
+ void *chunk;
+
+ off = 0;
+ resid = payload_size;
+
+ if ((chunk = malloc(NVME_MAX_XFER_SIZE)) == NULL)
+ errx(1, "unable to malloc %d bytes", NVME_MAX_XFER_SIZE);
+
+ while (resid > 0) {
+ size = (resid >= NVME_MAX_XFER_SIZE) ?
+ NVME_MAX_XFER_SIZE : resid;
+ memcpy(chunk, payload + off, size);
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opcode = NVM_ADMIN_FW_DOWNLOAD;
+ pt.cmd.cdw10 = (size / sizeof(uint32_t)) - 1;
+ pt.cmd.cdw11 = (off / sizeof(uint32_t));
+ pt.buf = chunk;
+ pt.len = size;
+ pt.is_read = 0;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "firmware download request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "firmware download request returned error");
+
+ resid -= size;
+ off += size;
+ }
+}
+
+static int
+activate_firmware(int fd, int slot, int commit_action)
+{
+ struct nvme_pt_command pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opcode = NVM_ADMIN_FW_COMMIT;
+ pt.cmd.cdw10 = (commit_action << 3) | slot;
+ pt.is_read = 0;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "firmware activate request failed");
+
+ if (NVME_CQE_SCT(pt.cpl.flags) == NVME_CQE_SCT_COMMAND &&
+ NVME_CQE_SC(pt.cpl.flags) == NVME_CQE_SC_FW_REQ_RESET)
+ return 1;
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "firmware activate request returned error");
+
+ return 0;
+}
+
+static void
+firmware_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, FIRMWARE_USAGE);
+ exit(1);
+}
+
+void
+firmware(int argc, char *argv[])
+{
+ u_int slot = 0;
+ int fd = -1;
+ int a_flag, s_flag, f_flag;
+ int commit_action, reboot_required;
+ int ch,
+ char *p, *image = NULL;
+ char *controller = NULL, prompt[64];
+ void *buf = NULL;
+ int32_t size = 0;
+ struct nvm_identify_controller cdata;
+
+ a_flag = s_flag = f_flag = false;
+
+ while ((ch = getopt(argc, argv, "af:s:")) != -1) {
+ switch (ch) {
+ case 'a':
+ a_flag = true;
+ break;
+ case 's':
+ slot = strtol(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid slot.\n",
+ optarg);
+ firmware_usage();
+ } else if (slot == 0) {
+ fprintf(stderr,
+ "0 is not a valid slot number. "
+ "Slot numbers start at 1.\n");
+ firmware_usage();
+ } else if (slot > 7) {
+ fprintf(stderr,
+ "Slot number %s specified which is "
+ "greater than max allowed slot number of "
+ "7.\n", optarg);
+ firmware_usage();
+ }
+ s_flag = true;
+ break;
+ case 'f':
+ image = optarg;
+ f_flag = true;
+ break;
+ }
+ }
+
+ /* Check that a controller (and not a namespace) was specified. */
+ if (optind >= argc || strstr(argv[optind], NVME_NS_PREFIX) != NULL)
+ firmware_usage();
+
+ if (!f_flag && !a_flag) {
+ fprintf(stderr,
+ "Neither a replace ([-f path_to_firmware]) nor "
+ "activate ([-a]) firmware image action\n"
+ "was specified.\n");
+ firmware_usage();
+ }
+
+ if (!f_flag && a_flag && slot == 0) {
+ fprintf(stderr,
+ "Slot number to activate not specified.\n");
+ firmware_usage();
+ }
+
+ controller = argv[optind];
+ open_dev(controller, &fd, 1, 1);
+ read_controller_data(fd, &cdata);
+
+ if ((cdata.oacs & NVME_ID_CTRLR_OACS_FW) == 0)
+ errx(1,
+ "controller does not support firmware activate/download");
+
+ if (f_flag && slot == 1 && (cdata.frmw & NVME_ID_CTRLR_FRMW_SLOT1_RO))
+ errx(1, "slot %d is marked as read only", slot);
+
+ if (slot > __SHIFTOUT(cdata.frmw, NVME_ID_CTRLR_FRMW_NSLOT))
+ errx(1,
+ "slot %d specified but controller only supports %d slots",
+ slot,
+ (uint8_t)__SHIFTOUT(cdata.frmw, NVME_ID_CTRLR_FRMW_NSLOT));
+
+ if (a_flag && !f_flag && !slot_has_valid_firmware(fd, slot))
+ errx(1,
+ "slot %d does not contain valid firmware,\n"
+ "try 'nvmecontrol logpage -p 3 %s' to get a list "
+ "of available images\n",
+ slot, controller);
+
+ if (f_flag)
+ read_image_file(image, &buf, &size);
+
+ if (f_flag && a_flag)
+ printf("You are about to download and activate "
+ "firmware image (%s) to controller %s.\n"
+ "This may damage your controller and/or "
+ "overwrite an existing firmware image.\n",
+ image, controller);
+ else if (a_flag)
+ printf("You are about to activate a new firmware "
+ "image on controller %s.\n"
+ "This may damage your controller.\n",
+ controller);
+ else if (f_flag)
+ printf("You are about to download firmware image "
+ "(%s) to controller %s.\n"
+ "This may damage your controller and/or "
+ "overwrite an existing firmware image.\n",
+ image, controller);
+
+ printf("Are you sure you want to continue? (yes/no) ");
+ while (1) {
+ fgets(prompt, sizeof(prompt), stdin);
+ if (strncasecmp(prompt, "yes", 3) == 0)
+ break;
+ if (strncasecmp(prompt, "no", 2) == 0)
+ exit(1);
+ printf("Please answer \"yes\" or \"no\". ");
+ }
+
+ if (f_flag) {
+ update_firmware(fd, buf, size);
+ if (a_flag)
+ commit_action = NVME_COMMIT_ACTION_REPLACE_ACTIVATE;
+ else
+ commit_action = NVME_COMMIT_ACTION_REPLACE_NO_ACTIVATE;
+ } else {
+ commit_action = NVME_COMMIT_ACTION_ACTIVATE_RESET;
+ }
+
+ reboot_required = activate_firmware(fd, slot, commit_action);
+
+ if (a_flag) {
+ if (reboot_required) {
+ printf("New firmware image activated but requires "
+ "conventional reset (i.e. reboot) to "
+ "complete activation.\n");
+ } else {
+ printf("New firmware image activated and will take "
+ "effect after next controller reset.\n"
+ "Controller reset can be initiated via "
+ "'nvmecontrol reset %s'\n",
+ controller);
+ }
+ }
+
+ close(fd);
+ exit(0);
+}
+#endif
Index: src/sbin/nvmectl/identify.c
diff -u /dev/null src/sbin/nvmectl/identify.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/identify.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,314 @@
+/* $NetBSD: identify.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: identify.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/identify.c 253476 2013-07-19 21:40:57Z jimharris $");
+#endif
+#endif
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+static void
+print_controller(struct nvm_identify_controller *cdata)
+{
+ uint8_t str[128];
+
+ printf("Controller Capabilities/Features\n");
+ printf("================================\n");
+ printf("Vendor ID: %04x\n", cdata->vid);
+ printf("Subsystem Vendor ID: %04x\n", cdata->ssvid);
+ nvme_strvis(str, sizeof(str), cdata->sn, sizeof(cdata->sn));
+ printf("Serial Number: %s\n", str);
+ nvme_strvis(str, sizeof(str), cdata->mn, sizeof(cdata->mn));
+ printf("Model Number: %s\n", str);
+ nvme_strvis(str, sizeof(str), cdata->fr, sizeof(cdata->fr));
+ printf("Firmware Version: %s\n", str);
+ printf("Recommended Arb Burst: %d\n", cdata->rab);
+ printf("IEEE OUI Identifier: %02x %02x %02x\n",
+ cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
+ printf("Multi-Interface Cap: %02x\n", cdata->cmic);
+ /* TODO: Use CAP.MPSMIN to determine true memory page size. */
+ printf("Max Data Transfer Size: ");
+ if (cdata->mdts == 0)
+ printf("Unlimited\n");
+ else
+ printf("%ld\n", sysconf(_SC_PAGESIZE) * (1 << cdata->mdts));
+ printf("\n");
+
+ printf("Admin Command Set Attributes\n");
+ printf("============================\n");
+ printf("Security Send/Receive: %s\n",
+ (cdata->oacs & NVME_ID_CTRLR_OACS_SECURITY) ?
+ "Supported" : "Not Supported");
+ printf("Format NVM: %s\n",
+ (cdata->oacs & NVME_ID_CTRLR_OACS_FORMAT) ?
+ "Supported" : "Not Supported");
+ printf("Firmware Activate/Download: %s\n",
+ (cdata->oacs & NVME_ID_CTRLR_OACS_FW) ?
+ "Supported" : "Not Supported");
+ printf("Abort Command Limit: %d\n", cdata->acl+1);
+ printf("Async Event Request Limit: %d\n", cdata->aerl+1);
+ printf("Number of Firmware Slots: ");
+ if (cdata->oacs & NVME_ID_CTRLR_OACS_FW)
+ printf("%d\n",
+ (uint8_t)__SHIFTOUT(cdata->frmw, NVME_ID_CTRLR_FRMW_NSLOT));
+ else
+ printf("N/A\n");
+ printf("Firmware Slot 1 Read-Only: ");
+ if (cdata->oacs & NVME_ID_CTRLR_OACS_FW)
+ printf("%s\n", (cdata->frmw & NVME_ID_CTRLR_FRMW_SLOT1_RO) ?
+ "Yes" : "No");
+ else
+ printf("N/A\n");
+ printf("Per-Namespace SMART Log: %s\n",
+ (cdata->lpa & NVME_ID_CTRLR_LPA_NS_SMART) ? "Yes" : "No");
+ printf("Error Log Page Entries: %d\n", cdata->elpe+1);
+ printf("Number of Power States: %d\n", cdata->npss+1);
+ printf("\n");
+
+ printf("NVM Command Set Attributes\n");
+ printf("==========================\n");
+ printf("Submission Queue Entry Size\n");
+ printf(" Max: %d\n",
+ 1 << __SHIFTOUT(cdata->sqes, NVME_ID_CTRLR_SQES_MAX));
+ printf(" Min: %d\n",
+ 1 << __SHIFTOUT(cdata->sqes, NVME_ID_CTRLR_SQES_MIN));
+ printf("Completion Queue Entry Size\n");
+ printf(" Max: %d\n",
+ 1 << __SHIFTOUT(cdata->cqes, NVME_ID_CTRLR_CQES_MAX));
+ printf(" Min: %d\n",
+ 1 << __SHIFTOUT(cdata->cqes, NVME_ID_CTRLR_CQES_MIN));
+ printf("Number of Namespaces: %d\n", cdata->nn);
+ printf("Compare Command: %s\n",
+ (cdata->oncs & NVME_ID_CTRLR_ONCS_COMPARE) ?
+ "Supported" : "Not Supported");
+ printf("Write Uncorrectable Command: %s\n",
+ (cdata->oncs & NVME_ID_CTRLR_ONCS_WRITE_UNC) ?
+ "Supported" : "Not Supported");
+ printf("Dataset Management Command: %s\n",
+ (cdata->oncs & NVME_ID_CTRLR_ONCS_DSM) ?
+ "Supported" : "Not Supported");
+ printf("Write Zeroes Command: %s\n",
+ (cdata->oncs & NVME_ID_CTRLR_ONCS_WRITE_ZERO) ?
+ "Supported" : "Not Supported");
+ printf("Set Features Command: %s\n",
+ (cdata->oncs & NVME_ID_CTRLR_ONCS_SET_FEATURES) ?
+ "Supported" : "Not Supported");
+ printf("Reservation: %s\n",
+ (cdata->oncs & NVME_ID_CTRLR_ONCS_RESERVATION) ?
+ "Supported" : "Not Supported");
+ printf("Volatile Write Cache: %s\n",
+ (cdata->vwc & NVME_ID_CTRLR_VWC_PRESENT) ?
+ "Present" : "Not Present");
+}
+
+static void
+print_namespace(struct nvm_identify_namespace *nsdata)
+{
+ uint32_t i;
+
+ printf("Size (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->nsze,
+ (long long)nsdata->nsze / 1024 / 1024);
+ printf("Capacity (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->ncap,
+ (long long)nsdata->ncap / 1024 / 1024);
+ printf("Utilization (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->nuse,
+ (long long)nsdata->nuse / 1024 / 1024);
+ printf("Thin Provisioning: %s\n",
+ (nsdata->nsfeat & NVME_ID_NS_NSFEAT_THIN_PROV) ?
+ "Supported" : "Not Supported");
+ printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1);
+ printf("Current LBA Format: LBA Format #%02d\n",
+ NVME_ID_NS_FLBAS(nsdata->flbas));
+ for (i = 0; i <= nsdata->nlbaf; i++)
+ printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n",
+ i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
+}
+
+static void
+identify_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, IDENTIFY_USAGE);
+ exit(1);
+}
+
+static void
+identify_ctrlr(int argc, char *argv[])
+{
+ struct nvm_identify_controller cdata;
+ int ch, fd, hexflag = 0, hexlength;
+ int verboseflag = 0;
+
+ while ((ch = getopt(argc, argv, "vx")) != -1) {
+ switch (ch) {
+ case 'v':
+ verboseflag = 1;
+ break;
+ case 'x':
+ hexflag = 1;
+ break;
+ default:
+ identify_usage();
+ }
+ }
+
+ /* Check that a controller was specified. */
+ if (optind >= argc)
+ identify_usage();
+
+ open_dev(argv[optind], &fd, 1, 1);
+ read_controller_data(fd, &cdata);
+ close(fd);
+
+ if (hexflag == 1) {
+ if (verboseflag == 1)
+ hexlength = sizeof(struct nvm_identify_controller);
+ else
+ hexlength = offsetof(struct nvm_identify_controller,
+ _reserved7);
+ print_hex(&cdata, hexlength);
+ exit(0);
+ }
+
+ if (verboseflag == 1) {
+ fprintf(stderr, "-v not currently supported without -x\n");
+ identify_usage();
+ }
+
+ print_controller(&cdata);
+ exit(0);
+}
+
+static void
+identify_ns(int argc, char *argv[])
+{
+ struct nvm_identify_namespace nsdata;
+ char path[64];
+ int ch, fd, hexflag = 0, hexlength, nsid;
+ int verboseflag = 0;
+
+ while ((ch = getopt(argc, argv, "vx")) != -1) {
+ switch (ch) {
+ case 'v':
+ verboseflag = 1;
+ break;
+ case 'x':
+ hexflag = 1;
+ break;
+ default:
+ identify_usage();
+ }
+ }
+
+ /* Check that a namespace was specified. */
+ if (optind >= argc)
+ identify_usage();
+
+ /*
+ * Check if the specified device node exists before continuing.
+ * This is a cleaner check for cases where the correct controller
+ * is specified, but an invalid namespace on that controller.
+ */
+ open_dev(argv[optind], &fd, 1, 1);
+ close(fd);
+
+ /*
+ * We send IDENTIFY commands to the controller, not the namespace,
+ * since it is an admin cmd. The namespace ID will be specified in
+ * the IDENTIFY command itself. So parse the namespace's device node
+ * string to get the controller substring and namespace ID.
+ */
+ parse_ns_str(argv[optind], path, &nsid);
+ open_dev(path, &fd, 1, 1);
+ read_namespace_data(fd, nsid, &nsdata);
+ close(fd);
+
+ if (hexflag == 1) {
+ if (verboseflag == 1)
+ hexlength = sizeof(struct nvm_identify_namespace);
+ else
+ hexlength = offsetof(struct nvm_identify_namespace,
+ _reserved2);
+ print_hex(&nsdata, hexlength);
+ exit(0);
+ }
+
+ if (verboseflag == 1) {
+ fprintf(stderr, "-v not currently supported without -x\n");
+ identify_usage();
+ }
+
+ print_namespace(&nsdata);
+ exit(0);
+}
+
+void
+identify(int argc, char *argv[])
+{
+ char *target;
+
+ if (argc < 2)
+ identify_usage();
+
+ while (getopt(argc, argv, "vx") != -1) ;
+
+ /* Check that a controller or namespace was specified. */
+ if (optind >= argc)
+ identify_usage();
+
+ target = argv[optind];
+
+ optreset = 1;
+ optind = 1;
+
+ /*
+ * If device node contains "ns", we consider it a namespace,
+ * otherwise, consider it a controller.
+ */
+ if (strstr(target, NVME_NS_PREFIX) == NULL)
+ identify_ctrlr(argc, argv);
+ else
+ identify_ns(argc, argv);
+}
Index: src/sbin/nvmectl/logpage.c
diff -u /dev/null src/sbin/nvmectl/logpage.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/logpage.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,377 @@
+/* $NetBSD: logpage.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * Copyright (c) 2013 EMC Corp.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: logpage.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/logpage.c 285796 2015-07-22 16:10:29Z jimharris $");
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+#define DEFAULT_SIZE (4096)
+#define MAX_FW_SLOTS (7)
+
+typedef void (*print_fn_t)(void *buf, uint32_t size);
+
+static void *
+get_log_buffer(uint32_t size)
+{
+ void *buf;
+
+ if ((buf = malloc(size)) == NULL)
+ errx(1, "unable to malloc %u bytes", size);
+
+ memset(buf, 0, size);
+ return (buf);
+}
+
+void
+read_logpage(int fd, uint8_t log_page, int nsid, void *payload,
+ uint32_t payload_size)
+{
+ struct nvme_pt_command pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opcode = NVM_ADMIN_GET_LOG_PG;
+ pt.cmd.nsid = nsid;
+ pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16;
+ pt.cmd.cdw10 |= log_page;
+ pt.buf = payload;
+ pt.len = payload_size;
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "get log page request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "get log page request returned error");
+}
+
+static void
+print_log_error(void *buf, uint32_t size)
+{
+ int i, nentries;
+ struct nvme_error_information_entry *entry = buf;
+
+ printf("Error Information Log\n");
+ printf("=====================\n");
+
+ if (entry->error_count == 0) {
+ printf("No error entries found\n");
+ return;
+ }
+
+ nentries = size/sizeof(struct nvme_error_information_entry);
+ for (i = 0; i < nentries; i++, entry++) {
+ if (entry->error_count == 0)
+ break;
+
+ printf("Entry %02d\n", i + 1);
+ printf("=========\n");
+ printf(" Error count: %ju\n", entry->error_count);
+ printf(" Submission queue ID: %u\n", entry->sqid);
+ printf(" Command ID: %u\n", entry->cid);
+ /* TODO: Export nvme_status_string structures from kernel? */
+ printf(" Status:\n");
+ printf(" Phase tag: %d\n",
+ (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_PHASE));
+ printf(" Status code: %d\n",
+ (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_SC_MASK));
+ printf(" Status code type: %d\n",
+ (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_SCT_MASK));
+ printf(" More: %d\n",
+ (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_M));
+ printf(" DNR: %d\n",
+ (uint16_t)__SHIFTOUT(entry->status, NVME_CQE_DNR));
+ printf(" Error location: %u\n", entry->error_location);
+ printf(" LBA: %ju\n", entry->lba);
+ printf(" Namespace ID: %u\n", entry->nsid);
+ printf(" Vendor specific info: %u\n", entry->vendor_specific);
+ printf(" Command specific info: %ju\n",
+ entry->command_specific);
+ }
+}
+
+static void
+print_log_health(void *buf, uint32_t size __unused)
+{
+ struct nvme_health_information_page *health = buf;
+ float composite_temperature = health->composite_temperature;
+
+ printf("SMART/Health Information Log\n");
+ printf("============================\n");
+
+ printf("Critical Warning State: 0x%02x\n",
+ health->critical_warning);
+ printf(" Available spare: %d\n",
+ (uint8_t)__SHIFTOUT(health->critical_warning,
+ NVME_HEALTH_PAGE_CW_AVAIL_SPARE));
+ printf(" Temperature: %d\n",
+ (uint8_t)__SHIFTOUT(health->critical_warning,
+ NVME_HEALTH_PAGE_CW_TEMPERTURE));
+ printf(" Device reliability: %d\n",
+ (uint8_t)__SHIFTOUT(health->critical_warning,
+ NVME_HEALTH_PAGE_CW_DEVICE_RELIABLITY));
+ printf(" Read only: %d\n",
+ (uint8_t)__SHIFTOUT(health->critical_warning,
+ NVME_HEALTH_PAGE_CW_READ_ONLY));
+ printf(" Volatile memory backup: %d\n",
+ (uint8_t)__SHIFTOUT(health->critical_warning,
+ NVME_HEALTH_PAGE_CW_VOLATILE_MEMORY_BACKUP));
+ printf("Temperature: %u K, %2.2f C, %3.2f F\n",
+ health->composite_temperature,
+ composite_temperature - (float)273.15,
+ (composite_temperature * (float)9/5) - (float)459.67);
+ printf("Available spare: %u\n",
+ health->available_spare);
+ printf("Available spare threshold: %u\n",
+ health->available_spare_threshold);
+ printf("Percentage used: %u\n",
+ health->percentage_used);
+
+ /*
+ * TODO: These are pretty ugly in hex. Is there a library that
+ * will convert 128-bit unsigned values to decimal?
+ */
+ printf("Data units (512 byte) read: 0x%016jx%016jx\n",
+ health->data_units_read[1],
+ health->data_units_read[0]);
+ printf("Data units (512 byte) written: 0x%016jx%016jx\n",
+ health->data_units_written[1],
+ health->data_units_written[0]);
+ printf("Host read commands: 0x%016jx%016jx\n",
+ health->host_read_commands[1],
+ health->host_read_commands[0]);
+ printf("Host write commands: 0x%016jx%016jx\n",
+ health->host_write_commands[1],
+ health->host_write_commands[0]);
+ printf("Controller busy time (minutes): 0x%016jx%016jx\n",
+ health->controller_busy_time[1],
+ health->controller_busy_time[0]);
+ printf("Power cycles: 0x%016jx%016jx\n",
+ health->power_cycles[1],
+ health->power_cycles[0]);
+ printf("Power on hours: 0x%016jx%016jx\n",
+ health->power_on_hours[1],
+ health->power_on_hours[0]);
+ printf("Unsafe shutdowns: 0x%016jx%016jx\n",
+ health->unsafe_shutdowns[1],
+ health->unsafe_shutdowns[0]);
+ printf("Media errors: 0x%016jx%016jx\n",
+ health->media_errors[1],
+ health->media_errors[0]);
+ printf("No. error info log entries: 0x%016jx%016jx\n",
+ health->num_error_info_log_entries[1],
+ health->num_error_info_log_entries[0]);
+}
+
+static void
+print_log_firmware(void *buf, uint32_t size __unused)
+{
+ u_int i;
+ const char *status;
+ struct nvme_firmware_page *fw = buf;
+
+ printf("Firmware Slot Log\n");
+ printf("=================\n");
+
+ for (i = 0; i < MAX_FW_SLOTS; i++) {
+ printf("Slot %d: ", i + 1);
+ if (__SHIFTOUT(fw->afi, NVME_FW_PAGE_AFI_SLOT) == i + 1)
+ status = " Active";
+ else
+ status = "Inactive";
+
+ if (fw->revision[i] == 0LLU)
+ printf("Empty\n");
+ else
+ if (isprint(*(uint8_t *)&fw->revision[i]))
+ printf("[%s] %.8s\n", status,
+ (char *)&fw->revision[i]);
+ else
+ printf("[%s] %016jx\n", status,
+ fw->revision[i]);
+ }
+}
+
+static struct logpage_function {
+ uint8_t log_page;
+ print_fn_t fn;
+} logfuncs[] = {
+ {NVME_LOG_ERROR, print_log_error },
+ {NVME_LOG_HEALTH_INFORMATION, print_log_health },
+ {NVME_LOG_FIRMWARE_SLOT, print_log_firmware },
+ {0, NULL },
+};
+
+static void
+logpage_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, LOGPAGE_USAGE);
+ exit(1);
+}
+
+void
+logpage(int argc, char *argv[])
+{
+ int fd, nsid;
+ int log_page = 0, pageflag = false;
+ int hexflag = false, ns_specified;
+ int ch;
+ char *p;
+ char cname[64];
+ uint32_t size;
+ void *buf;
+ struct logpage_function *f;
+ struct nvm_identify_controller cdata;
+ print_fn_t print_fn;
+
+ while ((ch = getopt(argc, argv, "p:x")) != -1) {
+ switch (ch) {
+ case 'p':
+ /* TODO: Add human-readable ASCII page IDs */
+ log_page = strtol(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid log page id.\n",
+ optarg);
+ logpage_usage();
+ /* TODO: Define valid log page id ranges in nvme.h? */
+ } else if (log_page == 0 ||
+ (log_page >= 0x04 && log_page <= 0x7F) ||
+ (log_page >= 0x80 && log_page <= 0xBF)) {
+ fprintf(stderr,
+ "\"%s\" not valid log page id.\n",
+ optarg);
+ logpage_usage();
+ }
+ pageflag = true;
+ break;
+ case 'x':
+ hexflag = true;
+ break;
+ }
+ }
+
+ if (!pageflag) {
+ printf("Missing page_id (-p).\n");
+ logpage_usage();
+ }
+
+ /* Check that a controller and/or namespace was specified. */
+ if (optind >= argc)
+ logpage_usage();
+
+ if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) {
+ ns_specified = true;
+ parse_ns_str(argv[optind], cname, &nsid);
+ open_dev(cname, &fd, 1, 1);
+ } else {
+ ns_specified = false;
+ nsid = 0xffffffff;
+ open_dev(argv[optind], &fd, 1, 1);
+ }
+
+ read_controller_data(fd, &cdata);
+
+ /*
+ * The log page attribtues indicate whether or not the controller
+ * supports the SMART/Health information log page on a per
+ * namespace basis.
+ */
+ if (ns_specified) {
+ if (log_page != NVME_LOG_HEALTH_INFORMATION)
+ errx(1, "log page %d valid only at controller level",
+ log_page);
+ if (!(cdata.lpa & NVME_ID_CTRLR_LPA_NS_SMART))
+ errx(1,
+ "controller does not support per namespace "
+ "smart/health information");
+ }
+
+ print_fn = print_hex;
+ if (!hexflag) {
+ /*
+ * See if there is a pretty print function for the
+ * specified log page. If one isn't found, we
+ * just revert to the default (print_hex).
+ */
+ f = logfuncs;
+ while (f->log_page > 0) {
+ if (log_page == f->log_page) {
+ print_fn = f->fn;
+ break;
+ }
+ f++;
+ }
+ }
+
+ /* Read the log page */
+ switch (log_page) {
+ case NVME_LOG_ERROR:
+ size = sizeof(struct nvme_error_information_entry);
+ size *= (cdata.elpe + 1);
+ break;
+ case NVME_LOG_HEALTH_INFORMATION:
+ size = sizeof(struct nvme_health_information_page);
+ break;
+ case NVME_LOG_FIRMWARE_SLOT:
+ size = sizeof(struct nvme_firmware_page);
+ break;
+ default:
+ size = DEFAULT_SIZE;
+ break;
+ }
+
+ buf = get_log_buffer(size);
+ read_logpage(fd, log_page, nsid, buf, size);
+ print_fn(buf, size);
+
+ close(fd);
+ exit(0);
+}
Index: src/sbin/nvmectl/nvme.h
diff -u /dev/null src/sbin/nvmectl/nvme.h:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/nvme.h Sat Jun 4 16:29:35 2016
@@ -0,0 +1,143 @@
+/* $NetBSD: nvme.h,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * 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: head/sys/dev/nvme/nvme.h 296617 2016-03-10 17:13:10Z mav $
+ */
+
+#ifndef __NVME_H__
+#define __NVME_H__
+
+#define NVME_MAX_XFER_SIZE MAXPHYS
+
+/* Get/Set Features */
+#define NVME_FEAT_ARBITRATION 0x01
+#define NVME_FEAT_POWER_MANAGEMENT 0x02
+#define NVME_FEAT_LBA_RANGE_TYPE 0x03
+#define NVME_FEAT_TEMPERATURE_THRESHOLD 0x04
+#define NVME_FEAT_ERROR_RECOVERY 0x05
+#define NVME_FEAT_VOLATILE_WRITE_CACHE 0x06
+#define NVME_FEAT_NUMBER_OF_QUEUES 0x07
+#define NVME_FEAT_INTERRUPT_COALESCING 0x08
+#define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION 0x09
+#define NVME_FEAT_WRITE_ATOMICITY_NORMAL 0x0a
+#define NVME_FEAT_ASYNC_EVENT_CONFIGURATION 0x0b
+#define NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION 0x0c
+#define NVME_FEAT_HOST_MEMORY_BUFFER 0x0d
+/* NVM Command Set specific */
+#define NVME_FEAT_SOFTWARE_PROGRESS_MARKER 0x80
+#define NVME_FEAT_HOST_IDENTIFIER 0x81
+#define NVME_FEAT_RESERVATION_NOTIFICATION_MASK 0x82
+#define NVME_FEAT_RESERVATION_PERSISTANCE 0x83
+
+/* Get Log Page */
+#define NVME_LOG_ERROR 0x01
+#define NVME_LOG_HEALTH_INFORMATION 0x02
+#define NVME_LOG_FIRMWARE_SLOT 0x03
+#define NVME_LOG_CHANGED_NAMESPACE_LIST 0x04
+#define NVME_LOG_COMMAND_EFFECTS_LOG 0x05
+#define NVME_LOG_RESERVATION_NOTIFICATION 0x80
+
+/* Error Information Log (Log Identifier 01h) */
+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 _reserved1[3];
+ uint64_t command_specific;
+ uint8_t reserved[24];
+} __packed __aligned(4);
+
+/* SMART / Health Information Log (Log Identifier 02h) */
+struct nvme_health_information_page {
+ uint8_t critical_warning;
+#define NVME_HEALTH_PAGE_CW_VOLATILE_MEMORY_BACKUP __BIT(4)
+#define NVME_HEALTH_PAGE_CW_READ_ONLY __BIT(3)
+#define NVME_HEALTH_PAGE_CW_DEVICE_RELIABLITY __BIT(2)
+#define NVME_HEALTH_PAGE_CW_TEMPERTURE __BIT(1)
+#define NVME_HEALTH_PAGE_CW_AVAIL_SPARE __BIT(0)
+ uint16_t composite_temperature;
+ uint8_t available_spare;
+ uint8_t available_spare_threshold;
+ uint8_t percentage_used;
+
+ uint8_t _reserved1[26];
+
+ uint64_t data_units_read[2];
+ uint64_t data_units_written[2];
+ uint64_t host_read_commands[2];
+ uint64_t host_write_commands[2];
+ 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_composite_temperature_time;
+ uint32_t critical_composite_temperature_time;
+ uint16_t temperature_sensor[8];
+
+ uint8_t reserved[296];
+} __packed __aligned(4);
+
+/* Firmware Commit */
+#define NVME_COMMIT_ACTION_REPLACE_NO_ACTIVATE 0
+#define NVME_COMMIT_ACTION_REPLACE_ACTIVATE 1
+#define NVME_COMMIT_ACTION_ACTIVATE_RESET 2
+#define NVME_COMMIT_ACTION_ACTIVATE_NO_RESET 3
+
+/* Firmware Slot Information (Log Identifier 03h) */
+struct nvme_firmware_page {
+ uint8_t afi;
+#define NVME_FW_PAGE_AFI_SLOT_RST __BITS(4, 6)
+#define NVME_FW_PAGE_AFI_SLOT __BITS(0, 2)
+ uint8_t _reserved1[7];
+
+ uint64_t revision[7]; /* revisions for 7 slots */
+
+ uint8_t reserved[448];
+} __packed __aligned(4);
+
+/* Commands Supported and Effects (Log Identifier 05h) */
+struct nvme_command_effeects_page {
+ uint32_t acs[256];
+#define NVME_CE_PAGE_CS_CSE __BITS(16, 18)
+#define NVME_CE_PAGE_CS_CCC __BIT(4)
+#define NVME_CE_PAGE_CS_NIC __BIT(3)
+#define NVME_CE_PAGE_CS_NCC __BIT(2)
+#define NVME_CE_PAGE_CS_LBCC __BIT(1)
+#define NVME_CE_PAGE_CS_CSUPP __BIT(0)
+ uint32_t iocs[256];
+
+ uint8_t reserved[2048];
+} __packed __aligned(4);
+
+#endif /* __NVME_H__ */
Index: src/sbin/nvmectl/nvmectl.8
diff -u /dev/null src/sbin/nvmectl/nvmectl.8:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/nvmectl.8 Sat Jun 4 16:29:35 2016
@@ -0,0 +1,147 @@
+.\" $NetBSD: nvmectl.8,v 1.1 2016/06/04 16:29:35 nonaka Exp $
+.\"
+.\" 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 <[email protected]>
+.\"
+.\" $FreeBSD: head/sbin/nvmecontrol/nvmecontrol.8 299151 2016-05-06 03:11:34Z pfg $
+.\"
+.Dd May 19, 2016
+.Dt NVMECTL 8
+.Os
+.Sh NAME
+.Nm nvmectl
+.Nd NVM Express control utility
+.Sh SYNOPSIS
+.Nm
+.Ic devlist
+.Nm
+.Ic identify
+.Op Fl v
+.Op Fl x
+.Aq device 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
+.Aq device id
+.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 power
+.Op Fl l
+.Op Fl p power_state
+.Op fl w workload_hint
+.Sh DESCRIPTION
+NVM Express (NVMe) is a storage protocol standard, for SSDs and other
+high-speed storage devices over PCI Express.
+.Sh EXAMPLES
+.Dl nvmectl devlist
+.Pp
+Display a list of NVMe controllers and namespaces along with their device nodes.
+.Pp
+.Dl nvmectl identify nvme0
+.Pp
+Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data.
+.Pp
+.Dl nvmectl identify -x -v nvme0ns1
+.Pp
+Display an hexadecimal dump of the nvme0 IDENTIFY_NAMESPACE data for namespace
+1.
+.\".Pp
+.\".Dl nvmectl 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 nvmectl reset nvme0
+.\".Pp
+.\"Perform a controller-level reset of the nvme0 controller.
+.Pp
+.Dl nvmectl 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 nvmectl logpage -p 1 -x nvme0
+.Pp
+Display a hexadecimal dump of the nvme0 controller's Error Information Log.
+.\".Pp
+.\".Dl nvmectl 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 nvmectl firmware -s 4 -a nvme0
+.\".Pp
+.\"Activate the firmware in slot 4 of the nvme0 controller on the next reset.
+.\".Pp
+.\".Dl nvmectl 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 nvmectl power -l nvme0
+.Pp
+List all the current power modes.
+.Pp
+.Dl nvmectl power -p 3 nvme0
+.Pp
+Set the current power mode.
+.Pp
+.Dl nvmectl power nvme0
+.Pp
+Get the current power mode.
+.Sh AUTHORS
+.An -nosplit
+nvmecontrol was developed by Intel and originally written by
+.An Jim Harris Aq Mt [email protected] .
+.Pp
+This man page was written by
+.An Jim Harris Aq Mt [email protected] .
Index: src/sbin/nvmectl/nvmectl.c
diff -u /dev/null src/sbin/nvmectl/nvmectl.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/nvmectl.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,287 @@
+/* $NetBSD: nvmectl.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: nvmectl.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 295087 2016-01-30 22:48:06Z imp $");
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+typedef void (*nvme_fn_t)(int argc, char *argv[]);
+
+static struct nvme_function {
+ const char *name;
+ nvme_fn_t fn;
+ const char *usage;
+} funcs[] = {
+ {"devlist", devlist, DEVLIST_USAGE},
+ {"identify", identify, IDENTIFY_USAGE},
+#ifdef PERFTEST_USAGE
+ {"perftest", perftest, PERFTEST_USAGE},
+#endif
+#ifdef RESET_USAGE
+ {"reset", reset, RESET_USAGE},
+#endif
+ {"logpage", logpage, LOGPAGE_USAGE},
+#ifdef FIRMWARE_USAGE
+ {"firmware", firmware, FIRMWARE_USAGE},
+#endif
+ {"power", power, POWER_USAGE},
+ {NULL, NULL, NULL},
+};
+
+static void
+usage(void)
+{
+ struct nvme_function *f;
+
+ f = funcs;
+ fprintf(stderr, "usage:\n");
+ while (f->name != NULL) {
+ fprintf(stderr, "%s", f->usage);
+ f++;
+ }
+ exit(1);
+}
+
+static void
+print_bytes(void *data, uint32_t length)
+{
+ uint32_t i, j;
+ uint8_t *p, *end;
+
+ end = (uint8_t *)data + length;
+
+ for (i = 0; i < length; i++) {
+ p = (uint8_t *)data + (i*16);
+ printf("%03x: ", i*16);
+ for (j = 0; j < 16 && p < end; j++)
+ printf("%02x ", *p++);
+ if (p >= end)
+ break;
+ printf("\n");
+ }
+ printf("\n");
+}
+
+static void
+print_dwords(void *data, uint32_t length)
+{
+ uint32_t *p;
+ uint32_t i, j;
+
+ p = (uint32_t *)data;
+ length /= sizeof(uint32_t);
+
+ for (i = 0; i < length; i+=8) {
+ printf("%03x: ", i*4);
+ for (j = 0; j < 8; j++)
+ printf("%08x ", p[i+j]);
+ printf("\n");
+ }
+
+ printf("\n");
+}
+
+void
+print_hex(void *data, uint32_t length)
+{
+ if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0)
+ print_dwords(data, length);
+ else
+ print_bytes(data, length);
+}
+
+void
+read_controller_data(int fd, struct nvm_identify_controller *cdata)
+{
+ struct nvme_pt_command pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opcode = NVM_ADMIN_IDENTIFY;
+ pt.cmd.cdw10 = 1;
+ pt.buf = cdata;
+ pt.len = sizeof(*cdata);
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "identify request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "identify request returned error");
+}
+
+void
+read_namespace_data(int fd, int nsid, struct nvm_identify_namespace *nsdata)
+{
+ struct nvme_pt_command pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opcode = NVM_ADMIN_IDENTIFY;
+ pt.cmd.nsid = nsid;
+ pt.buf = nsdata;
+ pt.len = sizeof(*nsdata);
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "identify request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "identify request returned error");
+}
+
+int
+open_dev(const char *str, int *fd, int show_error, int exit_on_error)
+{
+ char full_path[64];
+
+ if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
+ if (show_error)
+ warnx("controller/namespace ids must begin with '%s'",
+ NVME_CTRLR_PREFIX);
+ if (exit_on_error)
+ exit(1);
+ else
+ return (EINVAL);
+ }
+
+ snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str);
+ *fd = open(full_path, O_RDWR);
+ if (*fd < 0) {
+ if (show_error)
+ warn("could not open %s", full_path);
+ if (exit_on_error)
+ exit(1);
+ else
+ return (errno);
+ }
+
+ return (0);
+}
+
+void
+parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid)
+{
+ char *nsloc;
+
+ /*
+ * Pull the namespace id from the string. +2 skips past the "ns" part
+ * of the string. Don't search past 10 characters into the string,
+ * otherwise we know it is malformed.
+ */
+ nsloc = strnstr(ns_str, NVME_NS_PREFIX, 10);
+ if (nsloc != NULL)
+ *nsid = strtol(nsloc + 2, NULL, 10);
+ if (nsloc == NULL || (*nsid == 0 && errno != 0))
+ errx(1, "invalid namespace ID '%s'", ns_str);
+
+ /*
+ * The controller string will include only the nvmX part of the
+ * nvmeXnsY string.
+ */
+ snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str);
+}
+
+void
+nvme_strvis(u_char *dst, int dlen, const u_char *src, int slen)
+{
+#define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
+ /* Trim leading and trailing blanks and NULs. */
+ while (slen > 0 && STRVIS_ISWHITE(src[0]))
+ ++src, --slen;
+ while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
+ --slen;
+
+ while (slen > 0) {
+ if (*src < 0x20 || *src >= 0x80) {
+ /* non-printable characters */
+ dlen -= 4;
+ if (dlen < 1)
+ break;
+ *dst++ = '\\';
+ *dst++ = ((*src & 0300) >> 6) + '0';
+ *dst++ = ((*src & 0070) >> 3) + '0';
+ *dst++ = ((*src & 0007) >> 0) + '0';
+ } else if (*src == '\\') {
+ /* quote characters */
+ dlen -= 2;
+ if (dlen < 1)
+ break;
+ *dst++ = '\\';
+ *dst++ = '\\';
+ } else {
+ /* normal characters */
+ if (--dlen < 1)
+ break;
+ *dst++ = *src;
+ }
+ ++src, --slen;
+ }
+
+ *dst++ = 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct nvme_function *f;
+
+ if (argc < 2)
+ usage();
+
+ f = funcs;
+ while (f->name != NULL) {
+ if (strcmp(argv[1], f->name) == 0)
+ f->fn(argc-1, &argv[1]);
+ f++;
+ }
+
+ usage();
+
+ return (0);
+}
Index: src/sbin/nvmectl/nvmectl.h
diff -u /dev/null src/sbin/nvmectl/nvmectl.h:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/nvmectl.h Sat Jun 4 16:29:35 2016
@@ -0,0 +1,94 @@
+/* $NetBSD: nvmectl.h,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * 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: head/sbin/nvmecontrol/nvmecontrol.h 295087 2016-01-30 22:48:06Z imp $
+ */
+
+#ifndef __NVMECTL_H__
+#define __NVMECTL_H__
+
+#include <sys/ioctl.h>
+
+#include <dev/ic/nvmeio.h>
+#include "nvme.h"
+
+#define NVME_CTRLR_PREFIX "nvme"
+#define NVME_NS_PREFIX "ns"
+
+#define DEVLIST_USAGE \
+" nvmectl devlist\n"
+
+#define IDENTIFY_USAGE \
+" nvmectl identify [-x [-v]] <controller id|namespace id>\n"
+
+#if 0
+#define PERFTEST_USAGE \
+" nvmectl perftest <-n num_threads> <-o read|write>\n" \
+" <-s size_in_bytes> <-t time_in_seconds>\n" \
+" <-i intr|wait> [-f refthread] [-p]\n" \
+" <namespace id>\n"
+#endif
+
+#if 0
+#define RESET_USAGE \
+" nvmectl reset <controller id>\n"
+#endif
+
+#define LOGPAGE_USAGE \
+" nvmectl logpage <-p page_id> [-x] <controller id|namespace id>\n" \
+
+#if 0
+#define FIRMWARE_USAGE \
+" nvmectl firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n"
+#endif
+
+#define POWER_USAGE \
+" nvmectl power [-l] [-p new-state [-w workload-hint]] <controller id>\n"
+
+void devlist(int, char *[]);
+void identify(int, char *[]);
+#ifdef PERFTEST_USAGE
+void perftest(int, char *[]);
+#endif
+#ifdef RESET_USAGE
+void reset(int, char *[]);
+#endif
+void logpage(int, char *[]);
+#ifdef FIRMWARE_USAGE
+void firmware(int, char *[]);
+#endif
+void power(int, char *[]);
+
+int open_dev(const char *, int *, int, int);
+void parse_ns_str(const char *, char *, int *);
+void read_controller_data(int, struct nvm_identify_controller *);
+void read_namespace_data(int, int, struct nvm_identify_namespace *);
+void print_hex(void *, uint32_t);
+void read_logpage(int, uint8_t, int, void *, uint32_t);
+void nvme_strvis(uint8_t *, int, const uint8_t *, int);
+
+#endif /* __NVMECTL_H__ */
Index: src/sbin/nvmectl/perftest.c
diff -u /dev/null src/sbin/nvmectl/perftest.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/perftest.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,185 @@
+/* $NetBSD: perftest.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/perftest.c 257531 2013-11-01 22:05:29Z jimharris $");
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+#ifdef PERFTEST_USAGE
+static void
+print_perftest(struct nvme_io_test *io_test, bool perthread)
+{
+ uint64_t io_completed = 0, iops, mbps;
+ uint32_t i;
+
+ for (i = 0; i < io_test->num_threads; i++)
+ io_completed += io_test->io_completed[i];
+
+ iops = io_completed/io_test->time;
+ mbps = iops * io_test->size / (1024*1024);
+
+ printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7ju MB/s: %4ju\n",
+ io_test->num_threads, io_test->size,
+ io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
+ io_test->time, (uintmax_t)iops, (uintmax_t)mbps);
+
+ if (perthread)
+ for (i = 0; i < io_test->num_threads; i++)
+ printf("\t%3d: %8ju IO/s\n", i,
+ (uintmax_t)io_test->io_completed[i]/io_test->time);
+}
+
+static void
+perftest_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, PERFTEST_USAGE);
+ exit(1);
+}
+
+void
+perftest(int argc, char *argv[])
+{
+ struct nvme_io_test io_test;
+ int fd;
+ int ch;
+ char *p;
+ u_long ioctl_cmd = NVME_IO_TEST;
+ bool nflag, oflag, sflag, tflag;
+ int perthread = 0;
+
+ nflag = oflag = sflag = tflag = false;
+
+ memset(&io_test, 0, sizeof(io_test));
+
+ while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
+ switch (ch) {
+ case 'f':
+ if (!strcmp(optarg, "refthread"))
+ io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
+ break;
+ case 'i':
+ if (!strcmp(optarg, "bio") ||
+ !strcmp(optarg, "wait"))
+ ioctl_cmd = NVME_BIO_TEST;
+ else if (!strcmp(optarg, "io") ||
+ !strcmp(optarg, "intr"))
+ ioctl_cmd = NVME_IO_TEST;
+ break;
+ case 'n':
+ nflag = true;
+ io_test.num_threads = strtoul(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid number of threads.\n",
+ optarg);
+ perftest_usage();
+ } else if (io_test.num_threads == 0 ||
+ io_test.num_threads > 128) {
+ fprintf(stderr,
+ "\"%s\" not valid number of threads.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 'o':
+ oflag = true;
+ if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
+ io_test.opc = NVME_OPC_READ;
+ else if (!strcmp(optarg, "write") ||
+ !strcmp(optarg, "WRITE"))
+ io_test.opc = NVME_OPC_WRITE;
+ else {
+ fprintf(stderr, "\"%s\" not valid opcode.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 'p':
+ perthread = 1;
+ break;
+ case 's':
+ sflag = true;
+ io_test.size = strtoul(optarg, &p, 0);
+ if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
+ // do nothing
+ } else if (toupper(*p) == 'K') {
+ io_test.size *= 1024;
+ } else if (toupper(*p) == 'M') {
+ io_test.size *= 1024 * 1024;
+ } else {
+ fprintf(stderr, "\"%s\" not valid size.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 't':
+ tflag = true;
+ io_test.time = strtoul(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid time duration.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ }
+ }
+
+ if (!nflag || !oflag || !sflag || !tflag || optind >= argc)
+ perftest_usage();
+
+ open_dev(argv[optind], &fd, 1, 1);
+ if (ioctl(fd, ioctl_cmd, &io_test) < 0)
+ err(1, "ioctl NVME_IO_TEST failed");
+
+ close(fd);
+ print_perftest(&io_test, perthread);
+ exit(0);
+}
+#endif
Index: src/sbin/nvmectl/power.c
diff -u /dev/null src/sbin/nvmectl/power.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/power.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,194 @@
+/* $NetBSD: power.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * Copyright (c) 2016 Netflix, Inc
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: power.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/power.c 296672 2016-03-11 17:25:18Z dim $");
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+static void
+power_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, POWER_USAGE);
+ exit(1);
+}
+
+static void
+power_list_one(int i, struct nvm_identify_psd *psd)
+{
+ int mpower, apower, ipower;
+
+ mpower = psd->mp;
+ if (!(psd->flags & NVME_PSD_MPS))
+ mpower *= 100;
+ ipower = psd->idlp;
+ if (__SHIFTOUT(psd->ips, NVME_PSD_IPS_MASK) == 1)
+ ipower *= 100;
+ apower = psd->actp;
+ if (__SHIFTOUT(psd->ap, NVME_PSD_APS_MASK) == 1)
+ apower *= 100;
+ printf("%2d: %2d.%04dW%c %3d.%03dms %3d.%03dms %2d %2d %2d %2d %2d.%04dW %2d.%04dW %d\n",
+ i, mpower / 10000, mpower % 10000,
+ (psd->flags & NVME_PSD_NOPS) ? '*' : ' ',
+ psd->enlat / 1000, psd->enlat % 1000,
+ psd->exlat / 1000, psd->exlat % 1000,
+ (uint8_t)(psd->rrt & NVME_PSD_RRT_MASK),
+ (uint8_t)(psd->rrl & NVME_PSD_RRL_MASK),
+ (uint8_t)(psd->rwt & NVME_PSD_RWT_MASK),
+ (uint8_t)(psd->rwl & NVME_PSD_RWL_MASK),
+ ipower / 10000, ipower % 10000, apower / 10000, apower % 10000,
+ (uint16_t)__SHIFTOUT(psd->ap, NVME_PSD_APW_MASK));
+}
+
+static void
+power_list(struct nvm_identify_controller *cdata)
+{
+ int i;
+
+ printf("\nPower States Supported: %d\n\n", cdata->npss + 1);
+ printf(" # Max pwr Enter Lat Exit Lat RT RL WT WL Idle Pwr Act Pwr Workloadd\n");
+ printf("-- -------- --------- --------- -- -- -- -- -------- -------- --\n");
+ for (i = 0; i <= cdata->npss; i++)
+ power_list_one(i, &cdata->psd[i]);
+}
+
+static void
+power_set(int fd, int power_val, int workload, int perm)
+{
+ struct nvme_pt_command pt;
+ uint32_t p;
+
+ p = perm ? (1u << 31) : 0;
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opcode = NVM_ADMIN_SET_FEATURES;
+ pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT | p;
+ pt.cmd.cdw11 = power_val | (workload << 5);
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "set feature power mgmt request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "set feature power mgmt request returned error");
+}
+
+static void
+power_show(int fd)
+{
+ struct nvme_pt_command pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opcode = NVM_ADMIN_GET_FEATURES;
+ pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "set feature power mgmt request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "set feature power mgmt request returned error");
+
+ printf("Current Power Mode is %d\n", pt.cpl.cdw0);
+}
+
+void
+power(int argc, char *argv[])
+{
+ struct nvm_identify_controller cdata;
+ int ch, listflag = 0, powerflag = 0, power_val = 0, fd;
+ int workload = 0;
+ char *end;
+
+ while ((ch = getopt(argc, argv, "lp:w:")) != -1) {
+ switch (ch) {
+ case 'l':
+ listflag = 1;
+ break;
+ case 'p':
+ powerflag = 1;
+ power_val = strtol(optarg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "Invalid power state number: %s\n", optarg);
+ power_usage();
+ }
+ break;
+ case 'w':
+ workload = strtol(optarg, &end, 0);
+ if (*end != '\0') {
+ fprintf(stderr, "Invalid workload hint: %s\n", optarg);
+ power_usage();
+ }
+ break;
+ default:
+ power_usage();
+ }
+ }
+
+ /* Check that a controller was specified. */
+ if (optind >= argc)
+ power_usage();
+
+ if (listflag && powerflag) {
+ fprintf(stderr, "Can't set power and list power states\n");
+ power_usage();
+ }
+
+ open_dev(argv[optind], &fd, 1, 1);
+ read_controller_data(fd, &cdata);
+
+ if (listflag) {
+ power_list(&cdata);
+ goto out;
+ }
+
+ if (powerflag) {
+ power_set(fd, power_val, workload, 0);
+ goto out;
+ }
+ power_show(fd);
+
+out:
+ close(fd);
+ exit(0);
+}
Index: src/sbin/nvmectl/reset.c
diff -u /dev/null src/sbin/nvmectl/reset.c:1.1
--- /dev/null Sat Jun 4 16:29:35 2016
+++ src/sbin/nvmectl/reset.c Sat Jun 4 16:29:35 2016
@@ -0,0 +1,80 @@
+/* $NetBSD: reset.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */
+
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: reset.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/reset.c 253109 2013-07-09 21:14:15Z jimharris $");
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmectl.h"
+
+#ifdef RESET_USAGE
+static void
+reset_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, RESET_USAGE);
+ exit(1);
+}
+
+void
+reset(int argc, char *argv[])
+{
+ int ch, fd;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ reset_usage();
+ }
+ }
+
+ /* Check that a controller was specified. */
+ if (optind >= argc)
+ reset_usage();
+
+ open_dev(argv[optind], &fd, 1, 1);
+ if (ioctl(fd, NVME_RESET_CONTROLLER) < 0)
+ err(1, "reset request to %s failed", argv[optind]);
+
+ exit(0);
+}
+#endif