Module Name:    src
Committed By:   martin
Date:           Thu Apr 19 15:37:56 UTC 2018

Modified Files:
        src/sbin/nvmectl [netbsd-8]: Makefile bignum.c devlist.c firmware.c
            identify.c logpage.c nvme.h nvmectl.8 nvmectl.c nvmectl.h
            perftest.c power.c reset.c wdc.c
        src/sys/dev/ic [netbsd-8]: ld_nvme.c nvme.c nvmeio.h nvmereg.h
            nvmevar.h
        src/sys/dev/pci [netbsd-8]: nvme_pci.c
Added Files:
        src/sbin/nvmectl [netbsd-8]: util.c

Log Message:
Pull up following revision(s) (requested by nonaka in ticket #781):

        sbin/nvmectl/Makefile                           1.4
        sbin/nvmectl/bignum.c                           1.2
        sbin/nvmectl/devlist.c                          1.3-1.5
        sbin/nvmectl/firmware.c                         1.3,1.4
        sbin/nvmectl/identify.c                         1.3-1.5
        sbin/nvmectl/logpage.c                          1.5-1.7
        sbin/nvmectl/nvme.h                             1.3
        sbin/nvmectl/nvmectl.8                          1.5
        sbin/nvmectl/nvmectl.c                          1.5-1.7
        sbin/nvmectl/nvmectl.h                          1.5-1.8
        sbin/nvmectl/perftest.c                         1.3-1.5
        sbin/nvmectl/power.c                            1.3,1.4
        sbin/nvmectl/reset.c                            1.2,1.3
        sbin/nvmectl/util.c                             1.1,1.2
        sbin/nvmectl/wdc.c                              1.2-1.4
        sys/dev/ic/ld_nvme.c                            1.20
        sys/dev/ic/nvme.c                               1.38,1.39
        sys/dev/ic/nvmeio.h                             1.2
        sys/dev/ic/nvmereg.h                            1.10,1.11
        sys/dev/ic/nvmevar.h                            1.16
        sys/dev/pci/nvme_pci.c                          1.20

nvmectl(8): Sync with FreeBSD nvmecontrol(8) r328763.

nvmectl(8): fix wdc command usage.

nvme(4): Added some delay before check RDY bit quirk when disabling device.
Pick from FreeBSD nvme(4) r326937.

Add some new structure fileds, opcodes and statuses from NVMe 1.3a.

nvmectl(8): Add big-endian support.
from FreeBSD nvmecontolr(8) r329824.

nvmectl(8): fix subcommand usage.

nvmectl(8): Remove some wdc subcommands from man page.
- wdc drive-log
- wdc get-crash-dump
- wdc purge
- wdc purge-monitor

Typos.

use setprogname()/getprogname(), do not hardcode the prognam name in fixed
strings


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.3.2.1 src/sbin/nvmectl/Makefile
cvs rdiff -u -r1.1 -r1.1.8.1 src/sbin/nvmectl/bignum.c \
    src/sbin/nvmectl/reset.c
cvs rdiff -u -r1.2 -r1.2.8.1 src/sbin/nvmectl/devlist.c \
    src/sbin/nvmectl/identify.c src/sbin/nvmectl/perftest.c \
    src/sbin/nvmectl/power.c
cvs rdiff -u -r1.2 -r1.2.2.1 src/sbin/nvmectl/firmware.c \
    src/sbin/nvmectl/nvme.h
cvs rdiff -u -r1.4 -r1.4.2.1 src/sbin/nvmectl/logpage.c \
    src/sbin/nvmectl/nvmectl.8 src/sbin/nvmectl/nvmectl.c \
    src/sbin/nvmectl/nvmectl.h
cvs rdiff -u -r0 -r1.2.2.2 src/sbin/nvmectl/util.c
cvs rdiff -u -r1.1 -r1.1.4.1 src/sbin/nvmectl/wdc.c
cvs rdiff -u -r1.16.2.2 -r1.16.2.3 src/sys/dev/ic/ld_nvme.c
cvs rdiff -u -r1.30.2.3 -r1.30.2.4 src/sys/dev/ic/nvme.c
cvs rdiff -u -r1.1 -r1.1.12.1 src/sys/dev/ic/nvmeio.h
cvs rdiff -u -r1.9 -r1.9.2.1 src/sys/dev/ic/nvmereg.h
cvs rdiff -u -r1.13.6.2 -r1.13.6.3 src/sys/dev/ic/nvmevar.h
cvs rdiff -u -r1.19 -r1.19.2.1 src/sys/dev/pci/nvme_pci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/nvmectl/Makefile
diff -u src/sbin/nvmectl/Makefile:1.3 src/sbin/nvmectl/Makefile:1.3.2.1
--- src/sbin/nvmectl/Makefile:1.3	Sat Apr 29 00:06:40 2017
+++ src/sbin/nvmectl/Makefile	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.3 2017/04/29 00:06:40 nonaka Exp $
+#	$NetBSD: Makefile,v 1.3.2.1 2018/04/19 15:37:56 martin Exp $
 
 .include <bsd.own.mk>
 
@@ -11,6 +11,7 @@ SRCS+=	logpage.c
 SRCS+=	perftest.c
 SRCS+=	power.c
 SRCS+=	reset.c
+SRCS+=	util.c
 SRCS+=	wdc.c
 SRCS+=	bignum.c
 SRCS+=	humanize_bignum.c

Index: src/sbin/nvmectl/bignum.c
diff -u src/sbin/nvmectl/bignum.c:1.1 src/sbin/nvmectl/bignum.c:1.1.8.1
--- src/sbin/nvmectl/bignum.c:1.1	Mon Feb 13 11:16:46 2017
+++ src/sbin/nvmectl/bignum.c	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: bignum.c,v 1.1 2017/02/13 11:16:46 nonaka Exp $	*/
+/*	$NetBSD: bignum.c,v 1.1.8.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
  * Copyright (c) 2012 Alistair Crooks <a...@netbsd.org>
@@ -1649,7 +1649,7 @@ mp_2expt(mp_int * a, int b)
 	/* zero a as per default */
 	mp_zero(a);
 
-	/* grow a to accomodate the single bit */
+	/* grow a to accommodate the single bit */
 	if ((res = mp_grow(a, b / DIGIT_BIT + 1)) != MP_OKAY) {
 		return res;
 	}
@@ -1683,7 +1683,7 @@ doubled(mp_int * a, mp_int * b)
 {
 	int     x, res, oldused;
 
-	/* grow to accomodate result */
+	/* grow to accommodate result */
 	if (b->alloc < a->used + 1) {
 		if ((res = mp_grow(b, a->used + 1)) != MP_OKAY) {
 			return res;
Index: src/sbin/nvmectl/reset.c
diff -u src/sbin/nvmectl/reset.c:1.1 src/sbin/nvmectl/reset.c:1.1.8.1
--- src/sbin/nvmectl/reset.c:1.1	Sat Jun  4 16:29:35 2016
+++ src/sbin/nvmectl/reset.c	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: reset.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $	*/
+/*	$NetBSD: reset.c,v 1.1.8.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2013 Intel Corporation
  * All rights reserved.
  *
@@ -28,9 +30,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: reset.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $");
+__RCSID("$NetBSD: reset.c,v 1.1.8.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/reset.c 253109 2013-07-09 21:14:15Z jimharris $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/reset.c 326276 2017-11-27 15:37:16Z pfg $");
 #endif
 #endif
 
@@ -51,7 +53,7 @@ static void
 reset_usage(void)
 {
 	fprintf(stderr, "usage:\n");
-	fprintf(stderr, RESET_USAGE);
+	fprintf(stderr, "\t%s " RESET_USAGE, getprogname());
 	exit(1);
 }
 

Index: src/sbin/nvmectl/devlist.c
diff -u src/sbin/nvmectl/devlist.c:1.2 src/sbin/nvmectl/devlist.c:1.2.8.1
--- src/sbin/nvmectl/devlist.c:1.2	Sat Jun  4 20:59:49 2016
+++ src/sbin/nvmectl/devlist.c	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: devlist.c,v 1.2 2016/06/04 20:59:49 joerg Exp $	*/
+/*	$NetBSD: devlist.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2013 Intel Corporation
  * All rights reserved.
  *
@@ -28,9 +30,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: devlist.c,v 1.2 2016/06/04 20:59:49 joerg Exp $");
+__RCSID("$NetBSD: devlist.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/devlist.c 260381 2014-01-06 23:48:47Z jimharris $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/devlist.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -52,7 +54,7 @@ __dead static void
 devlist_usage(void)
 {
 	fprintf(stderr, "usage:\n");
-	fprintf(stderr, DEVLIST_USAGE);
+	fprintf(stderr, "\t%s " DEVLIST_USAGE, getprogname());
 	exit(1);
 }
 
Index: src/sbin/nvmectl/identify.c
diff -u src/sbin/nvmectl/identify.c:1.2 src/sbin/nvmectl/identify.c:1.2.8.1
--- src/sbin/nvmectl/identify.c:1.2	Sat Jun  4 20:59:49 2016
+++ src/sbin/nvmectl/identify.c	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: identify.c,v 1.2 2016/06/04 20:59:49 joerg Exp $	*/
+/*	$NetBSD: identify.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2013 Intel Corporation
  * All rights reserved.
  *
@@ -28,9 +30,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: identify.c,v 1.2 2016/06/04 20:59:49 joerg Exp $");
+__RCSID("$NetBSD: identify.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/identify.c 253476 2013-07-19 21:40:57Z jimharris $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/identify.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -72,6 +74,7 @@ print_controller(struct nvm_identify_con
 		printf("Unlimited\n");
 	else
 		printf("%ld\n", sysconf(_SC_PAGESIZE) * (1 << cdata->mdts));
+	printf("Controller ID:              0x%02x\n", cdata->cntlid);
 	printf("\n");
 
 	printf("Admin Command Set Attributes\n");
@@ -85,6 +88,9 @@ print_controller(struct nvm_identify_con
 	printf("Firmware Activate/Download:  %s\n",
 		(cdata->oacs & NVME_ID_CTRLR_OACS_FW) ?
 		"Supported" : "Not Supported");
+	printf("Namespace Managment:         %s\n",
+		(cdata->oacs & NVME_ID_CTRLR_OACS_NS) ?
+		"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:    ");
@@ -139,6 +145,16 @@ print_controller(struct nvm_identify_con
 	printf("Volatile Write Cache:        %s\n",
 		(cdata->vwc & NVME_ID_CTRLR_VWC_PRESENT) ?
 		"Present" : "Not Present");
+
+	if (cdata->oacs & NVME_ID_CTRLR_OACS_NS) {
+		printf("\n");
+		printf("Namespace Drive Attributes\n");
+		printf("==========================\n");
+		print_bignum("NVM total cap:               ",
+		    cdata->untncap.tnvmcap, "");
+		print_bignum("NVM unallocated cap:         ",
+		    cdata->untncap.unvmcap, "");
+	}
 }
 
 static void
@@ -170,7 +186,7 @@ __dead static void
 identify_usage(void)
 {
 	fprintf(stderr, "usage:\n");
-	fprintf(stderr, IDENTIFY_USAGE);
+	fprintf(stderr, "\t%s " IDENTIFY_USAGE, getprogname());
 	exit(1);
 }
 
Index: src/sbin/nvmectl/perftest.c
diff -u src/sbin/nvmectl/perftest.c:1.2 src/sbin/nvmectl/perftest.c:1.2.8.1
--- src/sbin/nvmectl/perftest.c:1.2	Thu Jul 14 10:02:43 2016
+++ src/sbin/nvmectl/perftest.c	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: perftest.c,v 1.2 2016/07/14 10:02:43 nonaka Exp $	*/
+/*	$NetBSD: perftest.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2013 Intel Corporation
  * All rights reserved.
  *
@@ -28,9 +30,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: perftest.c,v 1.2 2016/07/14 10:02:43 nonaka Exp $");
+__RCSID("$NetBSD: perftest.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/perftest.c 257531 2013-11-01 22:05:29Z jimharris $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/perftest.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -78,7 +80,7 @@ static void
 perftest_usage(void)
 {
 	fprintf(stderr, "usage:\n");
-	fprintf(stderr, PERFTEST_USAGE);
+	fprintf(stderr, "\t%s" PERFTEST_USAGE, getprogname());
 	exit(1);
 }
 
Index: src/sbin/nvmectl/power.c
diff -u src/sbin/nvmectl/power.c:1.2 src/sbin/nvmectl/power.c:1.2.8.1
--- src/sbin/nvmectl/power.c:1.2	Sat Jun  4 20:59:49 2016
+++ src/sbin/nvmectl/power.c	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: power.c,v 1.2 2016/06/04 20:59:49 joerg Exp $	*/
+/*	$NetBSD: power.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
  * Copyright (c) 2016 Netflix, Inc
@@ -28,9 +28,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: power.c,v 1.2 2016/06/04 20:59:49 joerg Exp $");
+__RCSID("$NetBSD: power.c,v 1.2.8.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/power.c 296672 2016-03-11 17:25:18Z dim $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/power.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -52,7 +52,7 @@ __dead static void
 power_usage(void)
 {
 	fprintf(stderr, "usage:\n");
-	fprintf(stderr, POWER_USAGE);
+	fprintf(stderr, "\t%s " POWER_USAGE, getprogname());
 	exit(1);
 }
 
@@ -104,7 +104,7 @@ power_set(int fd, int power_val, int wor
 	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.cdw10 = NVM_FEAT_POWER_MANAGEMENT | p;
 	pt.cmd.cdw11 = power_val | (workload << 5);
 
 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
@@ -121,7 +121,7 @@ power_show(int fd)
 
 	memset(&pt, 0, sizeof(pt));
 	pt.cmd.opcode = NVM_ADMIN_GET_FEATURES;
-	pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT;
+	pt.cmd.cdw10 = NVM_FEAT_POWER_MANAGEMENT;
 
 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
 		err(1, "set feature power mgmt request failed");

Index: src/sbin/nvmectl/firmware.c
diff -u src/sbin/nvmectl/firmware.c:1.2 src/sbin/nvmectl/firmware.c:1.2.2.1
--- src/sbin/nvmectl/firmware.c:1.2	Sat Apr 29 00:06:40 2017
+++ src/sbin/nvmectl/firmware.c	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: firmware.c,v 1.2 2017/04/29 00:06:40 nonaka Exp $	*/
+/*	$NetBSD: firmware.c,v 1.2.2.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2013 EMC Corp.
  * All rights reserved.
  *
@@ -31,9 +33,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: firmware.c,v 1.2 2017/04/29 00:06:40 nonaka Exp $");
+__RCSID("$NetBSD: firmware.c,v 1.2.2.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/firmware.c 313188 2017-02-04 05:52:50Z imp $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/firmware.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -186,7 +188,7 @@ firmware(int argc, char *argv[])
 	int				fd = -1;
 	int				a_flag, s_flag, f_flag;
 	int				commit_action, reboot_required;
-	int				ch,
+	int				ch;
 	char				*p, *image = NULL;
 	char				*controller = NULL, prompt[64];
 	void				*buf = NULL;
Index: src/sbin/nvmectl/nvme.h
diff -u src/sbin/nvmectl/nvme.h:1.2 src/sbin/nvmectl/nvme.h:1.2.2.1
--- src/sbin/nvmectl/nvme.h:1.2	Sat Apr 29 00:06:40 2017
+++ src/sbin/nvmectl/nvme.h	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvme.h,v 1.2 2017/04/29 00:06:40 nonaka Exp $	*/
+/*	$NetBSD: nvme.h,v 1.2.2.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
  * Copyright (C) 2012-2013 Intel Corporation
@@ -34,26 +34,6 @@
 /* Cap nvme to 1MB transfers driver explodes with larger sizes */
 #define NVME_MAX_XFER_SIZE		(MAXPHYS < (1<<20) ? MAXPHYS : (1<<20))
 
-/* 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

Index: src/sbin/nvmectl/logpage.c
diff -u src/sbin/nvmectl/logpage.c:1.4 src/sbin/nvmectl/logpage.c:1.4.2.1
--- src/sbin/nvmectl/logpage.c:1.4	Sat Apr 29 00:06:40 2017
+++ src/sbin/nvmectl/logpage.c	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: logpage.c,v 1.4 2017/04/29 00:06:40 nonaka Exp $	*/
+/*	$NetBSD: logpage.c,v 1.4.2.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2013 EMC Corp.
  * All rights reserved.
  *
@@ -31,9 +33,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: logpage.c,v 1.4 2017/04/29 00:06:40 nonaka Exp $");
+__RCSID("$NetBSD: logpage.c,v 1.4.2.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/logpage.c 314230 2017-02-25 00:09:16Z imp $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/logpage.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -52,12 +54,12 @@ __FBSDID("$FreeBSD: head/sbin/nvmecontro
 #include <unistd.h>
 
 #include "nvmectl.h"
-#include "bn.h"
 
 #define DEFAULT_SIZE	(4096)
 #define MAX_FW_SLOTS	(7)
 
-typedef void (*print_fn_t)(void *buf, uint32_t size);
+typedef void (*print_fn_t)(const struct nvm_identify_controller *cdata, void *buf,
+    uint32_t size);
 
 struct kv_name {
 	uint32_t key;
@@ -78,18 +80,17 @@ kv_lookup(const struct kv_name *kv, size
 }
 
 static void
-print_bin(void *data, uint32_t length)
+print_log_hex(const struct nvm_identify_controller *cdata __unused, void *data,
+    uint32_t length)
 {
-	write(STDOUT_FILENO, data, length);
+	print_hex(data, length);
 }
 
-/* "Missing" from endian.h */
-static __inline uint64_t
-le48dec(const void *pp)
+static void
+print_bin(const struct nvm_identify_controller *cdata __unused, void *data,
+    uint32_t length)
 {
-	uint8_t const *p = (uint8_t const *)pp;
-
-	return (((uint64_t)le16dec(p + 4) << 32) | le32dec(p));
+	write(STDOUT_FILENO, data, length);
 }
 
 static void *
@@ -127,11 +128,30 @@ read_logpage(int fd, uint8_t log_page, i
 }
 
 static void
-print_log_error(void *buf, uint32_t size)
+nvme_error_information_entry_swapbytes(struct nvme_error_information_entry *e)
+{
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	e->error_count = le64toh(e->error_count);
+	e->sqid = le16toh(e->sqid);
+	e->cid = le16toh(e->cid);
+	e->status = le16toh(e->status);
+	e->error_location = le16toh(e->error_location);
+	e->lba = le64toh(e->lba);
+	e->nsid = le32toh(e->nsid);
+	e->command_specific = le64toh(e->command_specific);
+#endif
+}
+
+static void
+print_log_error(const struct nvm_identify_controller *cdata __unused, void *buf,
+    uint32_t size)
 {
 	int					i, nentries;
 	struct nvme_error_information_entry	*entry = buf;
 
+	/* Convert data to host endian */
+	nvme_error_information_entry_swapbytes(entry);
+
 	printf("Error Information Log\n");
 	printf("=====================\n");
 
@@ -171,58 +191,46 @@ print_log_error(void *buf, uint32_t size
 	}
 }
 
-#define	METRIX_PREFIX_BUFSIZ	17
-#define	NO_METRIX_PREFIX_BUFSIZ	42
-
 static void
-print_bignum(const char *title, uint64_t v[2], const char *suffix)
+print_temp(uint16_t t)
 {
-	char buf[64];
-	uint8_t tmp[16];
-	uint64_t l = le64toh(v[0]);
-	uint64_t h = le64toh(v[1]);
-
-	tmp[ 0] = (h >> 56) & 0xff;
-	tmp[ 1] = (h >> 48) & 0xff;
-	tmp[ 2] = (h >> 40) & 0xff;
-	tmp[ 3] = (h >> 32) & 0xff;
-	tmp[ 4] = (h >> 24) & 0xff;
-	tmp[ 5] = (h >> 16) & 0xff;
-	tmp[ 6] = (h >> 8) & 0xff;
-	tmp[ 7] = h & 0xff;
-	tmp[ 8] = (l >> 56) & 0xff;
-	tmp[ 9] = (l >> 48) & 0xff;
-	tmp[10] = (l >> 40) & 0xff;
-	tmp[11] = (l >> 32) & 0xff;
-	tmp[12] = (l >> 24) & 0xff;
-	tmp[13] = (l >> 16) & 0xff;
-	tmp[14] = (l >> 8) & 0xff;
-	tmp[15] = l & 0xff;
-
-	buf[0] = '\0';
-	BIGNUM *bn = BN_bin2bn(tmp, __arraycount(tmp), NULL);
-	if (bn != NULL) {
-		humanize_bignum(buf, METRIX_PREFIX_BUFSIZ + strlen(suffix),
-		    bn, suffix, HN_AUTOSCALE, HN_DECIMAL);
-		BN_free(bn);
-	}
-	if (buf[0] == '\0')
-		snprintf(buf, sizeof(buf), "0x%016jx%016jx", h, l);
-	printf("%-31s %s\n", title, buf);
+	printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15,
+	    (float)t * 9 / 5 - 459.67);
 }
 
 static void
-print_temp(uint16_t t)
+nvme_health_information_page_swapbytes(struct nvme_health_information_page *e)
 {
-	printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15,
-	    (float)t * 9 / 5 - 459.67);
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	u_int i;
+
+	e->composite_temperature = le16toh(e->composite_temperature);
+	nvme_le128toh(e->data_units_read);
+	nvme_le128toh(e->data_units_written);
+	nvme_le128toh(e->host_read_commands);
+	nvme_le128toh(e->host_write_commands);
+	nvme_le128toh(e->controller_busy_time);
+	nvme_le128toh(e->power_cycles);
+	nvme_le128toh(e->power_on_hours);
+	nvme_le128toh(e->unsafe_shutdowns);
+	nvme_le128toh(e->media_errors);
+	nvme_le128toh(e->num_error_info_log_entries);
+	e->warning_temp_time = le32toh(e->warning_temp_time);
+	e->error_temp_time = le32toh(e->error_temp_time);
+	for (i = 0; i < __arraycount(e->temp_sensor); i++)
+		e->temp_sensor[i] = le16toh(e->temp_sensor[i]);
+#endif
 }
 
 static void
-print_log_health(void *buf, uint32_t size __unused)
+print_log_health(const struct nvm_identify_controller *cdata __unused, void *buf,
+    uint32_t size __unused)
 {
 	struct nvme_health_information_page *health = buf;
-	int i;
+	u_int i;
+
+	/* Convert data to host endian */
+	nvme_health_information_page_swapbytes(health);
 
 	printf("SMART/Health Information Log\n");
 	printf("============================\n");
@@ -269,7 +277,7 @@ print_log_health(void *buf, uint32_t siz
 
 	printf("Warning Temp Composite Time:    %d\n", health->warning_temp_time);
 	printf("Error Temp Composite Time:      %d\n", health->error_temp_time);
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < __arraycount(health->temp_sensor); i++) {
 		if (health->temp_sensor[i] == 0)
 			continue;
 		printf("Temperature Sensor %d:           ", i + 1);
@@ -278,16 +286,37 @@ print_log_health(void *buf, uint32_t siz
 }
 
 static void
-print_log_firmware(void *buf, uint32_t size __unused)
+nvme_firmware_page_swapbytes(struct nvme_firmware_page *e)
 {
-	u_int				i;
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	u_int i;
+
+	for (i = 0; i < __arraycount(e->revision); i++)
+		e->revision[i] = le64toh(e->revision[i]);
+#endif
+}
+
+static void
+print_log_firmware(const struct nvm_identify_controller *cdata, void *buf,
+    uint32_t size __unused)
+{
+	u_int				i, slots;
 	const char			*status;
 	struct nvme_firmware_page	*fw = buf;
 
+	/* Convert data to host endian */
+	nvme_firmware_page_swapbytes(fw);
+
 	printf("Firmware Slot Log\n");
 	printf("=================\n");
 
-	for (i = 0; i < MAX_FW_SLOTS; i++) {
+	if (!(cdata->oacs & NVME_ID_CTRLR_OACS_FW))
+		slots = 1;
+	else
+		slots = MIN(__SHIFTOUT(cdata->frmw, NVME_ID_CTRLR_FRMW_NSLOT),
+		    MAX_FW_SLOTS);
+
+	for (i = 0; i < slots; i++) {
 		printf("Slot %d: ", i + 1);
 		if (__SHIFTOUT(fw->afi, NVME_FW_PAGE_AFI_SLOT) == i + 1)
 			status = "  Active";
@@ -314,10 +343,29 @@ print_log_firmware(void *buf, uint32_t s
  * offset 147: it is only 1 byte, not 6.
  */
 static void
-print_intel_temp_stats(void *buf, uint32_t size __unused)
+intel_log_temp_stats_swapbytes(struct intel_log_temp_stats *e)
+{
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	e->current = le64toh(e->current);
+	e->overtemp_flag_last = le64toh(e->overtemp_flag_last);
+	e->overtemp_flag_life = le64toh(e->overtemp_flag_life);
+	e->max_temp = le64toh(e->max_temp);
+	e->min_temp = le64toh(e->min_temp);
+	e->max_oper_temp = le64toh(e->max_oper_temp);
+	e->min_oper_temp = le64toh(e->min_oper_temp);
+	e->est_offset = le64toh(e->est_offset);
+#endif
+}
+
+static void
+print_intel_temp_stats(const struct nvm_identify_controller *cdata __unused,
+    void *buf, uint32_t size __unused)
 {
 	struct intel_log_temp_stats	*temp = buf;
 
+	/* Convert data to host endian */
+	intel_log_temp_stats_swapbytes(temp);
+
 	printf("Intel Temperature Log\n");
 	printf("=====================\n");
 
@@ -344,7 +392,8 @@ print_intel_temp_stats(void *buf, uint32
  * Read and write stats pages have identical encoding.
  */
 static void
-print_intel_read_write_lat_log(void *buf, uint32_t size __unused)
+print_intel_read_write_lat_log(const struct nvm_identify_controller *cdata __unused,
+    void *buf, uint32_t size __unused)
 {
 	const char *walker = buf;
 	int i;
@@ -363,21 +412,23 @@ print_intel_read_write_lat_log(void *buf
 }
 
 static void
-print_intel_read_lat_log(void *buf, uint32_t size)
+print_intel_read_lat_log(const struct nvm_identify_controller *cdata, void *buf,
+    uint32_t size)
 {
 
 	printf("Intel Read Latency Log\n");
 	printf("======================\n");
-	print_intel_read_write_lat_log(buf, size);
+	print_intel_read_write_lat_log(cdata, buf, size);
 }
 
 static void
-print_intel_write_lat_log(void *buf, uint32_t size)
+print_intel_write_lat_log(const struct nvm_identify_controller *cdata, void *buf,
+    uint32_t size)
 {
 
 	printf("Intel Write Latency Log\n");
 	printf("=======================\n");
-	print_intel_read_write_lat_log(buf, size);
+	print_intel_read_write_lat_log(cdata, buf, size);
 }
 
 /*
@@ -385,7 +436,8 @@ print_intel_write_lat_log(void *buf, uin
  * Samsung also implements this and some extra data not documented.
  */
 static void
-print_intel_add_smart(void *buf, uint32_t size __unused)
+print_intel_add_smart(const struct nvm_identify_controller *cdata __unused,
+    void *buf, uint32_t size __unused)
 {
 	uint8_t *walker = buf;
 	uint8_t *end = walker + 150;
@@ -454,7 +506,8 @@ print_intel_add_smart(void *buf, uint32_
  * Appendix A for details
  */
 
-typedef void (*subprint_fn_t)(void *buf, uint16_t subtype, uint8_t res, uint32_t size);
+typedef void (*subprint_fn_t)(void *buf, uint16_t subtype, uint8_t res,
+    uint32_t size);
 
 struct subpage_print {
 	uint16_t key;
@@ -825,7 +878,8 @@ kv_indirect(void *buf, uint32_t subtype,
 }
 
 static void
-print_hgst_info_log(void *buf, uint32_t size __unused)
+print_hgst_info_log(const struct nvm_identify_controller *cdata __unused, void *buf,
+    uint32_t size __unused)
 {
 	uint8_t	*walker, *end, *subpage;
 	int pages __unused;
@@ -899,7 +953,7 @@ __dead static void
 logpage_usage(void)
 {
 	fprintf(stderr, "usage:\n");
-	fprintf(stderr, LOGPAGE_USAGE);
+	fprintf(stderr, "\t%s " LOGPAGE_USAGE, getprogname());
 	exit(1);
 }
 
@@ -1002,7 +1056,7 @@ logpage(int argc, char *argv[])
 			    "smart/health information");
 	}
 
-	print_fn = print_hex;
+	print_fn = print_log_hex;
 	size = DEFAULT_SIZE;
 	if (binflag)
 		print_fn = print_bin;
@@ -1034,7 +1088,7 @@ logpage(int argc, char *argv[])
 	/* Read the log page */
 	buf = get_log_buffer(size);
 	read_logpage(fd, log_page, nsid, buf, size);
-	print_fn(buf, size);
+	print_fn(&cdata, buf, size);
 
 	close(fd);
 	exit(0);
Index: src/sbin/nvmectl/nvmectl.8
diff -u src/sbin/nvmectl/nvmectl.8:1.4 src/sbin/nvmectl/nvmectl.8:1.4.2.1
--- src/sbin/nvmectl/nvmectl.8:1.4	Sun Apr 30 15:59:18 2017
+++ src/sbin/nvmectl/nvmectl.8	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-.\" $NetBSD: nvmectl.8,v 1.4 2017/04/30 15:59:18 wiz Exp $
+.\" $NetBSD: nvmectl.8,v 1.4.2.1 2018/04/19 15:37:56 martin Exp $
 .\"
 .\" Copyright (c) 2012 Intel Corporation
 .\" All rights reserved.
@@ -54,10 +54,10 @@
 .\".Aq Fl o Ar read|write
 .\".Aq Fl s Ar size_in_bytes
 .\".Aq Fl t Ar time_in_sec
-.\".Aq namespace id
+.\".Aq namespace_id
 .\".Nm
 .\".Ic reset
-.\".Aq controller id
+.\".Aq controller_id
 .Nm
 .Ic logpage
 .Op Fl x
@@ -80,21 +80,7 @@
 .Nm
 .Ic wdc cap-diag
 .Op Fl o path_template
-.Ar device id
-.Nm
-.Ic wdc drive-log
-.Op Fl o path_template
-.Ar device id
-.Nm
-.Ic wdc get-crash-dump
-.Op Fl o path_template
-.Ar device id
-.\" .Nm
-.\" .Ic wdc purge
-.\" .Aq device id
-.\" .Nm
-.\" .Ic wdc purge-monitor
-.\" .Aq device id
+.Ar device_id
 .Sh DESCRIPTION
 NVM Express (NVMe) is a storage protocol standard, for SSDs and other
 high-speed storage devices over PCI Express.
Index: src/sbin/nvmectl/nvmectl.c
diff -u src/sbin/nvmectl/nvmectl.c:1.4 src/sbin/nvmectl/nvmectl.c:1.4.2.1
--- src/sbin/nvmectl/nvmectl.c:1.4	Wed May  3 01:37:16 2017
+++ src/sbin/nvmectl/nvmectl.c	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: nvmectl.c,v 1.4 2017/05/03 01:37:16 christos Exp $	*/
+/*	$NetBSD: nvmectl.c,v 1.4.2.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2013 Intel Corporation
  * All rights reserved.
  *
@@ -28,9 +30,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: nvmectl.c,v 1.4 2017/05/03 01:37:16 christos Exp $");
+__RCSID("$NetBSD: nvmectl.c,v 1.4.2.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 314229 2017-02-25 00:09:12Z imp $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -52,7 +54,7 @@ __FBSDID("$FreeBSD: head/sbin/nvmecontro
 
 #include "nvmectl.h"
 
-static struct nvme_function funcs[] = {
+static const struct nvme_function funcs[] = {
 	{"devlist",	devlist,	DEVLIST_USAGE},
 	{"identify",	identify,	IDENTIFY_USAGE},
 #ifdef PERFTEST_USAGE
@@ -71,21 +73,21 @@ static struct nvme_function funcs[] = {
 };
 
 static __dead void
-gen_usage(struct nvme_function *f)
+gen_usage(const struct nvme_function *f)
 {
 
 	fprintf(stderr, "usage:\n");
 	while (f->name != NULL) {
-		fprintf(stderr, "%s", f->usage);
+		fprintf(stderr, "\t%s %s", getprogname(), f->usage);
 		f++;
 	}
 	exit(1);
 }
 
 __dead void
-dispatch(int argc, char *argv[], struct nvme_function *tbl)
+dispatch(int argc, char *argv[], const struct nvme_function *tbl)
 {
-	struct nvme_function *f = tbl;
+	const struct nvme_function *f = tbl;
 
 	if (argv[1] == NULL)
 		gen_usage(tbl);
@@ -165,6 +167,9 @@ read_controller_data(int fd, struct nvm_
 
 	if (nvme_completion_is_error(&pt.cpl))
 		errx(1, "identify request returned error");
+
+	/* Convert data to host endian */
+	nvme_identify_controller_swapbytes(cdata);
 }
 
 void
@@ -184,6 +189,9 @@ read_namespace_data(int fd, int nsid, st
 
 	if (nvme_completion_is_error(&pt.cpl))
 		errx(1, "identify request returned error");
+
+	/* Convert data to host endian */
+	nvme_identify_namespace_swapbytes(nsdata);
 }
 
 int
@@ -238,48 +246,10 @@ parse_ns_str(const char *ns_str, char *c
 	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[])
 {
+	setprogname(argv[0]);
 
 	if (argc < 2)
 		gen_usage(funcs);
Index: src/sbin/nvmectl/nvmectl.h
diff -u src/sbin/nvmectl/nvmectl.h:1.4 src/sbin/nvmectl/nvmectl.h:1.4.2.1
--- src/sbin/nvmectl/nvmectl.h:1.4	Wed May  3 01:37:16 2017
+++ src/sbin/nvmectl/nvmectl.h	Thu Apr 19 15:37:56 2018
@@ -1,6 +1,8 @@
-/*	$NetBSD: nvmectl.h,v 1.4 2017/05/03 01:37:16 christos Exp $	*/
+/*	$NetBSD: nvmectl.h,v 1.4.2.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (C) 2012-2013 Intel Corporation
  * All rights reserved.
  *
@@ -25,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/nvmecontrol/nvmecontrol.h 314230 2017-02-25 00:09:16Z imp $
+ * $FreeBSD: head/sbin/nvmecontrol/nvmecontrol.h 326276 2017-11-27 15:37:16Z pfg $
  */
 
 #ifndef __NVMECTL_H__
@@ -48,38 +50,38 @@ struct nvme_function {
 #define NVME_NS_PREFIX		"ns"
 
 #define DEVLIST_USAGE							       \
-"       nvmectl devlist\n"
+"devlist\n"
 
 #define IDENTIFY_USAGE							       \
-"       nvmectl identify [-x [-v]] <controller id|namespace id>\n"
+"identify [-x [-v]] <controller_id|namespace_id>\n"
 
-#if 0
+#ifdef ENABLE_PREFTEST
 #define PERFTEST_USAGE							       \
-"       nvmectl perftest <-n num_threads> <-o read|write>\n"		       \
+"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"
+"                        <namespace_id>\n"
 #endif
 
-#if 0
+#ifdef ENABLE_RESET
 #define RESET_USAGE							       \
-"       nvmectl reset <controller id>\n"
+"reset <controller id>\n"
 #endif
 
 #define LOGPAGE_USAGE							       \
-"       nvmectl logpage <-p page_id> [-b] [-v vendor] [-x] "		       \
-    "<controller id|namespace id>\n"
+"logpage <-p page_id> [-b] [-v vendor] [-x] "				       \
+    "<controller_id|namespace_id>\n"
 
-#if 0
+#ifdef ENABLE_FIRMWARE
 #define FIRMWARE_USAGE							       \
-"       nvmectl firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n"
+"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"
+"power [-l] [-p new-state [-w workload-hint]] <controller_id>\n"
 
 #define WDC_USAGE							       \
-"       nvmecontrol wdc (cap-diag|drive-log|get-crash-dump|purge|purge-montior)\n"
+"wdc cap-diag [-o path-templete]\n"
 
 void devlist(int, char *[]) __dead;
 void identify(int, char *[]) __dead;
@@ -102,7 +104,11 @@ void read_controller_data(int, struct nv
 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);
-__dead void dispatch(int argc, char *argv[], struct nvme_function *f);
+__dead void dispatch(int argc, char *argv[], const struct nvme_function *f);
+
+/* Utility Routines */
 void nvme_strvis(uint8_t *, int, const uint8_t *, int);
+void print_bignum(const char *, uint64_t v[2], const char *);
+uint64_t le48dec(const void *);
 
 #endif	/* __NVMECTL_H__ */

Index: src/sbin/nvmectl/wdc.c
diff -u src/sbin/nvmectl/wdc.c:1.1 src/sbin/nvmectl/wdc.c:1.1.4.1
--- src/sbin/nvmectl/wdc.c:1.1	Sat Apr 29 00:08:46 2017
+++ src/sbin/nvmectl/wdc.c	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.1 2017/04/29 00:08:46 nonaka Exp $	*/
+/*	$NetBSD: wdc.c,v 1.1.4.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
  * Copyright (c) 2017 Netflix, Inc
@@ -28,9 +28,9 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: wdc.c,v 1.1 2017/04/29 00:08:46 nonaka Exp $");
+__RCSID("$NetBSD: wdc.c,v 1.1.4.1 2018/04/19 15:37:56 martin Exp $");
 #if 0
-__FBSDID("$FreeBSD: head/sbin/nvmecontrol/wdc.c 316105 2017-03-28 20:34:02Z ngie $");
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/wdc.c 329824 2018-02-22 13:32:31Z wma $");
 #endif
 #endif
 
@@ -54,36 +54,12 @@ __FBSDID("$FreeBSD: head/sbin/nvmecontro
 #define WDC_NVME_CAP_DIAG_OPCODE	0xe6
 #define WDC_NVME_CAP_DIAG_CMD		0x0000
 
-#define WDC_NVME_DIAG_OPCODE		0xc6
-#define WDC_NVME_DRIVE_LOG_SIZE_CMD	0x0120
-#define WDC_NVME_DRIVE_LOG_CMD		0x0020
-#define WDC_NVME_CRASH_DUMP_SIZE_CMD	0x0320
-#define WDC_NVME_CRASH_DUMP_CMD		0x0420
-#define WDC_NVME_PFAIL_DUMP_SIZE_CMD	0x0520
-#define WDC_NVME_PFAIL_DUMP_CMD		0x0620
-
-#define WDC_NVME_CLEAR_DUMP_OPCODE	0xff
-#define WDC_NVME_CLEAR_CRASH_DUMP_CMD	0x0503
-#define WDC_NVME_CLEAR_PFAIL_DUMP_CMD	0x0603
-
 static void wdc_cap_diag(int argc, char *argv[]);
-static void wdc_drive_log(int argc, char *argv[]);
-static void wdc_get_crash_dump(int argc, char *argv[]);
-static void wdc_purge(int argc, char *argv[]);
-static void wdc_purge_monitor(int argc, char *argv[]);
-
-#define WDC_CAP_DIAG_USAGE	"\tnvmecontrol wdc cap-diag [-o path-template]\n"
-#define WDC_DRIVE_LOG_USAGE	"\tnvmecontrol wdc drive-log [-o path-template]\n"
-#define WDC_GET_CRASH_DUMP_USAGE "\tnvmecontrol wdc get-crash-dump [-o path-template]\n"
-#define WDC_PURGE_USAGE		"\tnvmecontrol wdc purge [-o path-template]\n"
-#define WDC_PURGE_MONITOR_USAGE	"\tnvmecontrol wdc purge-monitor\n"
 
-static struct nvme_function wdc_funcs[] = {
+#define WDC_CAP_DIAG_USAGE	"wdc cap-diag [-o path-template]\n"
+
+static const struct nvme_function wdc_funcs[] = {
 	{"cap-diag",		wdc_cap_diag,		WDC_CAP_DIAG_USAGE},
-	{"drive-log",		wdc_drive_log,		WDC_DRIVE_LOG_USAGE},
-	{"get-crash-dump",	wdc_get_crash_dump,	WDC_GET_CRASH_DUMP_USAGE},
-	{"purge",		wdc_purge,		WDC_PURGE_USAGE},
-	{"purge_monitor",	wdc_purge_monitor,	WDC_PURGE_MONITOR_USAGE},
 	{NULL,			NULL,			NULL},
 };
 
@@ -130,12 +106,13 @@ wdc_get_data(int fd, uint32_t opcode, ui
 
 static void
 wdc_do_dump(int fd, char *tmpl, const char *suffix, uint32_t opcode,
-    uint32_t size_cmd, uint32_t cmd, int len_off)
+    uint32_t cmd, int len_off)
 {
+	int first;
 	int fd2;
 	uint8_t *buf;
 	uint32_t len, offset;
-	ssize_t resid;
+	size_t resid;
 	long page_size;
 
 	page_size = sysconf(_SC_PAGESIZE);
@@ -144,56 +121,52 @@ wdc_do_dump(int fd, char *tmpl, const ch
 
 	wdc_append_serial_name(fd, tmpl, MAXPATHLEN, suffix);
 
-	buf = aligned_alloc(page_size, WDC_NVME_TOC_SIZE);
-	if (buf == NULL)
-		errx(1, "Can't get buffer to get size");
-	wdc_get_data(fd, opcode, WDC_NVME_TOC_SIZE,
-	    0, size_cmd, buf, WDC_NVME_TOC_SIZE);
-	len = be32dec(buf + len_off);
-
-	if (len == 0)
-		errx(1, "No data for %s", suffix);
-
-	printf("Dumping %d bytes to %s\n", len, tmpl);
 	/* XXX overwrite protection? */
-	fd2 = open(tmpl, O_WRONLY | O_CREAT | O_TRUNC);
+	fd2 = open(tmpl, O_WRONLY | O_CREAT | O_TRUNC, 0644);
 	if (fd2 < 0)
 		err(1, "open %s", tmpl);
-	offset = 0;
 	buf = aligned_alloc(page_size, NVME_MAX_XFER_SIZE);
 	if (buf == NULL)
 		errx(1, "Can't get buffer to read dump");
-	while (len > 0) {
+	offset = 0;
+	len = NVME_MAX_XFER_SIZE;
+	first = 1;
+
+	do {
 		resid = len > NVME_MAX_XFER_SIZE ? NVME_MAX_XFER_SIZE : len;
 		wdc_get_data(fd, opcode, resid, offset, cmd, buf, resid);
-		if (write(fd2, buf, resid) != resid)
+		if (first) {
+			len = be32dec(buf + len_off);
+			if (len == 0)
+				errx(1, "No data for %s", suffix);
+			if (memcmp("E6LG", buf, 4) != 0)
+				printf("Expected header of E6LG, found '%4.4s' instead\n",
+				    buf);
+			printf("Dumping %d bytes of version %d.%d log to %s\n", len,
+			    buf[8], buf[9], tmpl);
+			/*
+			 * Adjust amount to dump if total dump < 1MB,
+			 * though it likely doesn't matter to the WDC
+			 * analysis tools.
+			 */
+			if (resid > len)
+				resid = len;
+			first = 0;
+		}
+		if (write(fd2, buf, resid) != (ssize_t)resid)
 			err(1, "write");
 		offset += resid;
 		len -= resid;
-	}
+	} while (len > 0);
 	free(buf);
 	close(fd2);
 }
 
-static void
-wdc_do_clear_dump(int fd, uint32_t opcode, uint32_t cmd)
-{
-	struct nvme_pt_command	pt;
-
-	memset(&pt, 0, sizeof(pt));
-	pt.cmd.opcode = opcode;
-	pt.cmd.cdw12 = cmd;
-	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
-		err(1, "wdc_do_clear_dump request failed");
-	if (nvme_completion_is_error(&pt.cpl))
-		errx(1, "wdc_do_clear_dump request returned error");
-}
-
 __dead static void
 wdc_cap_diag_usage(void)
 {
 	fprintf(stderr, "usage:\n");
-	fprintf(stderr, WDC_CAP_DIAG_USAGE);
+	fprintf(stderr, "\t%s " WDC_CAP_DIAG_USAGE, getprogname());
 	exit(1);
 }
 
@@ -219,133 +192,13 @@ wdc_cap_diag(int argc, char *argv[])
 	open_dev(argv[optind], &fd, 1, 1);
 
 	wdc_do_dump(fd, path_tmpl, "cap_diag", WDC_NVME_CAP_DIAG_OPCODE,
-	    WDC_NVME_CAP_DIAG_CMD, WDC_NVME_CAP_DIAG_CMD, 4);
+	    WDC_NVME_CAP_DIAG_CMD, 4);
 
 	close(fd);
 
 	exit(1);	
 }
 
-__dead static void
-wdc_drive_log_usage(void)
-{
-	fprintf(stderr, "usage:\n");
-	fprintf(stderr, WDC_DRIVE_LOG_USAGE);
-	exit(1);
-}
-
-__dead static void
-wdc_drive_log(int argc, char *argv[])
-{
-	char path_tmpl[MAXPATHLEN];
-	int ch, fd;
-
-	path_tmpl[0] = '\0';
-	while ((ch = getopt(argc, argv, "o:")) != -1) {
-		switch ((char)ch) {
-		case 'o':
-			strlcpy(path_tmpl, optarg, MAXPATHLEN);
-			break;
-		default:
-			wdc_drive_log_usage();
-		}
-	}
-	/* Check that a controller was specified. */
-	if (optind >= argc)
-		wdc_drive_log_usage();
-	open_dev(argv[optind], &fd, 1, 1);
-
-	wdc_do_dump(fd, path_tmpl, "drive_log", WDC_NVME_DIAG_OPCODE,
-	    WDC_NVME_DRIVE_LOG_SIZE_CMD, WDC_NVME_DRIVE_LOG_CMD, 0);
-
-	close(fd);
-
-	exit(1);
-}
-
-__dead static void
-wdc_get_crash_dump_usage(void)
-{
-	fprintf(stderr, "usage:\n");
-	fprintf(stderr, WDC_CAP_DIAG_USAGE);
-	exit(1);
-}
-
-__dead static void
-wdc_get_crash_dump(int argc, char *argv[])
-{
-	char path_tmpl[MAXPATHLEN];
-	int ch, fd;
-
-	while ((ch = getopt(argc, argv, "o:")) != -1) {
-		switch ((char)ch) {
-		case 'o':
-			strlcpy(path_tmpl, optarg, MAXPATHLEN);
-			break;
-		default:
-			wdc_get_crash_dump_usage();
-		}
-	}
-	/* Check that a controller was specified. */
-	if (optind >= argc)
-		wdc_get_crash_dump_usage();
-	open_dev(argv[optind], &fd, 1, 1);
-
-	wdc_do_dump(fd, path_tmpl, "crash_dump", WDC_NVME_DIAG_OPCODE,
-	    WDC_NVME_CRASH_DUMP_SIZE_CMD, WDC_NVME_CRASH_DUMP_CMD, 0);
-	wdc_do_clear_dump(fd, WDC_NVME_CLEAR_DUMP_OPCODE,
-	    WDC_NVME_CLEAR_CRASH_DUMP_CMD);
-//	wdc_led_beacon_disable(fd);
-	wdc_do_dump(fd, path_tmpl, "pfail_dump", WDC_NVME_DIAG_OPCODE,
-	    WDC_NVME_PFAIL_DUMP_SIZE_CMD, WDC_NVME_PFAIL_DUMP_CMD, 0);
-	wdc_do_clear_dump(fd, WDC_NVME_CLEAR_DUMP_OPCODE,
-		WDC_NVME_CLEAR_PFAIL_DUMP_CMD);
-
-	close(fd);
-
-	exit(1);
-}
-
-__dead static void
-wdc_purge(int argc, char *argv[])
-{
-	char path_tmpl[MAXPATHLEN];
-	int ch;
-
-	while ((ch = getopt(argc, argv, "o:")) != -1) {
-		switch ((char)ch) {
-		case 'o':
-			strlcpy(path_tmpl, optarg, MAXPATHLEN);
-			break;
-		default:
-			wdc_cap_diag_usage();
-		}
-	}
-
-	printf("purge has not been implemented.\n");
-	exit(1);
-}
-
-__dead static void
-wdc_purge_monitor(int argc, char *argv[])
-{
-	char path_tmpl[MAXPATHLEN];
-	int ch;
-
-	while ((ch = getopt(argc, argv, "o:")) != -1) {
-		switch ((char)ch) {
-		case 'o':
-			strlcpy(path_tmpl, optarg, MAXPATHLEN);
-			break;
-		default:
-			wdc_cap_diag_usage();
-		}
-	}
-
-	printf("purge has not been implemented.\n");
-	exit(1);
-}
-
 void
 wdc(int argc, char *argv[])
 {

Index: src/sys/dev/ic/ld_nvme.c
diff -u src/sys/dev/ic/ld_nvme.c:1.16.2.2 src/sys/dev/ic/ld_nvme.c:1.16.2.3
--- src/sys/dev/ic/ld_nvme.c:1.16.2.2	Sun Mar 18 11:05:27 2018
+++ src/sys/dev/ic/ld_nvme.c	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_nvme.c,v 1.16.2.2 2018/03/18 11:05:27 martin Exp $	*/
+/*	$NetBSD: ld_nvme.c,v 1.16.2.3 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
  * Copyright (C) 2016 NONAKA Kimihiro <non...@netbsd.org>
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.16.2.2 2018/03/18 11:05:27 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.16.2.3 2018/04/19 15:37:56 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -86,7 +86,6 @@ ld_nvme_attach(device_t parent, device_t
 	struct nvme_attach_args *naa = aux;
 	struct nvme_namespace *ns;
 	struct nvm_namespace_format *f;
-	uint64_t nsze;
 	int error;
 
 	ld->sc_dv = self;
@@ -104,11 +103,10 @@ ld_nvme_attach(device_t parent, device_t
 
 	ns = nvme_ns_get(sc->sc_nvme, sc->sc_nsid);
 	KASSERT(ns);
-	nsze = lemtoh64(&ns->ident->nsze);
 	f = &ns->ident->lbaf[NVME_ID_NS_FLBAS(ns->ident->flbas)];
 
 	ld->sc_secsize = 1 << f->lbads;
-	ld->sc_secperunit = nsze;
+	ld->sc_secperunit = ns->ident->nsze;
 	ld->sc_maxxfer = naa->naa_maxphys;
 	ld->sc_maxqueuecnt = naa->naa_qentries;
 	ld->sc_start = ld_nvme_start;

Index: src/sys/dev/ic/nvme.c
diff -u src/sys/dev/ic/nvme.c:1.30.2.3 src/sys/dev/ic/nvme.c:1.30.2.4
--- src/sys/dev/ic/nvme.c:1.30.2.3	Mon Apr  9 13:23:29 2018
+++ src/sys/dev/ic/nvme.c	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvme.c,v 1.30.2.3 2018/04/09 13:23:29 bouyer Exp $	*/
+/*	$NetBSD: nvme.c,v 1.30.2.4 2018/04/19 15:37:56 martin Exp $	*/
 /*	$OpenBSD: nvme.c,v 1.49 2016/04/18 05:59:50 dlg Exp $ */
 
 /*
@@ -18,7 +18,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.30.2.3 2018/04/09 13:23:29 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.30.2.4 2018/04/19 15:37:56 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -40,6 +40,8 @@ __KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.3
 #include <dev/ic/nvmevar.h>
 #include <dev/ic/nvmeio.h>
 
+#define	B4_CHK_RDY_DELAY_MS	2300	/* workaround controller bug */
+
 int nvme_adminq_size = 32;
 int nvme_ioq_size = 1024;
 
@@ -218,15 +220,6 @@ static int
 nvme_ready(struct nvme_softc *sc, uint32_t rdy)
 {
 	u_int i = 0;
-	uint32_t cc;
-
-	cc = nvme_read4(sc, NVME_CC);
-	if (((cc & NVME_CC_EN) != 0) != (rdy != 0)) {
-		aprint_error_dev(sc->sc_dev,
-		    "controller enabled status expected %d, found to be %d\n",
-		    (rdy != 0), ((cc & NVME_CC_EN) != 0));
-		return ENXIO;
-	}
 
 	while ((nvme_read4(sc, NVME_CSTS) & NVME_CSTS_RDY) != rdy) {
 		if (i++ > sc->sc_rdy_to)
@@ -243,17 +236,24 @@ static int
 nvme_enable(struct nvme_softc *sc, u_int mps)
 {
 	uint32_t cc, csts;
+	int error;
 
 	cc = nvme_read4(sc, NVME_CC);
 	csts = nvme_read4(sc, NVME_CSTS);
-	
-	if (ISSET(cc, NVME_CC_EN)) {
-		aprint_error_dev(sc->sc_dev, "controller unexpectedly enabled, failed to stay disabled\n");
 
+	/*
+	 * See note in nvme_disable. Short circuit if we're already enabled.
+	 */
+	if (ISSET(cc, NVME_CC_EN)) {
 		if (ISSET(csts, NVME_CSTS_RDY))
-			return 1;
+			return 0;
 
 		goto waitready;
+	} else {
+		/* EN == 0 already wait for RDY == 0 or fail */
+		error = nvme_ready(sc, 0);
+		if (error)
+			return error;
 	}
 
 	nvme_write8(sc, NVME_ASQ, NVME_DMA_DVA(sc->sc_admin_q->q_sq_dmamem));
@@ -280,7 +280,6 @@ nvme_enable(struct nvme_softc *sc, u_int
 	nvme_write4(sc, NVME_CC, cc);
 	nvme_barrier(sc, 0, sc->sc_ios,
 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
-	delay(5000);
 
     waitready:
 	return nvme_ready(sc, NVME_CSTS_RDY);
@@ -290,20 +289,44 @@ static int
 nvme_disable(struct nvme_softc *sc)
 {
 	uint32_t cc, csts;
+	int error;
 
 	cc = nvme_read4(sc, NVME_CC);
 	csts = nvme_read4(sc, NVME_CSTS);
 
-	if (ISSET(cc, NVME_CC_EN) && !ISSET(csts, NVME_CSTS_RDY))
-		nvme_ready(sc, NVME_CSTS_RDY);
+	/*
+	 * Per 3.1.5 in NVME 1.3 spec, transitioning CC.EN from 0 to 1
+	 * when CSTS.RDY is 1 or transitioning CC.EN from 1 to 0 when
+	 * CSTS.RDY is 0 "has undefined results" So make sure that CSTS.RDY
+	 * isn't the desired value. Short circuit if we're already disabled.
+	 */
+	if (ISSET(cc, NVME_CC_EN)) {
+		if (!ISSET(csts, NVME_CSTS_RDY)) {
+			/* EN == 1, wait for RDY == 1 or fail */
+			error = nvme_ready(sc, NVME_CSTS_RDY);
+			if (error)
+				return error;
+		}
+	} else {
+		/* EN == 0 already wait for RDY == 0 */
+		if (!ISSET(csts, NVME_CSTS_RDY))
+			return 0;
 
-	CLR(cc, NVME_CC_EN);
+		goto waitready;
+	}
 
+	CLR(cc, NVME_CC_EN);
 	nvme_write4(sc, NVME_CC, cc);
 	nvme_barrier(sc, 0, sc->sc_ios, BUS_SPACE_BARRIER_READ);
-	
-	delay(5000);
 
+	/*
+	 * Some drives have issues with accessing the mmio after we disable,
+	 * so delay for a bit after we write the bit to cope with these issues.
+	 */
+	if (ISSET(sc->sc_quirks, NVME_QUIRK_DELAY_B4_CHK_RDY))
+		delay(B4_CHK_RDY_DELAY_MS);
+
+    waitready:
 	return nvme_ready(sc, 0);
 }
 
@@ -599,7 +622,9 @@ nvme_ns_identify(struct nvme_softc *sc, 
 
 	identify = kmem_zalloc(sizeof(*identify), KM_SLEEP);
 	*identify = *((volatile struct nvm_identify_namespace *)NVME_DMA_KVA(mem));
-	//memcpy(identify, NVME_DMA_KVA(mem), sizeof(*identify));
+
+	/* Convert data to host endian */
+	nvme_identify_namespace_swapbytes(identify);
 
 	ns = nvme_ns_get(sc, nsid);
 	KASSERT(ns);
@@ -874,7 +899,7 @@ nvme_getcache_fill(struct nvme_queue *q,
 	struct nvme_sqe *sqe = slot;
 
 	sqe->opcode = NVM_ADMIN_GET_FEATURES;
-	sqe->cdw10 = NVM_FEATURE_VOLATILE_WRITE_CACHE;
+	htolem32(&sqe->cdw10, NVM_FEATURE_VOLATILE_WRITE_CACHE);
 }
 
 static void
@@ -1097,7 +1122,7 @@ nvme_q_submit(struct nvme_softc *sc, str
 	    sizeof(*sqe) * tail, sizeof(*sqe), BUS_DMASYNC_POSTWRITE);
 	memset(sqe, 0, sizeof(*sqe));
 	(*fill)(q, ccb, sqe);
-	sqe->cid = ccb->ccb_id;
+	htolem16(&sqe->cid, ccb->ccb_id);
 	bus_dmamap_sync(sc->sc_dmat, NVME_DMA_MAP(q->q_sq_dmamem),
 	    sizeof(*sqe) * tail, sizeof(*sqe), BUS_DMASYNC_PREWRITE);
 
@@ -1309,25 +1334,28 @@ nvme_identify(struct nvme_softc *sc, u_i
 		goto done;
 
 	identify = NVME_DMA_KVA(mem);
+	sc->sc_identify = *identify;
+	identify = NULL;
 
-	strnvisx(sn, sizeof(sn), (const char *)identify->sn,
-	    sizeof(identify->sn), VIS_TRIM|VIS_SAFE|VIS_OCTAL);
-	strnvisx(mn, sizeof(mn), (const char *)identify->mn,
-	    sizeof(identify->mn), VIS_TRIM|VIS_SAFE|VIS_OCTAL);
-	strnvisx(fr, sizeof(fr), (const char *)identify->fr,
-	    sizeof(identify->fr), VIS_TRIM|VIS_SAFE|VIS_OCTAL);
+	/* Convert data to host endian */
+	nvme_identify_controller_swapbytes(&sc->sc_identify);
+
+	strnvisx(sn, sizeof(sn), (const char *)sc->sc_identify.sn,
+	    sizeof(sc->sc_identify.sn), VIS_TRIM|VIS_SAFE|VIS_OCTAL);
+	strnvisx(mn, sizeof(mn), (const char *)sc->sc_identify.mn,
+	    sizeof(sc->sc_identify.mn), VIS_TRIM|VIS_SAFE|VIS_OCTAL);
+	strnvisx(fr, sizeof(fr), (const char *)sc->sc_identify.fr,
+	    sizeof(sc->sc_identify.fr), VIS_TRIM|VIS_SAFE|VIS_OCTAL);
 	aprint_normal_dev(sc->sc_dev, "%s, firmware %s, serial %s\n", mn, fr,
 	    sn);
 
-	if (identify->mdts > 0) {
-		mdts = (1 << identify->mdts) * (1 << mps);
+	if (sc->sc_identify.mdts > 0) {
+		mdts = (1 << sc->sc_identify.mdts) * (1 << mps);
 		if (mdts < sc->sc_mdts)
 			sc->sc_mdts = mdts;
 	}
 
-	sc->sc_nn = lemtoh32(&identify->nn);
-
-	memcpy(&sc->sc_identify, identify, sizeof(sc->sc_identify));
+	sc->sc_nn = sc->sc_identify.nn;
 
 done:
 	nvme_dmamem_free(sc, mem);

Index: src/sys/dev/ic/nvmeio.h
diff -u src/sys/dev/ic/nvmeio.h:1.1 src/sys/dev/ic/nvmeio.h:1.1.12.1
--- src/sys/dev/ic/nvmeio.h:1.1	Sat Jun  4 16:11:51 2016
+++ src/sys/dev/ic/nvmeio.h	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmeio.h,v 1.1 2016/06/04 16:11:51 nonaka Exp $	*/
+/*	$NetBSD: nvmeio.h,v 1.1.12.1 2018/04/19 15:37:56 martin Exp $	*/
 
 /*-
  * Copyright (C) 2012-2013 Intel Corporation
@@ -25,12 +25,13 @@
  * 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 $
+ * $FreeBSD: head/sys/dev/nvme/nvme.h 329824 2018-02-22 13:32:31Z wma $
  */
 
 #ifndef __NVMEIO_H__
 #define __NVMEIO_H__
 
+#include <sys/endian.h>
 #include <sys/ioccom.h>
 #include <dev/ic/nvmereg.h>
 
@@ -94,4 +95,103 @@ struct nvme_pt_command {
 	uint32_t		timeout;
 };
 
+/* Endianess conversion functions for NVMe structs */
+static inline void
+nvme_le128toh(uint64_t v[2])
+{
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	uint64_t t;
+
+	t = le64toh(v[0]);
+	v[0] = le64toh(v[1]);
+	v[1] = t;
+#endif
+}
+
+static inline void
+nvme_namespace_format_swapbytes(struct nvm_namespace_format *format)
+{
+
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	format->ms = le16toh(format->ms);
+#endif
+}
+
+static inline void
+nvme_identify_namespace_swapbytes(struct nvm_identify_namespace *identify)
+{
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	u_int i;
+
+	identify->nsze = le64toh(identify->nsze);
+	identify->ncap = le64toh(identify->ncap);
+	identify->nuse = le64toh(identify->nuse);
+	identify->nawun = le16toh(identify->nawun);
+	identify->nawupf = le16toh(identify->nawupf);
+	identify->nacwu = le16toh(identify->nacwu);
+	identify->nabsn = le16toh(identify->nabsn);
+	identify->nabo = le16toh(identify->nabo);
+	identify->nabspf = le16toh(identify->nabspf);
+	identify->noiob = le16toh(identify->noiob);
+	for (i = 0; i < __arraycount(identify->lbaf); i++)
+		nvme_namespace_format_swapbytes(&identify->lbaf[i]);
+#endif
+}
+
+static inline void
+nvme_identify_psd_swapbytes(struct nvm_identify_psd *psd)
+{
+
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	psd->mp = le16toh(psd->mp);
+	psd->enlat = le32toh(psd->enlat);
+	psd->exlat = le32toh(psd->exlat);
+	psd->idlp = le16toh(psd->idlp);
+	psd->actp = le16toh(psd->actp);
+	psd->ap = le16toh(psd->ap);
+#endif
+}
+
+static inline void
+nvme_identify_controller_swapbytes(struct nvm_identify_controller *identify)
+{
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	u_int i;
+
+	identify->vid = le16toh(identify->vid);
+	identify->ssvid = le16toh(identify->ssvid);
+	identify->cntlid = le16toh(identify->cntlid);
+	identify->ver = le32toh(identify->ver);
+	identify->rtd3r = le32toh(identify->rtd3r);
+	identify->rtd3e = le32toh(identify->rtd3e);
+	identify->oaes = le32toh(identify->oaes);
+	identify->ctrattr = le32toh(identify->ctrattr);
+	identify->oacs = le16toh(identify->oacs);
+	identify->wctemp = le16toh(identify->wctemp);
+	identify->cctemp = le16toh(identify->cctemp);
+	identify->mtfa = le16toh(identify->mtfa);
+	identify->hmpre = le32toh(identify->hmpre);
+	identify->hmmin = le32toh(identify->hmmin);
+	nvme_le128toh(identify->untncap.tnvmcap);
+	nvme_le128toh(identify->untncap.unvmcap);
+	identify->rpmbs = le32toh(identify->rpmbs);
+	identify->edstt = le16toh(identify->edstt);
+	identify->kas = le16toh(identify->kas);
+	identify->hctma = le16toh(identify->hctma);
+	identify->mntmt = le16toh(identify->mntmt);
+	identify->mxtmt = le16toh(identify->mxtmt);
+	identify->sanicap = le32toh(identify->sanicap);
+	identify->maxcmd = le16toh(identify->maxcmd);
+	identify->nn = le32toh(identify->nn);
+	identify->oncs = le16toh(identify->oncs);
+	identify->fuses = le16toh(identify->fuses);
+	identify->awun = le16toh(identify->awun);
+	identify->awupf = le16toh(identify->awupf);
+	identify->acwu = le16toh(identify->acwu);
+	identify->sgls = le32toh(identify->sgls);
+	for (i = 0; i < __arraycount(identify->psd); i++)
+		nvme_identify_psd_swapbytes(&identify->psd[i]);
+#endif
+}
+
 #endif /* __NVMEIO_H__ */

Index: src/sys/dev/ic/nvmereg.h
diff -u src/sys/dev/ic/nvmereg.h:1.9 src/sys/dev/ic/nvmereg.h:1.9.2.1
--- src/sys/dev/ic/nvmereg.h:1.9	Mon May 29 02:20:34 2017
+++ src/sys/dev/ic/nvmereg.h	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmereg.h,v 1.9 2017/05/29 02:20:34 nonaka Exp $	*/
+/*	$NetBSD: nvmereg.h,v 1.9.2.1 2018/04/19 15:37:56 martin Exp $	*/
 /*	$OpenBSD: nvmereg.h,v 1.10 2016/04/14 11:18:32 dlg Exp $ */
 
 /*
@@ -20,6 +20,10 @@
 #ifndef	__NVMEREG_H__
 #define	__NVMEREG_H__
 
+#ifndef	NVME_CTASSERT
+#define	NVME_CTASSERT(x, s)	__CTASSERT(x)
+#endif
+
 #define NVME_CAP	0x0000	/* Controller Capabilities */
 #define  NVME_CAP_MPSMAX(_r)	(12 + (((_r) >> 52) & 0xf)) /* shift */
 #define  NVME_CAP_MPSMIN(_r)	(12 + (((_r) >> 48) & 0xf)) /* shift */
@@ -96,6 +100,7 @@ struct nvme_sge {
 	uint8_t		id;
 	uint8_t		_reserved[15];
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvme_sge) == 16, "bad size for nvme_sge");
 
 struct nvme_sge_data {
 	uint8_t		id;
@@ -105,6 +110,7 @@ struct nvme_sge_data {
 
 	uint64_t	address;
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvme_sge_data) == 16, "bad size for nvme_sge_data");
 
 struct nvme_sge_bit_bucket {
 	uint8_t		id;
@@ -114,6 +120,7 @@ struct nvme_sge_bit_bucket {
 
 	uint64_t	address;
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvme_sge_bit_bucket) == 16, "bad size for nvme_sge_bit_bucket");
 
 struct nvme_sqe {
 	uint8_t		opcode;
@@ -138,6 +145,7 @@ struct nvme_sqe {
 	uint32_t	cdw14;
 	uint32_t	cdw15;
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvme_sqe) == 64, "bad size for nvme_sqe");
 
 struct nvme_sqe_q {
 	uint8_t		opcode;
@@ -165,6 +173,7 @@ struct nvme_sqe_q {
 
 	uint8_t		_reserved4[16];
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvme_sqe_q) == 64, "bad size for nvme_sqe_q");
 
 struct nvme_sqe_io {
 	uint8_t		opcode;
@@ -217,6 +226,7 @@ struct nvme_sqe_io {
 	uint16_t	elbatm;	/* Expected Logical Block
 				   Application Tag Mask */
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvme_sqe_io) == 64, "bad size for nvme_sqe_io");
 
 struct nvme_cqe {
 	uint32_t	cdw0;
@@ -292,6 +302,7 @@ struct nvme_cqe {
 #define  NVME_CQE_SC_ACCESS_DENIED	(0x86 << 1)
 #define NVME_CQE_PHASE		__BIT(0)
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvme_cqe) == 16, "bad size for nvme_cqe");
 
 #define NVM_ADMIN_DEL_IOSQ	0x00 /* Delete I/O Submission Queue */
 #define NVM_ADMIN_ADD_IOSQ	0x01 /* Create I/O Submission Queue */
@@ -303,19 +314,60 @@ 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_NS_MANAGEMENT	0x0d /* Namespace Management */
+/* 0x0e-0x0f - reserved */
 #define NVM_ADMIN_FW_COMMIT	0x10 /* Firmware Commit */
 #define NVM_ADMIN_FW_DOWNLOAD	0x11 /* Firmware Image Download */
+#define NVM_ADMIN_DEV_SELFTEST	0x14 /* Device Self Test */
+#define NVM_ADMIN_NS_ATTACHMENT	0x15 /* Namespace Attachment */
+#define NVM_ADMIN_KEEP_ALIVE	0x18 /* Keep Alive */
+#define NVM_ADMIN_DIRECTIVE_SND	0x19 /* Derective Send */
+#define NVM_ADMIN_DIRECTIVE_RCV	0x1a /* Derective Receive */
+#define NVM_ADMIN_VIRT_MGMT	0x1c /* Virtualization Management */
+#define NVM_ADMIN_NVME_MI_SEND	0x1d /* NVMe-MI Send */
+#define NVM_ADMIN_NVME_MI_RECV	0x1e /* NVMe-MI Receive */
+#define NVM_ADMIN_DOORBELL_BC	0x7c /* Doorbell Buffer Config */
+#define NVM_ADMIN_FORMAT_NVM	0x80 /* Format NVM */
+#define NVM_ADMIN_SECURITY_SND	0x81 /* Security Send */
+#define NVM_ADMIN_SECURITY_RCV	0x82 /* Security Receive */
+#define NVM_ADMIN_SANITIZE	0x84 /* Sanitize */
 
 #define NVM_CMD_FLUSH		0x00 /* Flush */
 #define NVM_CMD_WRITE		0x01 /* Write */
 #define NVM_CMD_READ		0x02 /* Read */
 #define NVM_CMD_WR_UNCOR	0x04 /* Write Uncorrectable */
 #define NVM_CMD_COMPARE		0x05 /* Compare */
+/* 0x06-0x07 - reserved */
+#define NVM_CMD_WRITE_ZEROES	0x08 /* Write Zeroes */
 #define NVM_CMD_DSM		0x09 /* Dataset Management */
 
 /* Features for GET/SET FEATURES */
+/* 0x00 - reserved */
+#define NVM_FEAT_ARBITRATION			0x01
+#define NVM_FEAT_POWER_MANAGEMENT		0x02
+#define NVM_FEAT_LBA_RANGE_TYPE			0x03
+#define NVM_FEAT_TEMPERATURE_THRESHOLD		0x04
+#define NVM_FEAT_ERROR_RECOVERY			0x05
 #define NVM_FEATURE_VOLATILE_WRITE_CACHE	0x06	/* optional */
 #define NVM_FEATURE_NUMBER_OF_QUEUES		0x07	/* mandatory */
+#define NVM_FEAT_INTERRUPT_COALESCING		0x08
+#define NVM_FEAT_INTERRUPT_VECTOR_CONFIGURATION 0x09
+#define NVM_FEAT_WRITE_ATOMICITY		0x0a
+#define NVM_FEAT_ASYNC_EVENT_CONFIGURATION	0x0b
+#define NVM_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION 0x0c
+#define NVM_FEAT_HOST_MEMORY_BUFFER		0x0d
+#define NVM_FEAT_TIMESTAMP			0x0e
+#define NVM_FEAT_KEEP_ALIVE_TIMER		0x0f
+#define NVM_FEAT_HOST_CONTROLLED_THERMAL_MGMT	0x10
+#define NVM_FEAT_NON_OP_POWER_STATE_CONFIG	0x11
+/* 0x12-0x77 - reserved */
+/* 0x78-0x7f - NVMe Management Interface */
+#define NVM_FEAT_SOFTWARE_PROGRESS_MARKER	0x80
+#define NVM_FEAT_HOST_IDENTIFIER		0x81
+#define NVM_FEAT_RESERVATION_NOTIFICATION_MASK	0x82
+#define NVM_FEAT_RESERVATION_PERSISTANCE	0x83
+/* 0x84-0xBF - command set specific (reserved) */
+/* 0xC0-0xFF - vendor specific */
 
 /* Power State Descriptor Data */
 struct nvm_identify_psd {
@@ -349,6 +401,7 @@ struct nvm_identify_psd {
 
 	uint8_t		_reserved[8];
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvm_identify_psd) == 32, "bad size for nvm_identify_psd");
 
 struct nvm_identify_controller {
 	/* Controller Capabilities and Features */
@@ -366,13 +419,30 @@ struct nvm_identify_controller {
 	uint8_t		cmic;		/* Controller Multi-Path I/O and
 					   Namespace Sharing Capabilities */
 	uint8_t		mdts;		/* Maximum Data Transfer Size */
+
 	uint16_t	cntlid;		/* Controller ID */
+	uint32_t	ver;		/* Version */
+
+	uint32_t	rtd3r;		/* RTD3 Resume Latency */
+	uint32_t	rtd3e;		/* RTD3 Enter Latency */
+
+	uint32_t	oaes;		/* Optional Asynchronous Events Supported */
+	uint32_t	ctrattr;	/* Controller Attributes */
 
-	uint8_t		_reserved1[176];
+	uint8_t		_reserved1[12];
+
+	uint8_t		fguid[16];	/* FRU Globally Unique Identifier */
+
+	uint8_t		_reserved2[128];
 
 	/* Admin Command Set Attributes & Optional Controller Capabilities */
 
 	uint16_t	oacs;		/* Optional Admin Command Support */
+#define	NVME_ID_CTRLR_OACS_DOORBELL_BC	__BIT(8)
+#define	NVME_ID_CTRLR_OACS_VIRT_MGMT	__BIT(7)
+#define	NVME_ID_CTRLR_OACS_NVME_MI	__BIT(6)
+#define	NVME_ID_CTRLR_OACS_DIRECTIVES	__BIT(5)
+#define	NVME_ID_CTRLR_OACS_DEV_SELFTEST	__BIT(4)
 #define	NVME_ID_CTRLR_OACS_NS		__BIT(3)
 #define	NVME_ID_CTRLR_OACS_FW		__BIT(2)
 #define	NVME_ID_CTRLR_OACS_FORMAT	__BIT(1)
@@ -395,7 +465,40 @@ struct nvm_identify_controller {
 	uint8_t		apsta;		/* Autonomous Power State Transition
 					   Attributes */
 
-	uint8_t		_reserved2[246];
+	uint16_t	wctemp;		/* Warning Composite Temperature
+					   Threshold */
+	uint16_t	cctemp;		/* Critical Composite Temperature
+					   Threshold */
+
+	uint16_t	mtfa;		/* Maximum Time for Firmware Activation */
+
+	uint32_t	hmpre;		/* Host Memory Buffer Preferred Size */
+	uint32_t	hmmin;		/* Host Memory Buffer Minimum Size */
+
+	struct {
+		uint64_t	tnvmcap[2];
+		uint64_t	unvmcap[2];
+	} __packed untncap;		/* Name space capabilities:
+					   if NVME_ID_CTRLR_OACS_NS,
+					   report tnvmcap and unvmcap */
+
+	uint32_t	rpmbs;		/* Replay Protected Memory Block Support */
+
+	uint16_t	edstt;		/* Extended Device Self-test Time */
+	uint8_t		dsto;		/* Device Self-test Options */
+
+	uint8_t		fwug;		/* Firmware Update Granularity */
+
+	uint16_t	kas;		/* Keep Alive Support */
+
+	uint16_t	hctma;		/* Host Controlled Thermal Management
+					   Attributes */
+	uint16_t	mntmt;		/* Minimum Thermal Management Temperature */
+	uint16_t	mxtmt;		/* Maximum Thermal Management Temperature */
+
+	uint32_t	sanicap;	/* Sanitize Capabilities */
+
+	uint8_t		_reserved3[180];
 
 	/* NVM Command Set Attributes */
 
@@ -405,7 +508,8 @@ struct nvm_identify_controller {
 	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];
+
+	uint16_t	maxcmd;		/* Maximum Outstanding Commands */
 
 	uint32_t	nn;		/* Number of Namespaces */
 
@@ -419,11 +523,14 @@ struct nvm_identify_controller {
 	uint16_t	fuses;		/* Fused Operation Support */
 
 	uint8_t		fna;		/* Format NVM Attributes */
+#define	NVME_ID_CTRLR_FNA_CRYPTO_ERASE	__BIT(2)
+#define	NVME_ID_CTRLR_FNA_ERASE_ALL	__BIT(1)
+#define	NVME_ID_CTRLR_FNA_FORMAT_ALL	__BIT(0)
 	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 */
+
 	uint8_t		nvscc;		/* NVM Vendor Specific Command */
 	uint8_t		_reserved4[1];
 
@@ -432,26 +539,26 @@ struct nvm_identify_controller {
 
 	uint32_t	sgls;		/* SGL Support */
 
-	uint8_t		_reserved6[164];
+	uint8_t		_reserved6[228];
 
-	/* I/O Command Set Attributes */
+	uint8_t		subnqn[256];	/* NVM Subsystem NVMe Qualified Name */
 
-	uint8_t		_reserved7[1344];
+	uint8_t		_reserved7[768];
 
-	/* Power State Descriptors */
+	uint8_t		_reserved8[256]; /* NVMe over Fabrics specification */
 
 	struct nvm_identify_psd psd[32]; /* Power State Descriptors */
 
-	/* Vendor Specific */
-
-	uint8_t		_reserved8[1024];
+	uint8_t		vs[1024];	/* Vendor Specific */
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvm_identify_controller) == 4096, "bad size for nvm_identify_controller");
 
 struct nvm_namespace_format {
 	uint16_t	ms;		/* Metadata Size */
 	uint8_t		lbads;		/* LBA Data Size */
 	uint8_t		rp;		/* Relative Performance */
 } __packed __aligned(4);
+NVME_CTASSERT(sizeof(struct nvm_namespace_format) == 4, "bad size for nvm_namespace_format");
 
 struct nvm_identify_namespace {
 	uint64_t	nsze;		/* Namespace Size */
@@ -471,9 +578,35 @@ struct nvm_identify_namespace {
 	uint8_t		mc;		/* Metadata Capabilities */
 	uint8_t		dpc;		/* End-to-end Data Protection
 					   Capabilities */
-	uint8_t		dps;		/* End-to-end Data Protection Type Settings */
+	uint8_t		dps;		/* End-to-end Data Protection Type
+					   Settings */
+#define	NVME_ID_NS_DPS_MD_START			__BIT(3)
+#define	NVME_ID_NS_DPS_PIT(_f)			((_f) & 0x7)
+
+	uint8_t		nmic;		/* Namespace Multi-path I/O and Namespace
+					   Sharing Capabilities */
+
+	uint8_t		rescap;		/* Reservation Capabilities */
+
+	uint8_t		fpi;		/* Format Progress Indicator */
+
+	uint8_t		dlfeat;		/* Deallocate Logical Block Features */
+
+	uint16_t	nawun;		/* Namespace Atomic Write Unit Normal  */
+	uint16_t	nawupf;		/* Namespace Atomic Write Unit Power Fail */
+	uint16_t	nacwu;		/* Namespace Atomic Compare & Write Unit */
+	uint16_t	nabsn;		/* Namespace Atomic Boundary Size Normal */
+	uint16_t	nabo;		/* Namespace Atomic Boundary Offset */
+	uint16_t	nabspf;		/* Namespace Atomic Boundary Size Power
+					   Fail */
+	uint16_t	noiob;		/* Namespace Optimal IO Boundary */
+
+	uint8_t		nvmcap[16];	/* NVM Capacity */
+
+	uint8_t		_reserved1[40];	/* bytes 64-103: Reserved */
 
-	uint8_t		_reserved1[98];
+	uint8_t		nguid[16];	/* Namespace Globally Unique Identifier */
+	uint8_t		eui64[8];	/* IEEE Extended Unique Identifier */
 
 	struct nvm_namespace_format
 			lbaf[16];	/* LBA Format Support */
@@ -482,5 +615,6 @@ struct nvm_identify_namespace {
 
 	uint8_t		vs[3712];
 } __packed __aligned(8);
+NVME_CTASSERT(sizeof(struct nvm_identify_namespace) == 4096, "bad size for nvm_identify_namespace");
 
 #endif	/* __NVMEREG_H__ */

Index: src/sys/dev/ic/nvmevar.h
diff -u src/sys/dev/ic/nvmevar.h:1.13.6.2 src/sys/dev/ic/nvmevar.h:1.13.6.3
--- src/sys/dev/ic/nvmevar.h:1.13.6.2	Sun Mar 18 11:05:27 2018
+++ src/sys/dev/ic/nvmevar.h	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvmevar.h,v 1.13.6.2 2018/03/18 11:05:27 martin Exp $	*/
+/*	$NetBSD: nvmevar.h,v 1.13.6.3 2018/04/19 15:37:56 martin Exp $	*/
 /*	$OpenBSD: nvmevar.h,v 1.8 2016/04/14 11:18:32 dlg Exp $ */
 
 /*
@@ -136,6 +136,9 @@ struct nvme_softc {
 	uint32_t		sc_flags;
 #define	NVME_F_ATTACHED	__BIT(0)
 #define	NVME_F_OPEN	__BIT(1)
+
+	uint32_t		sc_quirks;
+#define	NVME_QUIRK_DELAY_B4_CHK_RDY	__BIT(0)
 };
 
 #define	lemtoh16(p)	le16toh(*((uint16_t *)(p)))

Index: src/sys/dev/pci/nvme_pci.c
diff -u src/sys/dev/pci/nvme_pci.c:1.19 src/sys/dev/pci/nvme_pci.c:1.19.2.1
--- src/sys/dev/pci/nvme_pci.c:1.19	Thu Jun  1 02:45:11 2017
+++ src/sys/dev/pci/nvme_pci.c	Thu Apr 19 15:37:56 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: nvme_pci.c,v 1.19 2017/06/01 02:45:11 chs Exp $	*/
+/*	$NetBSD: nvme_pci.c,v 1.19.2.1 2018/04/19 15:37:56 martin Exp $	*/
 /*	$OpenBSD: nvme_pci.c,v 1.3 2016/04/14 11:18:32 dlg Exp $ */
 
 /*
@@ -43,7 +43,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvme_pci.c,v 1.19 2017/06/01 02:45:11 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme_pci.c,v 1.19.2.1 2018/04/19 15:37:56 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -59,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: nvme_pci.c,v
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
 
 #include <dev/ic/nvmereg.h>
 #include <dev/ic/nvmevar.h>
@@ -92,6 +93,39 @@ static int	nvme_pci_intr_disestablish(st
 static int	nvme_pci_setup_intr(struct pci_attach_args *,
 		    struct nvme_pci_softc *);
 
+static const struct nvme_pci_quirk {
+	pci_vendor_id_t		vendor;
+	pci_product_id_t	product;
+	uint32_t		quirks;
+} nvme_pci_quirks[] = {
+	{ PCI_VENDOR_HGST, PCI_PRODUCT_HGST_SN100,
+	    NVME_QUIRK_DELAY_B4_CHK_RDY },
+	{ PCI_VENDOR_HGST, PCI_PRODUCT_HGST_SN200,
+	    NVME_QUIRK_DELAY_B4_CHK_RDY },
+	{ PCI_VENDOR_BEIJING_MEMBLAZE, PCI_PRODUCT_BEIJING_MEMBLAZE_PBLAZE4,
+	    NVME_QUIRK_DELAY_B4_CHK_RDY },
+	{ PCI_VENDOR_SAMSUNGELEC3, PCI_PRODUCT_SAMSUNGELEC3_172X,
+	    NVME_QUIRK_DELAY_B4_CHK_RDY },
+	{ PCI_VENDOR_SAMSUNGELEC3, PCI_PRODUCT_SAMSUNGELEC3_172XAB,
+	    NVME_QUIRK_DELAY_B4_CHK_RDY },
+};
+
+static const struct nvme_pci_quirk *
+nvme_pci_lookup_quirk(struct pci_attach_args *pa)
+{
+	const struct nvme_pci_quirk *q;
+	int i;
+
+	for (i = 0; i < __arraycount(nvme_pci_quirks); i++) {
+		q = &nvme_pci_quirks[i];
+
+		if (PCI_VENDOR(pa->pa_id) == q->vendor &&
+		    PCI_PRODUCT(pa->pa_id) == q->product)
+			return q;
+	}
+	return NULL;
+}
+
 static int
 nvme_pci_match(device_t parent, cfdata_t match, void *aux)
 {
@@ -111,6 +145,7 @@ nvme_pci_attach(device_t parent, device_
 	struct nvme_pci_softc *psc = device_private(self);
 	struct nvme_softc *sc = &psc->psc_nvme;
 	struct pci_attach_args *pa = aux;
+	const struct nvme_pci_quirk *quirk;
 	pcireg_t memtype, reg;
 	bus_addr_t memaddr;
 	int flags, error;
@@ -179,6 +214,11 @@ nvme_pci_attach(device_t parent, device_
 	sc->sc_ih = kmem_zalloc(sizeof(*sc->sc_ih) * psc->psc_nintrs, KM_SLEEP);
 	sc->sc_softih = kmem_zalloc(
 	    sizeof(*sc->sc_softih) * psc->psc_nintrs, KM_SLEEP);
+
+	quirk = nvme_pci_lookup_quirk(pa);
+	if (quirk != NULL)
+		sc->sc_quirks = quirk->quirks;
+
 	if (nvme_attach(sc) != 0) {
 		/* error printed by nvme_attach() */
 		goto softintr_free;

Added files:

Index: src/sbin/nvmectl/util.c
diff -u /dev/null src/sbin/nvmectl/util.c:1.2.2.2
--- /dev/null	Thu Apr 19 15:37:57 2018
+++ src/sbin/nvmectl/util.c	Thu Apr 19 15:37:56 2018
@@ -0,0 +1,140 @@
+/*	$NetBSD: util.c,v 1.2.2.2 2018/04/19 15:37:56 martin Exp $	*/
+
+/*-
+ * Copyright (c) 2017 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: util.c,v 1.2.2.2 2018/04/19 15:37:56 martin Exp $");
+#if 0
+__FBSDID("$FreeBSD: head/sbin/nvmecontrol/util.c 320423 2017-06-27 20:24:25Z imp $");
+#endif
+#endif
+
+#include <sys/endian.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "nvmectl.h"
+#include "bn.h"
+
+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;
+}
+
+#define	METRIX_PREFIX_BUFSIZ	17
+#define	NO_METRIX_PREFIX_BUFSIZ	42
+
+void
+print_bignum(const char *title, uint64_t v[2], const char *suffix)
+{
+	char buf[64];
+	uint8_t tmp[16];
+	uint64_t h, l;
+
+#if _BYTE_ORDER != _LITTLE_ENDIAN
+	/* Already Converted to host endian */
+	h = v[0];
+	l = v[1];
+	memcpy(tmp, v, sizeof(tmp));
+#else
+	h = v[1];
+	l = v[0];
+
+	tmp[ 0] = (h >> 56) & 0xff;
+	tmp[ 1] = (h >> 48) & 0xff;
+	tmp[ 2] = (h >> 40) & 0xff;
+	tmp[ 3] = (h >> 32) & 0xff;
+	tmp[ 4] = (h >> 24) & 0xff;
+	tmp[ 5] = (h >> 16) & 0xff;
+	tmp[ 6] = (h >> 8) & 0xff;
+	tmp[ 7] = h & 0xff;
+	tmp[ 8] = (l >> 56) & 0xff;
+	tmp[ 9] = (l >> 48) & 0xff;
+	tmp[10] = (l >> 40) & 0xff;
+	tmp[11] = (l >> 32) & 0xff;
+	tmp[12] = (l >> 24) & 0xff;
+	tmp[13] = (l >> 16) & 0xff;
+	tmp[14] = (l >> 8) & 0xff;
+	tmp[15] = l & 0xff;
+#endif
+
+	buf[0] = '\0';
+	BIGNUM *bn = BN_bin2bn(tmp, sizeof(tmp), NULL);
+	if (bn != NULL) {
+		humanize_bignum(buf, METRIX_PREFIX_BUFSIZ + strlen(suffix),
+		    bn, suffix, HN_AUTOSCALE, HN_DECIMAL);
+		BN_free(bn);
+	}
+	if (buf[0] == '\0')
+		snprintf(buf, sizeof(buf), "0x%016" PRIx64 "%016" PRIx64, h, l);
+	printf("%-31s %s\n", title, buf);
+}
+
+/* "Missing" from endian.h */
+uint64_t
+le48dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((uint64_t)le16dec(p + 4) << 32) | le32dec(p));
+}

Reply via email to