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)); +}