175871362SJim Harris /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
475871362SJim Harris * Copyright (c) 2013 EMC Corp.
575871362SJim Harris * All rights reserved.
675871362SJim Harris *
775871362SJim Harris * Copyright (C) 2012-2013 Intel Corporation
875871362SJim Harris * All rights reserved.
9fe83abacSWarner Losh * Copyright (C) 2016-2023 Warner Losh <imp@FreeBSD.org>
106c99d132SAlexander Motin * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
1175871362SJim Harris *
1275871362SJim Harris * Redistribution and use in source and binary forms, with or without
1375871362SJim Harris * modification, are permitted provided that the following conditions
1475871362SJim Harris * are met:
1575871362SJim Harris * 1. Redistributions of source code must retain the above copyright
1675871362SJim Harris * notice, this list of conditions and the following disclaimer.
1775871362SJim Harris * 2. Redistributions in binary form must reproduce the above copyright
1875871362SJim Harris * notice, this list of conditions and the following disclaimer in the
1975871362SJim Harris * documentation and/or other materials provided with the distribution.
2075871362SJim Harris *
2175871362SJim Harris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2275871362SJim Harris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2375871362SJim Harris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2475871362SJim Harris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2575871362SJim Harris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2675871362SJim Harris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2775871362SJim Harris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2875871362SJim Harris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2975871362SJim Harris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3075871362SJim Harris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3175871362SJim Harris * SUCH DAMAGE.
3275871362SJim Harris */
3375871362SJim Harris
3475871362SJim Harris #include <sys/param.h>
3575871362SJim Harris #include <sys/ioccom.h>
3675871362SJim Harris
3775871362SJim Harris #include <ctype.h>
38821ef73cSJim Harris #include <err.h>
3975871362SJim Harris #include <fcntl.h>
4075871362SJim Harris #include <stdbool.h>
4175871362SJim Harris #include <stddef.h>
4275871362SJim Harris #include <stdio.h>
4375871362SJim Harris #include <stdlib.h>
4475871362SJim Harris #include <string.h>
455dc463f9SAlexander Motin #include <sysexits.h>
4675871362SJim Harris #include <unistd.h>
4733a099d2SWarner Losh #include <sys/endian.h>
4833a099d2SWarner Losh
4975871362SJim Harris #include "nvmecontrol.h"
5075871362SJim Harris
51f634b4c1SWarner Losh /* Tables for command line parsing */
52f634b4c1SWarner Losh
53f634b4c1SWarner Losh static cmd_fn_t logpage;
54f634b4c1SWarner Losh
55f634b4c1SWarner Losh #define NONE 0xffffffffu
56f634b4c1SWarner Losh static struct options {
57f634b4c1SWarner Losh bool binary;
58f634b4c1SWarner Losh bool hex;
59f634b4c1SWarner Losh uint32_t page;
606c99d132SAlexander Motin uint8_t lsp;
616c99d132SAlexander Motin uint16_t lsi;
626c99d132SAlexander Motin bool rae;
63f634b4c1SWarner Losh const char *vendor;
64f634b4c1SWarner Losh const char *dev;
65f634b4c1SWarner Losh } opt = {
66f634b4c1SWarner Losh .binary = false,
67f634b4c1SWarner Losh .hex = false,
68f634b4c1SWarner Losh .page = NONE,
696c99d132SAlexander Motin .lsp = 0,
706c99d132SAlexander Motin .lsi = 0,
716c99d132SAlexander Motin .rae = false,
72f634b4c1SWarner Losh .vendor = NULL,
73f634b4c1SWarner Losh .dev = NULL,
74f634b4c1SWarner Losh };
75f634b4c1SWarner Losh
76f634b4c1SWarner Losh static const struct opts logpage_opts[] = {
77f634b4c1SWarner Losh #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
78f634b4c1SWarner Losh OPT("binary", 'b', arg_none, opt, binary,
79f634b4c1SWarner Losh "Dump the log page as binary"),
80f634b4c1SWarner Losh OPT("hex", 'x', arg_none, opt, hex,
81f634b4c1SWarner Losh "Dump the log page as hex"),
82f634b4c1SWarner Losh OPT("page", 'p', arg_uint32, opt, page,
83f634b4c1SWarner Losh "Page to dump"),
846c99d132SAlexander Motin OPT("lsp", 'f', arg_uint8, opt, lsp,
856c99d132SAlexander Motin "Log Specific Field"),
8697db0313SAlexander Motin OPT("lsi", 'i', arg_uint16, opt, lsi,
876c99d132SAlexander Motin "Log Specific Identifier"),
886c99d132SAlexander Motin OPT("rae", 'r', arg_none, opt, rae,
896c99d132SAlexander Motin "Retain Asynchronous Event"),
90f634b4c1SWarner Losh OPT("vendor", 'v', arg_string, opt, vendor,
91f634b4c1SWarner Losh "Vendor specific formatting"),
92f634b4c1SWarner Losh { NULL, 0, arg_none, NULL, NULL }
93f634b4c1SWarner Losh };
94f634b4c1SWarner Losh #undef OPT
95f634b4c1SWarner Losh
96f634b4c1SWarner Losh static const struct args logpage_args[] = {
97f634b4c1SWarner Losh { arg_string, &opt.dev, "<controller id|namespace id>" },
98f634b4c1SWarner Losh { arg_none, NULL, NULL },
99f634b4c1SWarner Losh };
100f634b4c1SWarner Losh
101f634b4c1SWarner Losh static struct cmd logpage_cmd = {
102f634b4c1SWarner Losh .name = "logpage",
103f634b4c1SWarner Losh .fn = logpage,
104f634b4c1SWarner Losh .descr = "Print logpages in human-readable form",
105f634b4c1SWarner Losh .ctx_size = sizeof(opt),
106f634b4c1SWarner Losh .opts = logpage_opts,
107f634b4c1SWarner Losh .args = logpage_args,
108f634b4c1SWarner Losh };
109f634b4c1SWarner Losh
110f634b4c1SWarner Losh CMD_COMMAND(logpage_cmd);
111f634b4c1SWarner Losh
112f634b4c1SWarner Losh /* End of tables for command line parsing */
113a13a291aSWarner Losh
11475871362SJim Harris #define MAX_FW_SLOTS (7)
11575871362SJim Harris
116f428a90aSWarner Losh static SLIST_HEAD(,logpage_function) logpages;
117f428a90aSWarner Losh
1186c99d132SAlexander Motin static int
logpage_compare(struct logpage_function * a,struct logpage_function * b)1196c99d132SAlexander Motin logpage_compare(struct logpage_function *a, struct logpage_function *b)
1206c99d132SAlexander Motin {
1216c99d132SAlexander Motin int c;
1226c99d132SAlexander Motin
1236c99d132SAlexander Motin if ((a->vendor == NULL) != (b->vendor == NULL))
1246c99d132SAlexander Motin return (a->vendor == NULL ? -1 : 1);
1256c99d132SAlexander Motin if (a->vendor != NULL) {
1266c99d132SAlexander Motin c = strcmp(a->vendor, b->vendor);
1276c99d132SAlexander Motin if (c != 0)
1286c99d132SAlexander Motin return (c);
1296c99d132SAlexander Motin }
1306c99d132SAlexander Motin return ((int)a->log_page - (int)b->log_page);
1316c99d132SAlexander Motin }
1326c99d132SAlexander Motin
133f428a90aSWarner Losh void
logpage_register(struct logpage_function * p)134f428a90aSWarner Losh logpage_register(struct logpage_function *p)
135f428a90aSWarner Losh {
1366c99d132SAlexander Motin struct logpage_function *l, *a;
137f428a90aSWarner Losh
1386c99d132SAlexander Motin a = NULL;
1396c99d132SAlexander Motin l = SLIST_FIRST(&logpages);
1406c99d132SAlexander Motin while (l != NULL) {
1416c99d132SAlexander Motin if (logpage_compare(l, p) > 0)
1426c99d132SAlexander Motin break;
1436c99d132SAlexander Motin a = l;
1446c99d132SAlexander Motin l = SLIST_NEXT(l, link);
1456c99d132SAlexander Motin }
1466c99d132SAlexander Motin if (a == NULL)
147f428a90aSWarner Losh SLIST_INSERT_HEAD(&logpages, p, link);
1486c99d132SAlexander Motin else
1496c99d132SAlexander Motin SLIST_INSERT_AFTER(a, p, link);
150f428a90aSWarner Losh }
151228c4255SWarner Losh
152a773b08bSWarner Losh const char *
kv_lookup(const struct kv_name * kv,size_t kv_count,uint32_t key)1530cf14228SWarner Losh kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key)
1540cf14228SWarner Losh {
1550cf14228SWarner Losh static char bad[32];
1560cf14228SWarner Losh size_t i;
1570cf14228SWarner Losh
1580cf14228SWarner Losh for (i = 0; i < kv_count; i++, kv++)
1590cf14228SWarner Losh if (kv->key == key)
1600cf14228SWarner Losh return kv->name;
1610cf14228SWarner Losh snprintf(bad, sizeof(bad), "Attribute %#x", key);
1620cf14228SWarner Losh return bad;
1630cf14228SWarner Losh }
1640cf14228SWarner Losh
165ba6da686SWarner Losh static void
print_log_hex(const struct nvme_controller_data * cdata __unused,void * data,uint32_t length)1668ce85adfSWarner Losh print_log_hex(const struct nvme_controller_data *cdata __unused, void *data, uint32_t length)
167ba6da686SWarner Losh {
1688ce85adfSWarner Losh
1698ce85adfSWarner Losh print_hex(data, length);
1708ce85adfSWarner Losh }
1718ce85adfSWarner Losh
1728ce85adfSWarner Losh static void
print_bin(const struct nvme_controller_data * cdata __unused,void * data,uint32_t length)1738ce85adfSWarner Losh print_bin(const struct nvme_controller_data *cdata __unused, void *data, uint32_t length)
1748ce85adfSWarner Losh {
1758ce85adfSWarner Losh
176ba6da686SWarner Losh write(STDOUT_FILENO, data, length);
177ba6da686SWarner Losh }
178ba6da686SWarner Losh
17975871362SJim Harris static void *
get_log_buffer(uint32_t size)180821ef73cSJim Harris get_log_buffer(uint32_t size)
18175871362SJim Harris {
18275871362SJim Harris void *buf;
18375871362SJim Harris
184821ef73cSJim Harris if ((buf = malloc(size)) == NULL)
1855dc463f9SAlexander Motin errx(EX_OSERR, "unable to malloc %u bytes", size);
186821ef73cSJim Harris
18775871362SJim Harris memset(buf, 0, size);
18875871362SJim Harris return (buf);
18975871362SJim Harris }
19075871362SJim Harris
19175871362SJim Harris void
read_logpage(int fd,uint8_t log_page,uint32_t nsid,uint8_t lsp,uint16_t lsi,uint8_t rae,uint64_t lpo,uint8_t csi,uint8_t ot,uint16_t uuid_index,void * payload,uint32_t payload_size)1926c99d132SAlexander Motin read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp,
193*98ab7d0aSWarner Losh uint16_t lsi, uint8_t rae, uint64_t lpo, uint8_t csi, uint8_t ot,
194*98ab7d0aSWarner Losh uint16_t uuid_index, void *payload, uint32_t payload_size)
19575871362SJim Harris {
19675871362SJim Harris struct nvme_pt_command pt;
19785656a9aSWarner Losh u_int numd;
19875871362SJim Harris
1996c99d132SAlexander Motin numd = payload_size / sizeof(uint32_t) - 1;
20075871362SJim Harris memset(&pt, 0, sizeof(pt));
2019544e6dcSChuck Tuffli pt.cmd.opc = NVME_OPC_GET_LOG_PAGE;
2020d787e9bSWojciech Macek pt.cmd.nsid = htole32(nsid);
2036c99d132SAlexander Motin pt.cmd.cdw10 = htole32(
2046c99d132SAlexander Motin (numd << 16) | /* NUMDL */
2056c99d132SAlexander Motin (rae << 15) | /* RAE */
2066c99d132SAlexander Motin (lsp << 8) | /* LSP */
2076c99d132SAlexander Motin log_page); /* LID */
2086c99d132SAlexander Motin pt.cmd.cdw11 = htole32(
2096c99d132SAlexander Motin ((uint32_t)lsi << 16) | /* LSI */
2106c99d132SAlexander Motin (numd >> 16)); /* NUMDU */
211*98ab7d0aSWarner Losh pt.cmd.cdw12 = htole32(lpo & 0xffffffff); /* LPOL */
212*98ab7d0aSWarner Losh pt.cmd.cdw13 = htole32(lpo >> 32); /* LPOU */
213*98ab7d0aSWarner Losh pt.cmd.cdw14 = htole32(
214*98ab7d0aSWarner Losh (csi << 24) | /* CSI */
215*98ab7d0aSWarner Losh (ot << 23) | /* OT */
216*98ab7d0aSWarner Losh uuid_index); /* UUID Index */
21775871362SJim Harris pt.buf = payload;
21875871362SJim Harris pt.len = payload_size;
21975871362SJim Harris pt.is_read = 1;
22075871362SJim Harris
221821ef73cSJim Harris if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
2225dc463f9SAlexander Motin err(EX_IOERR, "get log page request failed");
22375871362SJim Harris
224821ef73cSJim Harris if (nvme_completion_is_error(&pt.cpl))
2255dc463f9SAlexander Motin errx(EX_IOERR, "get log page request returned error");
22675871362SJim Harris }
22775871362SJim Harris
22875871362SJim Harris static void
print_log_error(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size)2298ce85adfSWarner Losh print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size)
23075871362SJim Harris {
23175871362SJim Harris int i, nentries;
2320d787e9bSWojciech Macek uint16_t status;
2330d787e9bSWojciech Macek uint8_t p, sc, sct, m, dnr;
23475871362SJim Harris struct nvme_error_information_entry *entry = buf;
23575871362SJim Harris
23675871362SJim Harris printf("Error Information Log\n");
23775871362SJim Harris printf("=====================\n");
23875871362SJim Harris
239729ee4c8SWarner Losh if (letoh(entry->error_count) == 0) {
24075871362SJim Harris printf("No error entries found\n");
24175871362SJim Harris return;
24275871362SJim Harris }
24375871362SJim Harris
24475871362SJim Harris nentries = size / sizeof(struct nvme_error_information_entry);
24575871362SJim Harris for (i = 0; i < nentries; i++, entry++) {
246729ee4c8SWarner Losh if (letoh(entry->error_count) == 0)
24775871362SJim Harris break;
24875871362SJim Harris
249729ee4c8SWarner Losh status = letoh(entry->status);
2500d787e9bSWojciech Macek
2510d787e9bSWojciech Macek p = NVME_STATUS_GET_P(status);
2520d787e9bSWojciech Macek sc = NVME_STATUS_GET_SC(status);
2530d787e9bSWojciech Macek sct = NVME_STATUS_GET_SCT(status);
2540d787e9bSWojciech Macek m = NVME_STATUS_GET_M(status);
2550d787e9bSWojciech Macek dnr = NVME_STATUS_GET_DNR(status);
2560d787e9bSWojciech Macek
25775871362SJim Harris printf("Entry %02d\n", i + 1);
25875871362SJim Harris printf("=========\n");
259729ee4c8SWarner Losh printf(" Error count: %ju\n", letoh(entry->error_count));
260729ee4c8SWarner Losh printf(" Submission queue ID: %u\n", letoh(entry->sqid));
261729ee4c8SWarner Losh printf(" Command ID: %u\n", letoh(entry->cid));
26275871362SJim Harris /* TODO: Export nvme_status_string structures from kernel? */
26375871362SJim Harris printf(" Status:\n");
2640d787e9bSWojciech Macek printf(" Phase tag: %d\n", p);
2650d787e9bSWojciech Macek printf(" Status code: %d\n", sc);
2660d787e9bSWojciech Macek printf(" Status code type: %d\n", sct);
2670d787e9bSWojciech Macek printf(" More: %d\n", m);
2680d787e9bSWojciech Macek printf(" DNR: %d\n", dnr);
269729ee4c8SWarner Losh printf(" Error location: %u\n", letoh(entry->error_location));
270729ee4c8SWarner Losh printf(" LBA: %ju\n", letoh(entry->lba));
271729ee4c8SWarner Losh printf(" Namespace ID: %u\n", letoh(entry->nsid));
272729ee4c8SWarner Losh printf(" Vendor specific info: %u\n", letoh(entry->vendor_specific));
273729ee4c8SWarner Losh printf(" Transport type: %u\n", letoh(entry->trtype));
274729ee4c8SWarner Losh printf(" Command specific info:%ju\n", letoh(entry->csi));
275729ee4c8SWarner Losh printf(" Transport specific: %u\n", letoh(entry->ttsi));
27675871362SJim Harris }
27775871362SJim Harris }
27875871362SJim Harris
2792da383a5SWarner Losh void
print_temp_K(uint16_t t)2803a194eacSWanpeng Qian print_temp_K(uint16_t t)
281dc58cdf9SWarner Losh {
282dc58cdf9SWarner Losh printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, (float)t * 9 / 5 - 459.67);
283dc58cdf9SWarner Losh }
284dc58cdf9SWarner Losh
2853a194eacSWanpeng Qian void
print_temp_C(uint16_t t)2863a194eacSWanpeng Qian print_temp_C(uint16_t t)
2873a194eacSWanpeng Qian {
2883a194eacSWanpeng Qian printf("%2.2f K, %u C, %3.2f F\n", (float)t + 273.15, t, (float)t * 9 / 5 + 32);
2893a194eacSWanpeng Qian }
290dc58cdf9SWarner Losh
291dc58cdf9SWarner Losh static void
print_log_health(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)2928ce85adfSWarner Losh print_log_health(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused)
29375871362SJim Harris {
29475871362SJim Harris struct nvme_health_information_page *health = buf;
29533a099d2SWarner Losh char cbuf[UINT128_DIG + 1];
2960d787e9bSWojciech Macek uint8_t warning;
297dc58cdf9SWarner Losh int i;
29875871362SJim Harris
299729ee4c8SWarner Losh warning = letoh(health->critical_warning);
3000d787e9bSWojciech Macek
30175871362SJim Harris printf("SMART/Health Information Log\n");
30275871362SJim Harris printf("============================\n");
30375871362SJim Harris
3040d787e9bSWojciech Macek printf("Critical Warning State: 0x%02x\n", warning);
30575871362SJim Harris printf(" Available spare: %d\n",
3060d787e9bSWojciech Macek !!(warning & NVME_CRIT_WARN_ST_AVAILABLE_SPARE));
30775871362SJim Harris printf(" Temperature: %d\n",
3080d787e9bSWojciech Macek !!(warning & NVME_CRIT_WARN_ST_TEMPERATURE));
30975871362SJim Harris printf(" Device reliability: %d\n",
3100d787e9bSWojciech Macek !!(warning & NVME_CRIT_WARN_ST_DEVICE_RELIABILITY));
31175871362SJim Harris printf(" Read only: %d\n",
3120d787e9bSWojciech Macek !!(warning & NVME_CRIT_WARN_ST_READ_ONLY));
31375871362SJim Harris printf(" Volatile memory backup: %d\n",
3140d787e9bSWojciech Macek !!(warning & NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP));
315dc58cdf9SWarner Losh printf("Temperature: ");
316729ee4c8SWarner Losh print_temp_K(letoh(health->temperature));
31775871362SJim Harris printf("Available spare: %u\n",
318729ee4c8SWarner Losh letoh(health->available_spare));
31975871362SJim Harris printf("Available spare threshold: %u\n",
320729ee4c8SWarner Losh letoh(health->available_spare_threshold));
32175871362SJim Harris printf("Percentage used: %u\n",
322729ee4c8SWarner Losh letoh(health->percentage_used));
32375871362SJim Harris
32433a099d2SWarner Losh printf("Data units (512,000 byte) read: %s\n",
32533a099d2SWarner Losh uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf)));
326dc58cdf9SWarner Losh printf("Data units written: %s\n",
32733a099d2SWarner Losh uint128_to_str(to128(health->data_units_written), cbuf, sizeof(cbuf)));
32833a099d2SWarner Losh printf("Host read commands: %s\n",
32933a099d2SWarner Losh uint128_to_str(to128(health->host_read_commands), cbuf, sizeof(cbuf)));
33033a099d2SWarner Losh printf("Host write commands: %s\n",
33133a099d2SWarner Losh uint128_to_str(to128(health->host_write_commands), cbuf, sizeof(cbuf)));
33233a099d2SWarner Losh printf("Controller busy time (minutes): %s\n",
33333a099d2SWarner Losh uint128_to_str(to128(health->controller_busy_time), cbuf, sizeof(cbuf)));
33433a099d2SWarner Losh printf("Power cycles: %s\n",
33533a099d2SWarner Losh uint128_to_str(to128(health->power_cycles), cbuf, sizeof(cbuf)));
33633a099d2SWarner Losh printf("Power on hours: %s\n",
33733a099d2SWarner Losh uint128_to_str(to128(health->power_on_hours), cbuf, sizeof(cbuf)));
33833a099d2SWarner Losh printf("Unsafe shutdowns: %s\n",
33933a099d2SWarner Losh uint128_to_str(to128(health->unsafe_shutdowns), cbuf, sizeof(cbuf)));
34033a099d2SWarner Losh printf("Media errors: %s\n",
34133a099d2SWarner Losh uint128_to_str(to128(health->media_errors), cbuf, sizeof(cbuf)));
34233a099d2SWarner Losh printf("No. error info log entries: %s\n",
34333a099d2SWarner Losh uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf)));
344dc58cdf9SWarner Losh
345729ee4c8SWarner Losh printf("Warning Temp Composite Time: %d\n", letoh(health->warning_temp_time));
346729ee4c8SWarner Losh printf("Error Temp Composite Time: %d\n", letoh(health->error_temp_time));
3470d787e9bSWojciech Macek for (i = 0; i < 8; i++) {
348729ee4c8SWarner Losh if (letoh(health->temp_sensor[i]) == 0)
349dc58cdf9SWarner Losh continue;
350dc58cdf9SWarner Losh printf("Temperature Sensor %d: ", i + 1);
351729ee4c8SWarner Losh print_temp_K(letoh(health->temp_sensor[i]));
352dc58cdf9SWarner Losh }
353729ee4c8SWarner Losh printf("Temperature 1 Transition Count: %d\n", letoh(health->tmt1tc));
354729ee4c8SWarner Losh printf("Temperature 2 Transition Count: %d\n", letoh(health->tmt2tc));
355729ee4c8SWarner Losh printf("Total Time For Temperature 1: %d\n", letoh(health->ttftmt1));
356729ee4c8SWarner Losh printf("Total Time For Temperature 2: %d\n", letoh(health->ttftmt2));
35775871362SJim Harris }
35875871362SJim Harris
35975871362SJim Harris static void
print_log_firmware(const struct nvme_controller_data * cdata,void * buf,uint32_t size __unused)3600d787e9bSWojciech Macek print_log_firmware(const struct nvme_controller_data *cdata, void *buf, uint32_t size __unused)
36175871362SJim Harris {
36224e99dabSWarner Losh int i, slots;
36375871362SJim Harris const char *status;
36475871362SJim Harris struct nvme_firmware_page *fw = buf;
3650d787e9bSWojciech Macek uint8_t afi_slot;
3660d787e9bSWojciech Macek uint16_t oacs_fw;
3670d787e9bSWojciech Macek uint8_t fw_num_slots;
3680d787e9bSWojciech Macek
369fba73a40SJohn Baldwin afi_slot = NVMEV(NVME_FIRMWARE_PAGE_AFI_SLOT, fw->afi);
3700d787e9bSWojciech Macek
371fba73a40SJohn Baldwin oacs_fw = NVMEV(NVME_CTRLR_DATA_OACS_FIRMWARE, cdata->oacs);
372fba73a40SJohn Baldwin fw_num_slots = NVMEV(NVME_CTRLR_DATA_FRMW_NUM_SLOTS, cdata->frmw);
37375871362SJim Harris
37475871362SJim Harris printf("Firmware Slot Log\n");
37575871362SJim Harris printf("=================\n");
37675871362SJim Harris
3770d787e9bSWojciech Macek if (oacs_fw == 0)
37824e99dabSWarner Losh slots = 1;
37924e99dabSWarner Losh else
3800d787e9bSWojciech Macek slots = MIN(fw_num_slots, MAX_FW_SLOTS);
38124e99dabSWarner Losh
38224e99dabSWarner Losh for (i = 0; i < slots; i++) {
38375871362SJim Harris printf("Slot %d: ", i + 1);
3840d787e9bSWojciech Macek if (afi_slot == i + 1)
38575871362SJim Harris status = " Active";
38675871362SJim Harris else
38775871362SJim Harris status = "Inactive";
38875871362SJim Harris
3897485926eSJohn Baldwin if (fw->revision[i][0] == '\0')
39075871362SJim Harris printf("Empty\n");
39175871362SJim Harris else
3927485926eSJohn Baldwin printf("[%s] %.8s\n", status, fw->revision[i]);
39375871362SJim Harris }
39475871362SJim Harris }
39575871362SJim Harris
3966c99d132SAlexander Motin static void
print_log_ns(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)3976c99d132SAlexander Motin print_log_ns(const struct nvme_controller_data *cdata __unused, void *buf,
3986c99d132SAlexander Motin uint32_t size __unused)
3996c99d132SAlexander Motin {
4006c99d132SAlexander Motin struct nvme_ns_list *nsl;
4016c99d132SAlexander Motin u_int i;
4026c99d132SAlexander Motin
4036c99d132SAlexander Motin nsl = (struct nvme_ns_list *)buf;
4046c99d132SAlexander Motin printf("Changed Namespace List\n");
4056c99d132SAlexander Motin printf("======================\n");
4066c99d132SAlexander Motin
407acdf72f7SWarner Losh for (i = 0; i < nitems(nsl->ns) && letoh(nsl->ns[i]) != 0; i++) {
408acdf72f7SWarner Losh printf("%08x\n", letoh(nsl->ns[i]));
4096c99d132SAlexander Motin }
4106c99d132SAlexander Motin }
4116c99d132SAlexander Motin
4126c99d132SAlexander Motin static void
print_log_command_effects(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)4136c99d132SAlexander Motin print_log_command_effects(const struct nvme_controller_data *cdata __unused,
4146c99d132SAlexander Motin void *buf, uint32_t size __unused)
4156c99d132SAlexander Motin {
4166c99d132SAlexander Motin struct nvme_command_effects_page *ce;
4176c99d132SAlexander Motin u_int i;
4186c99d132SAlexander Motin uint32_t s;
4196c99d132SAlexander Motin
4206c99d132SAlexander Motin ce = (struct nvme_command_effects_page *)buf;
4216c99d132SAlexander Motin printf("Commands Supported and Effects\n");
4226c99d132SAlexander Motin printf("==============================\n");
4236c99d132SAlexander Motin printf(" Command\tLBCC\tNCC\tNIC\tCCC\tCSE\tUUID\n");
4246c99d132SAlexander Motin
4256c99d132SAlexander Motin for (i = 0; i < 255; i++) {
426b850caf7SWarner Losh s = letoh(ce->acs[i]);
427fba73a40SJohn Baldwin if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0)
4286c99d132SAlexander Motin continue;
4296c99d132SAlexander Motin printf("Admin\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i,
430fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No",
431fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No",
432fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No",
433fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No",
434fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_CSE, s),
435fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No");
4366c99d132SAlexander Motin }
4376c99d132SAlexander Motin for (i = 0; i < 255; i++) {
438b850caf7SWarner Losh s = letoh(ce->iocs[i]);
439fba73a40SJohn Baldwin if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0)
4406c99d132SAlexander Motin continue;
4416c99d132SAlexander Motin printf("I/O\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i,
442fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No",
443fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No",
444fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No",
445fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No",
446fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_CSE, s),
447fba73a40SJohn Baldwin NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No");
4486c99d132SAlexander Motin }
4496c99d132SAlexander Motin }
4506c99d132SAlexander Motin
4516c99d132SAlexander Motin static void
print_log_res_notification(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)4526c99d132SAlexander Motin print_log_res_notification(const struct nvme_controller_data *cdata __unused,
4536c99d132SAlexander Motin void *buf, uint32_t size __unused)
4546c99d132SAlexander Motin {
4556c99d132SAlexander Motin struct nvme_res_notification_page *rn;
4566c99d132SAlexander Motin
4576c99d132SAlexander Motin rn = (struct nvme_res_notification_page *)buf;
4586c99d132SAlexander Motin printf("Reservation Notification\n");
4596c99d132SAlexander Motin printf("========================\n");
4606c99d132SAlexander Motin
4613d28a9c6SWarner Losh printf("Log Page Count: %ju\n",
4623d28a9c6SWarner Losh (uintmax_t)letoh(rn->log_page_count));
4636c99d132SAlexander Motin printf("Log Page Type: ");
4643d28a9c6SWarner Losh switch (letoh(rn->log_page_type)) {
4656c99d132SAlexander Motin case 0:
4666c99d132SAlexander Motin printf("Empty Log Page\n");
4676c99d132SAlexander Motin break;
4686c99d132SAlexander Motin case 1:
4696c99d132SAlexander Motin printf("Registration Preempted\n");
4706c99d132SAlexander Motin break;
4716c99d132SAlexander Motin case 2:
4726c99d132SAlexander Motin printf("Reservation Released\n");
4736c99d132SAlexander Motin break;
4746c99d132SAlexander Motin case 3:
4756c99d132SAlexander Motin printf("Reservation Preempted\n");
4766c99d132SAlexander Motin break;
4776c99d132SAlexander Motin default:
4783d28a9c6SWarner Losh printf("Unknown %x\n", letoh(rn->log_page_type));
4796c99d132SAlexander Motin break;
4806c99d132SAlexander Motin };
4813d28a9c6SWarner Losh printf("Number of Available Log Pages: %d\n", letoh(rn->available_log_pages));
4823d28a9c6SWarner Losh printf("Namespace ID: 0x%x\n", letoh(rn->nsid));
4836c99d132SAlexander Motin }
4846c99d132SAlexander Motin
4856c99d132SAlexander Motin static void
print_log_sanitize_status(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)4866c99d132SAlexander Motin print_log_sanitize_status(const struct nvme_controller_data *cdata __unused,
4876c99d132SAlexander Motin void *buf, uint32_t size __unused)
4886c99d132SAlexander Motin {
4896c99d132SAlexander Motin struct nvme_sanitize_status_page *ss;
4906c99d132SAlexander Motin u_int p;
49155a1679eSWarner Losh uint16_t sprog, sstat;
4926c99d132SAlexander Motin
4936c99d132SAlexander Motin ss = (struct nvme_sanitize_status_page *)buf;
4946c99d132SAlexander Motin printf("Sanitize Status\n");
4956c99d132SAlexander Motin printf("===============\n");
4966c99d132SAlexander Motin
49755a1679eSWarner Losh sprog = letoh(ss->sprog);
4986c99d132SAlexander Motin printf("Sanitize Progress: %u%% (%u/65535)\n",
49955a1679eSWarner Losh (sprog * 100 + 32768) / 65536, sprog);
5006c99d132SAlexander Motin printf("Sanitize Status: ");
50155a1679eSWarner Losh sstat = letoh(ss->sstat);
50255a1679eSWarner Losh switch (NVMEV(NVME_SS_PAGE_SSTAT_STATUS, sstat)) {
5036c99d132SAlexander Motin case NVME_SS_PAGE_SSTAT_STATUS_NEVER:
5046c99d132SAlexander Motin printf("Never sanitized");
5056c99d132SAlexander Motin break;
5066c99d132SAlexander Motin case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED:
5076c99d132SAlexander Motin printf("Completed");
5086c99d132SAlexander Motin break;
5096c99d132SAlexander Motin case NVME_SS_PAGE_SSTAT_STATUS_INPROG:
5106c99d132SAlexander Motin printf("In Progress");
5116c99d132SAlexander Motin break;
5126c99d132SAlexander Motin case NVME_SS_PAGE_SSTAT_STATUS_FAILED:
5136c99d132SAlexander Motin printf("Failed");
5146c99d132SAlexander Motin break;
5156c99d132SAlexander Motin case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD:
5166c99d132SAlexander Motin printf("Completed with deallocation");
5176c99d132SAlexander Motin break;
5186c99d132SAlexander Motin default:
51955a1679eSWarner Losh printf("Unknown 0x%x", sstat);
5206c99d132SAlexander Motin break;
5216c99d132SAlexander Motin }
52255a1679eSWarner Losh p = NVMEV(NVME_SS_PAGE_SSTAT_PASSES, sstat);
5236c99d132SAlexander Motin if (p > 0)
5246c99d132SAlexander Motin printf(", %d passes", p);
52555a1679eSWarner Losh if (NVMEV(NVME_SS_PAGE_SSTAT_GDE, sstat) != 0)
5266c99d132SAlexander Motin printf(", Global Data Erased");
5276c99d132SAlexander Motin printf("\n");
52855a1679eSWarner Losh printf("Sanitize Command Dword 10: 0x%x\n", letoh(ss->scdw10));
52955a1679eSWarner Losh printf("Time For Overwrite: %u sec\n", letoh(ss->etfo));
53055a1679eSWarner Losh printf("Time For Block Erase: %u sec\n", letoh(ss->etfbe));
53155a1679eSWarner Losh printf("Time For Crypto Erase: %u sec\n", letoh(ss->etfce));
53255a1679eSWarner Losh printf("Time For Overwrite No-Deallocate: %u sec\n", letoh(ss->etfownd));
53355a1679eSWarner Losh printf("Time For Block Erase No-Deallocate: %u sec\n", letoh(ss->etfbewnd));
53455a1679eSWarner Losh printf("Time For Crypto Erase No-Deallocate: %u sec\n", letoh(ss->etfcewnd));
5356c99d132SAlexander Motin }
5366c99d132SAlexander Motin
53767334019SChuck Tuffli static const char *
53867334019SChuck Tuffli self_test_res[] = {
53967334019SChuck Tuffli [0] = "completed without error",
54067334019SChuck Tuffli [1] = "aborted by a Device Self-test command",
54167334019SChuck Tuffli [2] = "aborted by a Controller Level Reset",
54267334019SChuck Tuffli [3] = "aborted due to namespace removal",
54367334019SChuck Tuffli [4] = "aborted due to Format NVM command",
54467334019SChuck Tuffli [5] = "failed due to fatal or unknown test error",
54567334019SChuck Tuffli [6] = "completed with an unknown segment that failed",
54667334019SChuck Tuffli [7] = "completed with one or more failed segments",
54767334019SChuck Tuffli [8] = "aborted for unknown reason",
54867334019SChuck Tuffli [9] = "aborted due to a sanitize operation",
54967334019SChuck Tuffli };
55067334019SChuck Tuffli static uint32_t self_test_res_max = nitems(self_test_res);
55167334019SChuck Tuffli
55267334019SChuck Tuffli static void
print_log_self_test_status(const struct nvme_controller_data * cdata __unused,void * buf,uint32_t size __unused)55367334019SChuck Tuffli print_log_self_test_status(const struct nvme_controller_data *cdata __unused,
55467334019SChuck Tuffli void *buf, uint32_t size __unused)
55567334019SChuck Tuffli {
55667334019SChuck Tuffli struct nvme_device_self_test_page *dst;
55767334019SChuck Tuffli uint32_t r;
55898f841efSWarner Losh uint16_t vs;
55967334019SChuck Tuffli
56067334019SChuck Tuffli dst = buf;
56167334019SChuck Tuffli printf("Device Self-test Status\n");
56267334019SChuck Tuffli printf("=======================\n");
56367334019SChuck Tuffli
56467334019SChuck Tuffli printf("Current Operation: ");
56598f841efSWarner Losh switch (letoh(dst->curr_operation)) {
56667334019SChuck Tuffli case 0x0:
56767334019SChuck Tuffli printf("No device self-test operation in progress\n");
56867334019SChuck Tuffli break;
56967334019SChuck Tuffli case 0x1:
57067334019SChuck Tuffli printf("Short device self-test operation in progress\n");
57167334019SChuck Tuffli break;
57267334019SChuck Tuffli case 0x2:
57367334019SChuck Tuffli printf("Extended device self-test operation in progress\n");
57467334019SChuck Tuffli break;
57567334019SChuck Tuffli case 0xe:
57667334019SChuck Tuffli printf("Vendor specific\n");
57767334019SChuck Tuffli break;
57867334019SChuck Tuffli default:
57998f841efSWarner Losh printf("Reserved (0x%x)\n", letoh(dst->curr_operation));
58067334019SChuck Tuffli }
58167334019SChuck Tuffli
58298f841efSWarner Losh if (letoh(dst->curr_operation) != 0)
58398f841efSWarner Losh printf("Current Completion: %u%%\n", letoh(dst->curr_compl) & 0x7f);
58467334019SChuck Tuffli
58567334019SChuck Tuffli printf("Results\n");
58667334019SChuck Tuffli for (r = 0; r < 20; r++) {
58767334019SChuck Tuffli uint64_t failing_lba;
58898f841efSWarner Losh uint8_t code, res, status;
58967334019SChuck Tuffli
59098f841efSWarner Losh status = letoh(dst->result[r].status);
59198f841efSWarner Losh code = (status >> 4) & 0xf;
59298f841efSWarner Losh res = status & 0xf;
59367334019SChuck Tuffli
59467334019SChuck Tuffli if (res == 0xf)
59567334019SChuck Tuffli continue;
59667334019SChuck Tuffli
59767334019SChuck Tuffli printf("[%2u] ", r);
59867334019SChuck Tuffli switch (code) {
59967334019SChuck Tuffli case 0x1:
60067334019SChuck Tuffli printf("Short device self-test");
60167334019SChuck Tuffli break;
60267334019SChuck Tuffli case 0x2:
60367334019SChuck Tuffli printf("Extended device self-test");
60467334019SChuck Tuffli break;
60567334019SChuck Tuffli case 0xe:
60667334019SChuck Tuffli printf("Vendor specific");
60767334019SChuck Tuffli break;
60867334019SChuck Tuffli default:
60967334019SChuck Tuffli printf("Reserved (0x%x)", code);
61067334019SChuck Tuffli }
61167334019SChuck Tuffli if (res < self_test_res_max)
61267334019SChuck Tuffli printf(" %s", self_test_res[res]);
61367334019SChuck Tuffli else
61467334019SChuck Tuffli printf(" Reserved status 0x%x", res);
61567334019SChuck Tuffli
61667334019SChuck Tuffli if (res == 7)
61798f841efSWarner Losh printf(" starting in segment %u",
61898f841efSWarner Losh letoh(dst->result[r].segment_num));
61967334019SChuck Tuffli
62067334019SChuck Tuffli #define BIT(b) (1 << (b))
62198f841efSWarner Losh if (letoh(dst->result[r].valid_diag_info) & BIT(0))
62298f841efSWarner Losh printf(" NSID=0x%x", letoh(dst->result[r].nsid));
62398f841efSWarner Losh if (letoh(dst->result[r].valid_diag_info) & BIT(1)) {
62467334019SChuck Tuffli memcpy(&failing_lba, dst->result[r].failing_lba,
62567334019SChuck Tuffli sizeof(failing_lba));
62698f841efSWarner Losh printf(" FLBA=0x%jx", (uintmax_t)letoh(failing_lba));
62767334019SChuck Tuffli }
62898f841efSWarner Losh if (letoh(dst->result[r].valid_diag_info) & BIT(2))
62998f841efSWarner Losh printf(" SCT=0x%x", letoh(dst->result[r].status_code_type));
63098f841efSWarner Losh if (letoh(dst->result[r].valid_diag_info) & BIT(3))
63198f841efSWarner Losh printf(" SC=0x%x", letoh(dst->result[r].status_code));
63267334019SChuck Tuffli #undef BIT
63398f841efSWarner Losh memcpy(&vs, dst->result[r].vendor_specific, sizeof(vs));
63498f841efSWarner Losh printf(" VENDOR_SPECIFIC=0x%x", letoh(vs));
63567334019SChuck Tuffli printf("\n");
63667334019SChuck Tuffli }
63767334019SChuck Tuffli }
63867334019SChuck Tuffli
6399caeb430SWarner Losh /*
640ab1dd091SWarner Losh * Table of log page printer / sizing.
641ab1dd091SWarner Losh *
642d8fab838SWarner Losh * Make sure you keep all the pages of one vendor together so -v help
643d8fab838SWarner Losh * lists all the vendors pages.
644ab1dd091SWarner Losh */
645aecd1901SWarner Losh NVME_LOGPAGE(error,
646aecd1901SWarner Losh NVME_LOG_ERROR, NULL, "Drive Error Log",
647aecd1901SWarner Losh print_log_error, 0);
648aecd1901SWarner Losh NVME_LOGPAGE(health,
649aecd1901SWarner Losh NVME_LOG_HEALTH_INFORMATION, NULL, "Health/SMART Data",
650aecd1901SWarner Losh print_log_health, sizeof(struct nvme_health_information_page));
651aecd1901SWarner Losh NVME_LOGPAGE(fw,
652aecd1901SWarner Losh NVME_LOG_FIRMWARE_SLOT, NULL, "Firmware Information",
653aecd1901SWarner Losh print_log_firmware, sizeof(struct nvme_firmware_page));
6546c99d132SAlexander Motin NVME_LOGPAGE(ns,
6556c99d132SAlexander Motin NVME_LOG_CHANGED_NAMESPACE, NULL, "Changed Namespace List",
6566c99d132SAlexander Motin print_log_ns, sizeof(struct nvme_ns_list));
6576c99d132SAlexander Motin NVME_LOGPAGE(ce,
6586c99d132SAlexander Motin NVME_LOG_COMMAND_EFFECT, NULL, "Commands Supported and Effects",
6596c99d132SAlexander Motin print_log_command_effects, sizeof(struct nvme_command_effects_page));
6606c99d132SAlexander Motin NVME_LOGPAGE(dst,
6616c99d132SAlexander Motin NVME_LOG_DEVICE_SELF_TEST, NULL, "Device Self-test",
66267334019SChuck Tuffli print_log_self_test_status, sizeof(struct nvme_device_self_test_page));
6636c99d132SAlexander Motin NVME_LOGPAGE(thi,
6646c99d132SAlexander Motin NVME_LOG_TELEMETRY_HOST_INITIATED, NULL, "Telemetry Host-Initiated",
6656c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6666c99d132SAlexander Motin NVME_LOGPAGE(tci,
6676c99d132SAlexander Motin NVME_LOG_TELEMETRY_CONTROLLER_INITIATED, NULL, "Telemetry Controller-Initiated",
6686c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6696c99d132SAlexander Motin NVME_LOGPAGE(egi,
6706c99d132SAlexander Motin NVME_LOG_ENDURANCE_GROUP_INFORMATION, NULL, "Endurance Group Information",
6716c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6726c99d132SAlexander Motin NVME_LOGPAGE(plpns,
6736c99d132SAlexander Motin NVME_LOG_PREDICTABLE_LATENCY_PER_NVM_SET, NULL, "Predictable Latency Per NVM Set",
6746c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6756c99d132SAlexander Motin NVME_LOGPAGE(ple,
6766c99d132SAlexander Motin NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE, NULL, "Predictable Latency Event Aggregate",
6776c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6786c99d132SAlexander Motin NVME_LOGPAGE(ana,
679c2318cf8SChuck Tuffli NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS, NULL, "Asymmetric Namespace Access",
6806c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6816c99d132SAlexander Motin NVME_LOGPAGE(pel,
6826c99d132SAlexander Motin NVME_LOG_PERSISTENT_EVENT_LOG, NULL, "Persistent Event Log",
6836c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6846c99d132SAlexander Motin NVME_LOGPAGE(lbasi,
6856c99d132SAlexander Motin NVME_LOG_LBA_STATUS_INFORMATION, NULL, "LBA Status Information",
6866c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6876c99d132SAlexander Motin NVME_LOGPAGE(egea,
6886c99d132SAlexander Motin NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE, NULL, "Endurance Group Event Aggregate",
6896c99d132SAlexander Motin NULL, DEFAULT_SIZE);
6906c99d132SAlexander Motin NVME_LOGPAGE(res_notification,
6916c99d132SAlexander Motin NVME_LOG_RES_NOTIFICATION, NULL, "Reservation Notification",
6926c99d132SAlexander Motin print_log_res_notification, sizeof(struct nvme_res_notification_page));
6936c99d132SAlexander Motin NVME_LOGPAGE(sanitize_status,
6946c99d132SAlexander Motin NVME_LOG_SANITIZE_STATUS, NULL, "Sanitize Status",
6956c99d132SAlexander Motin print_log_sanitize_status, sizeof(struct nvme_sanitize_status_page));
69675871362SJim Harris
69775871362SJim Harris static void
logpage_help(void)698d8fab838SWarner Losh logpage_help(void)
699d8fab838SWarner Losh {
700f428a90aSWarner Losh const struct logpage_function *f;
701d8fab838SWarner Losh const char *v;
702d8fab838SWarner Losh
703d8fab838SWarner Losh fprintf(stderr, "\n");
704d8fab838SWarner Losh fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name");
705d8fab838SWarner Losh fprintf(stderr, "-------- ---------- ----------\n");
706f428a90aSWarner Losh SLIST_FOREACH(f, &logpages, link) {
707f428a90aSWarner Losh v = f->vendor == NULL ? "-" : f->vendor;
708f428a90aSWarner Losh fprintf(stderr, "0x%02x %-10s %s\n", f->log_page, v, f->name);
709d8fab838SWarner Losh }
710d8fab838SWarner Losh
7115dc463f9SAlexander Motin exit(EX_USAGE);
712d8fab838SWarner Losh }
713d8fab838SWarner Losh
714a13a291aSWarner Losh static void
logpage(const struct cmd * f,int argc,char * argv[])715f634b4c1SWarner Losh logpage(const struct cmd *f, int argc, char *argv[])
71675871362SJim Harris {
717635c517aSAlexander Motin int fd;
718a7bf63beSAlexander Motin char *path;
719635c517aSAlexander Motin uint32_t nsid, size;
72075871362SJim Harris void *buf;
721f634b4c1SWarner Losh const struct logpage_function *lpf;
72275871362SJim Harris struct nvme_controller_data cdata;
72375871362SJim Harris print_fn_t print_fn;
7240d787e9bSWojciech Macek uint8_t ns_smart;
72575871362SJim Harris
726f634b4c1SWarner Losh if (arg_parse(argc, argv, f))
727f634b4c1SWarner Losh return;
728f634b4c1SWarner Losh if (opt.hex && opt.binary) {
72975871362SJim Harris fprintf(stderr,
730f634b4c1SWarner Losh "Can't specify both binary and hex\n");
731f634b4c1SWarner Losh arg_help(argc, argv, f);
73275871362SJim Harris }
733f634b4c1SWarner Losh if (opt.vendor != NULL && strcmp(opt.vendor, "help") == 0)
734d8fab838SWarner Losh logpage_help();
735f634b4c1SWarner Losh if (opt.page == NONE) {
736f634b4c1SWarner Losh fprintf(stderr, "Missing page_id (-p).\n");
737f634b4c1SWarner Losh arg_help(argc, argv, f);
73875871362SJim Harris }
7391f15d49eSAlexander Motin open_dev(opt.dev, &fd, 0, 1);
740a7bf63beSAlexander Motin get_nsid(fd, &path, &nsid);
741a7bf63beSAlexander Motin if (nsid == 0) {
742a7bf63beSAlexander Motin nsid = NVME_GLOBAL_NAMESPACE_TAG;
743a7bf63beSAlexander Motin } else {
744a7bf63beSAlexander Motin close(fd);
7451f15d49eSAlexander Motin open_dev(path, &fd, 0, 1);
7462528d6a3SJim Harris }
747a7bf63beSAlexander Motin free(path);
7482528d6a3SJim Harris
7495dc463f9SAlexander Motin if (read_controller_data(fd, &cdata))
7505dc463f9SAlexander Motin errx(EX_IOERR, "Identify request failed");
751628683cbSJim Harris
752fba73a40SJohn Baldwin ns_smart = NVMEV(NVME_CTRLR_DATA_LPA_NS_SMART, cdata.lpa);
7530d787e9bSWojciech Macek
75475871362SJim Harris /*
755abe10d21SAndrius V * The log page attributes indicate whether or not the controller
75675871362SJim Harris * supports the SMART/Health information log page on a per
75775871362SJim Harris * namespace basis.
75875871362SJim Harris */
759a7bf63beSAlexander Motin if (nsid != NVME_GLOBAL_NAMESPACE_TAG) {
760f634b4c1SWarner Losh if (opt.page != NVME_LOG_HEALTH_INFORMATION)
7615dc463f9SAlexander Motin errx(EX_USAGE, "log page %d valid only at controller level",
762f634b4c1SWarner Losh opt.page);
7630d787e9bSWojciech Macek if (ns_smart == 0)
7645dc463f9SAlexander Motin errx(EX_UNAVAILABLE,
7652528d6a3SJim Harris "controller does not support per namespace "
7662528d6a3SJim Harris "smart/health information");
76775871362SJim Harris }
76875871362SJim Harris
7698ce85adfSWarner Losh print_fn = print_log_hex;
770cc63e8e6SWarner Losh size = DEFAULT_SIZE;
771f634b4c1SWarner Losh if (opt.binary)
772ba6da686SWarner Losh print_fn = print_bin;
773f634b4c1SWarner Losh if (!opt.binary && !opt.hex) {
77475871362SJim Harris /*
7755619c99fSWarner Losh * See if there is a pretty print function for the specified log
7765619c99fSWarner Losh * page. If one isn't found, we just revert to the default
777e8604394SWarner Losh * (print_hex). If there was a vendor specified by the user, and
7785619c99fSWarner Losh * the page is vendor specific, don't match the print function
7795619c99fSWarner Losh * unless the vendors match.
78075871362SJim Harris */
781f634b4c1SWarner Losh SLIST_FOREACH(lpf, &logpages, link) {
78216091536SWarner Losh if (lpf->vendor != NULL && opt.vendor != NULL &&
78316091536SWarner Losh strcmp(lpf->vendor, opt.vendor) != 0)
7845619c99fSWarner Losh continue;
785f634b4c1SWarner Losh if (opt.page != lpf->log_page)
7865619c99fSWarner Losh continue;
7876c99d132SAlexander Motin if (lpf->print_fn != NULL)
788f634b4c1SWarner Losh print_fn = lpf->print_fn;
789f634b4c1SWarner Losh size = lpf->size;
79075871362SJim Harris break;
79175871362SJim Harris }
79275871362SJim Harris }
79375871362SJim Harris
794f634b4c1SWarner Losh if (opt.page == NVME_LOG_ERROR) {
79575871362SJim Harris size = sizeof(struct nvme_error_information_entry);
79675871362SJim Harris size *= (cdata.elpe + 1);
79775871362SJim Harris }
79875871362SJim Harris
799cc63e8e6SWarner Losh /* Read the log page */
80075871362SJim Harris buf = get_log_buffer(size);
801*98ab7d0aSWarner Losh read_logpage(fd, opt.page, nsid, opt.lsp, opt.lsi, opt.rae,
802*98ab7d0aSWarner Losh 0, 0, 0, 0, buf, size);
8038ce85adfSWarner Losh print_fn(&cdata, buf, size);
80475871362SJim Harris
80575871362SJim Harris close(fd);
806821ef73cSJim Harris exit(0);
80775871362SJim Harris }
808