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 <jimhar...@freebsd.org>
+.\"
+.\" $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 jimhar...@freebsd.org .
+.Pp
+This man page was written by
+.An Jim Harris Aq Mt jimhar...@freebsd.org .
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

Reply via email to