1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2013 EMC Corp. 5 * All rights reserved. 6 * 7 * Copyright (C) 2012-2013 Intel Corporation 8 * All rights reserved. 9 * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/ioccom.h> 35 36 #include <ctype.h> 37 #include <err.h> 38 #include <fcntl.h> 39 #include <stdbool.h> 40 #include <stddef.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <sysexits.h> 45 #include <unistd.h> 46 #include <sys/endian.h> 47 48 #include "nvmecontrol.h" 49 50 /* Tables for command line parsing */ 51 52 static cmd_fn_t logpage; 53 54 #define NONE 0xffffffffu 55 static struct options { 56 bool binary; 57 bool hex; 58 uint32_t page; 59 uint8_t lsp; 60 uint16_t lsi; 61 bool rae; 62 const char *vendor; 63 const char *dev; 64 } opt = { 65 .binary = false, 66 .hex = false, 67 .page = NONE, 68 .lsp = 0, 69 .lsi = 0, 70 .rae = false, 71 .vendor = NULL, 72 .dev = NULL, 73 }; 74 75 static const struct opts logpage_opts[] = { 76 #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 77 OPT("binary", 'b', arg_none, opt, binary, 78 "Dump the log page as binary"), 79 OPT("hex", 'x', arg_none, opt, hex, 80 "Dump the log page as hex"), 81 OPT("page", 'p', arg_uint32, opt, page, 82 "Page to dump"), 83 OPT("lsp", 'f', arg_uint8, opt, lsp, 84 "Log Specific Field"), 85 OPT("lsi", 'i', arg_uint16, opt, lsi, 86 "Log Specific Identifier"), 87 OPT("rae", 'r', arg_none, opt, rae, 88 "Retain Asynchronous Event"), 89 OPT("vendor", 'v', arg_string, opt, vendor, 90 "Vendor specific formatting"), 91 { NULL, 0, arg_none, NULL, NULL } 92 }; 93 #undef OPT 94 95 static const struct args logpage_args[] = { 96 { arg_string, &opt.dev, "<controller id|namespace id>" }, 97 { arg_none, NULL, NULL }, 98 }; 99 100 static struct cmd logpage_cmd = { 101 .name = "logpage", 102 .fn = logpage, 103 .descr = "Print logpages in human-readable form", 104 .ctx_size = sizeof(opt), 105 .opts = logpage_opts, 106 .args = logpage_args, 107 }; 108 109 CMD_COMMAND(logpage_cmd); 110 111 /* End of tables for command line parsing */ 112 113 #define MAX_FW_SLOTS (7) 114 115 static SLIST_HEAD(,logpage_function) logpages; 116 117 static int 118 logpage_compare(struct logpage_function *a, struct logpage_function *b) 119 { 120 int c; 121 122 if ((a->vendor == NULL) != (b->vendor == NULL)) 123 return (a->vendor == NULL ? -1 : 1); 124 if (a->vendor != NULL) { 125 c = strcmp(a->vendor, b->vendor); 126 if (c != 0) 127 return (c); 128 } 129 return ((int)a->log_page - (int)b->log_page); 130 } 131 132 void 133 logpage_register(struct logpage_function *p) 134 { 135 struct logpage_function *l, *a; 136 137 a = NULL; 138 l = SLIST_FIRST(&logpages); 139 while (l != NULL) { 140 if (logpage_compare(l, p) > 0) 141 break; 142 a = l; 143 l = SLIST_NEXT(l, link); 144 } 145 if (a == NULL) 146 SLIST_INSERT_HEAD(&logpages, p, link); 147 else 148 SLIST_INSERT_AFTER(a, p, link); 149 } 150 151 const char * 152 kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key) 153 { 154 static char bad[32]; 155 size_t i; 156 157 for (i = 0; i < kv_count; i++, kv++) 158 if (kv->key == key) 159 return kv->name; 160 snprintf(bad, sizeof(bad), "Attribute %#x", key); 161 return bad; 162 } 163 164 static void 165 print_log_hex(const struct nvme_controller_data *cdata __unused, void *data, uint32_t length) 166 { 167 168 print_hex(data, length); 169 } 170 171 static void 172 print_bin(const struct nvme_controller_data *cdata __unused, void *data, uint32_t length) 173 { 174 175 write(STDOUT_FILENO, data, length); 176 } 177 178 static void * 179 get_log_buffer(uint32_t size) 180 { 181 void *buf; 182 183 if ((buf = malloc(size)) == NULL) 184 errx(EX_OSERR, "unable to malloc %u bytes", size); 185 186 memset(buf, 0, size); 187 return (buf); 188 } 189 190 void 191 read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp, 192 uint16_t lsi, uint8_t rae, void *payload, uint32_t payload_size) 193 { 194 struct nvme_pt_command pt; 195 struct nvme_error_information_entry *err_entry; 196 u_int i, err_pages, numd; 197 198 numd = payload_size / sizeof(uint32_t) - 1; 199 memset(&pt, 0, sizeof(pt)); 200 pt.cmd.opc = NVME_OPC_GET_LOG_PAGE; 201 pt.cmd.nsid = htole32(nsid); 202 pt.cmd.cdw10 = htole32( 203 (numd << 16) | /* NUMDL */ 204 (rae << 15) | /* RAE */ 205 (lsp << 8) | /* LSP */ 206 log_page); /* LID */ 207 pt.cmd.cdw11 = htole32( 208 ((uint32_t)lsi << 16) | /* LSI */ 209 (numd >> 16)); /* NUMDU */ 210 pt.cmd.cdw12 = 0; /* LPOL */ 211 pt.cmd.cdw13 = 0; /* LPOU */ 212 pt.cmd.cdw14 = 0; /* UUID Index */ 213 pt.buf = payload; 214 pt.len = payload_size; 215 pt.is_read = 1; 216 217 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 218 err(EX_IOERR, "get log page request failed"); 219 220 /* Convert data to host endian */ 221 switch (log_page) { 222 case NVME_LOG_ERROR: 223 err_entry = (struct nvme_error_information_entry *)payload; 224 err_pages = payload_size / sizeof(struct nvme_error_information_entry); 225 for (i = 0; i < err_pages; i++) 226 nvme_error_information_entry_swapbytes(err_entry++); 227 break; 228 case NVME_LOG_HEALTH_INFORMATION: 229 nvme_health_information_page_swapbytes( 230 (struct nvme_health_information_page *)payload); 231 break; 232 case NVME_LOG_CHANGED_NAMESPACE: 233 nvme_ns_list_swapbytes((struct nvme_ns_list *)payload); 234 break; 235 case NVME_LOG_DEVICE_SELF_TEST: 236 nvme_device_self_test_swapbytes( 237 (struct nvme_device_self_test_page *)payload); 238 break; 239 case NVME_LOG_COMMAND_EFFECT: 240 nvme_command_effects_page_swapbytes( 241 (struct nvme_command_effects_page *)payload); 242 break; 243 case NVME_LOG_RES_NOTIFICATION: 244 nvme_res_notification_page_swapbytes( 245 (struct nvme_res_notification_page *)payload); 246 break; 247 case NVME_LOG_SANITIZE_STATUS: 248 nvme_sanitize_status_page_swapbytes( 249 (struct nvme_sanitize_status_page *)payload); 250 break; 251 case INTEL_LOG_TEMP_STATS: 252 intel_log_temp_stats_swapbytes( 253 (struct intel_log_temp_stats *)payload); 254 break; 255 default: 256 break; 257 } 258 259 if (nvme_completion_is_error(&pt.cpl)) 260 errx(EX_IOERR, "get log page request returned error"); 261 } 262 263 static void 264 print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size) 265 { 266 int i, nentries; 267 uint16_t status; 268 uint8_t p, sc, sct, m, dnr; 269 struct nvme_error_information_entry *entry = buf; 270 271 printf("Error Information Log\n"); 272 printf("=====================\n"); 273 274 if (entry->error_count == 0) { 275 printf("No error entries found\n"); 276 return; 277 } 278 279 nentries = size/sizeof(struct nvme_error_information_entry); 280 for (i = 0; i < nentries; i++, entry++) { 281 if (entry->error_count == 0) 282 break; 283 284 status = entry->status; 285 286 p = NVME_STATUS_GET_P(status); 287 sc = NVME_STATUS_GET_SC(status); 288 sct = NVME_STATUS_GET_SCT(status); 289 m = NVME_STATUS_GET_M(status); 290 dnr = NVME_STATUS_GET_DNR(status); 291 292 printf("Entry %02d\n", i + 1); 293 printf("=========\n"); 294 printf(" Error count: %ju\n", entry->error_count); 295 printf(" Submission queue ID: %u\n", entry->sqid); 296 printf(" Command ID: %u\n", entry->cid); 297 /* TODO: Export nvme_status_string structures from kernel? */ 298 printf(" Status:\n"); 299 printf(" Phase tag: %d\n", p); 300 printf(" Status code: %d\n", sc); 301 printf(" Status code type: %d\n", sct); 302 printf(" More: %d\n", m); 303 printf(" DNR: %d\n", dnr); 304 printf(" Error location: %u\n", entry->error_location); 305 printf(" LBA: %ju\n", entry->lba); 306 printf(" Namespace ID: %u\n", entry->nsid); 307 printf(" Vendor specific info: %u\n", entry->vendor_specific); 308 printf(" Transport type: %u\n", entry->trtype); 309 printf(" Command specific info:%ju\n", entry->csi); 310 printf(" Transport specific: %u\n", entry->ttsi); 311 } 312 } 313 314 void 315 print_temp_K(uint16_t t) 316 { 317 printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, (float)t * 9 / 5 - 459.67); 318 } 319 320 void 321 print_temp_C(uint16_t t) 322 { 323 printf("%2.2f K, %u C, %3.2f F\n", (float)t + 273.15, t, (float)t * 9 / 5 + 32); 324 } 325 326 static void 327 print_log_health(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused) 328 { 329 struct nvme_health_information_page *health = buf; 330 char cbuf[UINT128_DIG + 1]; 331 uint8_t warning; 332 int i; 333 334 warning = health->critical_warning; 335 336 printf("SMART/Health Information Log\n"); 337 printf("============================\n"); 338 339 printf("Critical Warning State: 0x%02x\n", warning); 340 printf(" Available spare: %d\n", 341 !!(warning & NVME_CRIT_WARN_ST_AVAILABLE_SPARE)); 342 printf(" Temperature: %d\n", 343 !!(warning & NVME_CRIT_WARN_ST_TEMPERATURE)); 344 printf(" Device reliability: %d\n", 345 !!(warning & NVME_CRIT_WARN_ST_DEVICE_RELIABILITY)); 346 printf(" Read only: %d\n", 347 !!(warning & NVME_CRIT_WARN_ST_READ_ONLY)); 348 printf(" Volatile memory backup: %d\n", 349 !!(warning & NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP)); 350 printf("Temperature: "); 351 print_temp_K(health->temperature); 352 printf("Available spare: %u\n", 353 health->available_spare); 354 printf("Available spare threshold: %u\n", 355 health->available_spare_threshold); 356 printf("Percentage used: %u\n", 357 health->percentage_used); 358 359 printf("Data units (512,000 byte) read: %s\n", 360 uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf))); 361 printf("Data units written: %s\n", 362 uint128_to_str(to128(health->data_units_written), cbuf, sizeof(cbuf))); 363 printf("Host read commands: %s\n", 364 uint128_to_str(to128(health->host_read_commands), cbuf, sizeof(cbuf))); 365 printf("Host write commands: %s\n", 366 uint128_to_str(to128(health->host_write_commands), cbuf, sizeof(cbuf))); 367 printf("Controller busy time (minutes): %s\n", 368 uint128_to_str(to128(health->controller_busy_time), cbuf, sizeof(cbuf))); 369 printf("Power cycles: %s\n", 370 uint128_to_str(to128(health->power_cycles), cbuf, sizeof(cbuf))); 371 printf("Power on hours: %s\n", 372 uint128_to_str(to128(health->power_on_hours), cbuf, sizeof(cbuf))); 373 printf("Unsafe shutdowns: %s\n", 374 uint128_to_str(to128(health->unsafe_shutdowns), cbuf, sizeof(cbuf))); 375 printf("Media errors: %s\n", 376 uint128_to_str(to128(health->media_errors), cbuf, sizeof(cbuf))); 377 printf("No. error info log entries: %s\n", 378 uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf))); 379 380 printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); 381 printf("Error Temp Composite Time: %d\n", health->error_temp_time); 382 for (i = 0; i < 8; i++) { 383 if (health->temp_sensor[i] == 0) 384 continue; 385 printf("Temperature Sensor %d: ", i + 1); 386 print_temp_K(health->temp_sensor[i]); 387 } 388 printf("Temperature 1 Transition Count: %d\n", health->tmt1tc); 389 printf("Temperature 2 Transition Count: %d\n", health->tmt2tc); 390 printf("Total Time For Temperature 1: %d\n", health->ttftmt1); 391 printf("Total Time For Temperature 2: %d\n", health->ttftmt2); 392 } 393 394 static void 395 print_log_firmware(const struct nvme_controller_data *cdata, void *buf, uint32_t size __unused) 396 { 397 int i, slots; 398 const char *status; 399 struct nvme_firmware_page *fw = buf; 400 uint8_t afi_slot; 401 uint16_t oacs_fw; 402 uint8_t fw_num_slots; 403 404 afi_slot = NVMEV(NVME_FIRMWARE_PAGE_AFI_SLOT, fw->afi); 405 406 oacs_fw = NVMEV(NVME_CTRLR_DATA_OACS_FIRMWARE, cdata->oacs); 407 fw_num_slots = NVMEV(NVME_CTRLR_DATA_FRMW_NUM_SLOTS, cdata->frmw); 408 409 printf("Firmware Slot Log\n"); 410 printf("=================\n"); 411 412 if (oacs_fw == 0) 413 slots = 1; 414 else 415 slots = MIN(fw_num_slots, MAX_FW_SLOTS); 416 417 for (i = 0; i < slots; i++) { 418 printf("Slot %d: ", i + 1); 419 if (afi_slot == i + 1) 420 status = " Active"; 421 else 422 status = "Inactive"; 423 424 if (fw->revision[i][0] == '\0') 425 printf("Empty\n"); 426 else 427 printf("[%s] %.8s\n", status, fw->revision[i]); 428 } 429 } 430 431 static void 432 print_log_ns(const struct nvme_controller_data *cdata __unused, void *buf, 433 uint32_t size __unused) 434 { 435 struct nvme_ns_list *nsl; 436 u_int i; 437 438 nsl = (struct nvme_ns_list *)buf; 439 printf("Changed Namespace List\n"); 440 printf("======================\n"); 441 442 for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) { 443 printf("%08x\n", nsl->ns[i]); 444 } 445 } 446 447 static void 448 print_log_command_effects(const struct nvme_controller_data *cdata __unused, 449 void *buf, uint32_t size __unused) 450 { 451 struct nvme_command_effects_page *ce; 452 u_int i; 453 uint32_t s; 454 455 ce = (struct nvme_command_effects_page *)buf; 456 printf("Commands Supported and Effects\n"); 457 printf("==============================\n"); 458 printf(" Command\tLBCC\tNCC\tNIC\tCCC\tCSE\tUUID\n"); 459 460 for (i = 0; i < 255; i++) { 461 s = ce->acs[i]; 462 if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0) 463 continue; 464 printf("Admin\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 465 NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No", 466 NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No", 467 NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No", 468 NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No", 469 NVMEV(NVME_CE_PAGE_CSE, s), 470 NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No"); 471 } 472 for (i = 0; i < 255; i++) { 473 s = ce->iocs[i]; 474 if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0) 475 continue; 476 printf("I/O\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 477 NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No", 478 NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No", 479 NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No", 480 NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No", 481 NVMEV(NVME_CE_PAGE_CSE, s), 482 NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No"); 483 } 484 } 485 486 static void 487 print_log_res_notification(const struct nvme_controller_data *cdata __unused, 488 void *buf, uint32_t size __unused) 489 { 490 struct nvme_res_notification_page *rn; 491 492 rn = (struct nvme_res_notification_page *)buf; 493 printf("Reservation Notification\n"); 494 printf("========================\n"); 495 496 printf("Log Page Count: %ju\n", rn->log_page_count); 497 printf("Log Page Type: "); 498 switch (rn->log_page_type) { 499 case 0: 500 printf("Empty Log Page\n"); 501 break; 502 case 1: 503 printf("Registration Preempted\n"); 504 break; 505 case 2: 506 printf("Reservation Released\n"); 507 break; 508 case 3: 509 printf("Reservation Preempted\n"); 510 break; 511 default: 512 printf("Unknown %x\n", rn->log_page_type); 513 break; 514 }; 515 printf("Number of Available Log Pages: %d\n", rn->available_log_pages); 516 printf("Namespace ID: 0x%x\n", rn->nsid); 517 } 518 519 static void 520 print_log_sanitize_status(const struct nvme_controller_data *cdata __unused, 521 void *buf, uint32_t size __unused) 522 { 523 struct nvme_sanitize_status_page *ss; 524 u_int p; 525 526 ss = (struct nvme_sanitize_status_page *)buf; 527 printf("Sanitize Status\n"); 528 printf("===============\n"); 529 530 printf("Sanitize Progress: %u%% (%u/65535)\n", 531 (ss->sprog * 100 + 32768) / 65536, ss->sprog); 532 printf("Sanitize Status: "); 533 switch (NVMEV(NVME_SS_PAGE_SSTAT_STATUS, ss->sstat)) { 534 case NVME_SS_PAGE_SSTAT_STATUS_NEVER: 535 printf("Never sanitized"); 536 break; 537 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED: 538 printf("Completed"); 539 break; 540 case NVME_SS_PAGE_SSTAT_STATUS_INPROG: 541 printf("In Progress"); 542 break; 543 case NVME_SS_PAGE_SSTAT_STATUS_FAILED: 544 printf("Failed"); 545 break; 546 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD: 547 printf("Completed with deallocation"); 548 break; 549 default: 550 printf("Unknown"); 551 break; 552 } 553 p = NVMEV(NVME_SS_PAGE_SSTAT_PASSES, ss->sstat); 554 if (p > 0) 555 printf(", %d passes", p); 556 if (NVMEV(NVME_SS_PAGE_SSTAT_GDE, ss->sstat) != 0) 557 printf(", Global Data Erased"); 558 printf("\n"); 559 printf("Sanitize Command Dword 10: 0x%x\n", ss->scdw10); 560 printf("Time For Overwrite: %u sec\n", ss->etfo); 561 printf("Time For Block Erase: %u sec\n", ss->etfbe); 562 printf("Time For Crypto Erase: %u sec\n", ss->etfce); 563 printf("Time For Overwrite No-Deallocate: %u sec\n", ss->etfownd); 564 printf("Time For Block Erase No-Deallocate: %u sec\n", ss->etfbewnd); 565 printf("Time For Crypto Erase No-Deallocate: %u sec\n", ss->etfcewnd); 566 } 567 568 static const char * 569 self_test_res[] = { 570 [0] = "completed without error", 571 [1] = "aborted by a Device Self-test command", 572 [2] = "aborted by a Controller Level Reset", 573 [3] = "aborted due to namespace removal", 574 [4] = "aborted due to Format NVM command", 575 [5] = "failed due to fatal or unknown test error", 576 [6] = "completed with an unknown segment that failed", 577 [7] = "completed with one or more failed segments", 578 [8] = "aborted for unknown reason", 579 [9] = "aborted due to a sanitize operation", 580 }; 581 static uint32_t self_test_res_max = nitems(self_test_res); 582 583 static void 584 print_log_self_test_status(const struct nvme_controller_data *cdata __unused, 585 void *buf, uint32_t size __unused) 586 { 587 struct nvme_device_self_test_page *dst; 588 uint32_t r; 589 590 dst = buf; 591 printf("Device Self-test Status\n"); 592 printf("=======================\n"); 593 594 printf("Current Operation: "); 595 switch (dst->curr_operation) { 596 case 0x0: 597 printf("No device self-test operation in progress\n"); 598 break; 599 case 0x1: 600 printf("Short device self-test operation in progress\n"); 601 break; 602 case 0x2: 603 printf("Extended device self-test operation in progress\n"); 604 break; 605 case 0xe: 606 printf("Vendor specific\n"); 607 break; 608 default: 609 printf("Reserved (0x%x)\n", dst->curr_operation); 610 } 611 612 if (dst->curr_operation != 0) 613 printf("Current Completion: %u%%\n", dst->curr_compl & 0x7f); 614 615 printf("Results\n"); 616 for (r = 0; r < 20; r++) { 617 uint64_t failing_lba; 618 uint8_t code, res; 619 620 code = (dst->result[r].status >> 4) & 0xf; 621 res = dst->result[r].status & 0xf; 622 623 if (res == 0xf) 624 continue; 625 626 printf("[%2u] ", r); 627 switch (code) { 628 case 0x1: 629 printf("Short device self-test"); 630 break; 631 case 0x2: 632 printf("Extended device self-test"); 633 break; 634 case 0xe: 635 printf("Vendor specific"); 636 break; 637 default: 638 printf("Reserved (0x%x)", code); 639 } 640 if (res < self_test_res_max) 641 printf(" %s", self_test_res[res]); 642 else 643 printf(" Reserved status 0x%x", res); 644 645 if (res == 7) 646 printf(" starting in segment %u", dst->result[r].segment_num); 647 648 #define BIT(b) (1 << (b)) 649 if (dst->result[r].valid_diag_info & BIT(0)) 650 printf(" NSID=0x%x", dst->result[r].nsid); 651 if (dst->result[r].valid_diag_info & BIT(1)) { 652 memcpy(&failing_lba, dst->result[r].failing_lba, 653 sizeof(failing_lba)); 654 printf(" FLBA=0x%jx", failing_lba); 655 } 656 if (dst->result[r].valid_diag_info & BIT(2)) 657 printf(" SCT=0x%x", dst->result[r].status_code_type); 658 if (dst->result[r].valid_diag_info & BIT(3)) 659 printf(" SC=0x%x", dst->result[r].status_code); 660 #undef BIT 661 printf("\n"); 662 } 663 } 664 665 /* 666 * Table of log page printer / sizing. 667 * 668 * Make sure you keep all the pages of one vendor together so -v help 669 * lists all the vendors pages. 670 */ 671 NVME_LOGPAGE(error, 672 NVME_LOG_ERROR, NULL, "Drive Error Log", 673 print_log_error, 0); 674 NVME_LOGPAGE(health, 675 NVME_LOG_HEALTH_INFORMATION, NULL, "Health/SMART Data", 676 print_log_health, sizeof(struct nvme_health_information_page)); 677 NVME_LOGPAGE(fw, 678 NVME_LOG_FIRMWARE_SLOT, NULL, "Firmware Information", 679 print_log_firmware, sizeof(struct nvme_firmware_page)); 680 NVME_LOGPAGE(ns, 681 NVME_LOG_CHANGED_NAMESPACE, NULL, "Changed Namespace List", 682 print_log_ns, sizeof(struct nvme_ns_list)); 683 NVME_LOGPAGE(ce, 684 NVME_LOG_COMMAND_EFFECT, NULL, "Commands Supported and Effects", 685 print_log_command_effects, sizeof(struct nvme_command_effects_page)); 686 NVME_LOGPAGE(dst, 687 NVME_LOG_DEVICE_SELF_TEST, NULL, "Device Self-test", 688 print_log_self_test_status, sizeof(struct nvme_device_self_test_page)); 689 NVME_LOGPAGE(thi, 690 NVME_LOG_TELEMETRY_HOST_INITIATED, NULL, "Telemetry Host-Initiated", 691 NULL, DEFAULT_SIZE); 692 NVME_LOGPAGE(tci, 693 NVME_LOG_TELEMETRY_CONTROLLER_INITIATED, NULL, "Telemetry Controller-Initiated", 694 NULL, DEFAULT_SIZE); 695 NVME_LOGPAGE(egi, 696 NVME_LOG_ENDURANCE_GROUP_INFORMATION, NULL, "Endurance Group Information", 697 NULL, DEFAULT_SIZE); 698 NVME_LOGPAGE(plpns, 699 NVME_LOG_PREDICTABLE_LATENCY_PER_NVM_SET, NULL, "Predictable Latency Per NVM Set", 700 NULL, DEFAULT_SIZE); 701 NVME_LOGPAGE(ple, 702 NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE, NULL, "Predictable Latency Event Aggregate", 703 NULL, DEFAULT_SIZE); 704 NVME_LOGPAGE(ana, 705 NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS, NULL, "Asymmetric Namespace Access", 706 NULL, DEFAULT_SIZE); 707 NVME_LOGPAGE(pel, 708 NVME_LOG_PERSISTENT_EVENT_LOG, NULL, "Persistent Event Log", 709 NULL, DEFAULT_SIZE); 710 NVME_LOGPAGE(lbasi, 711 NVME_LOG_LBA_STATUS_INFORMATION, NULL, "LBA Status Information", 712 NULL, DEFAULT_SIZE); 713 NVME_LOGPAGE(egea, 714 NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE, NULL, "Endurance Group Event Aggregate", 715 NULL, DEFAULT_SIZE); 716 NVME_LOGPAGE(res_notification, 717 NVME_LOG_RES_NOTIFICATION, NULL, "Reservation Notification", 718 print_log_res_notification, sizeof(struct nvme_res_notification_page)); 719 NVME_LOGPAGE(sanitize_status, 720 NVME_LOG_SANITIZE_STATUS, NULL, "Sanitize Status", 721 print_log_sanitize_status, sizeof(struct nvme_sanitize_status_page)); 722 723 static void 724 logpage_help(void) 725 { 726 const struct logpage_function *f; 727 const char *v; 728 729 fprintf(stderr, "\n"); 730 fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name"); 731 fprintf(stderr, "-------- ---------- ----------\n"); 732 SLIST_FOREACH(f, &logpages, link) { 733 v = f->vendor == NULL ? "-" : f->vendor; 734 fprintf(stderr, "0x%02x %-10s %s\n", f->log_page, v, f->name); 735 } 736 737 exit(EX_USAGE); 738 } 739 740 static void 741 logpage(const struct cmd *f, int argc, char *argv[]) 742 { 743 int fd; 744 char *path; 745 uint32_t nsid, size; 746 void *buf; 747 const struct logpage_function *lpf; 748 struct nvme_controller_data cdata; 749 print_fn_t print_fn; 750 uint8_t ns_smart; 751 752 if (arg_parse(argc, argv, f)) 753 return; 754 if (opt.hex && opt.binary) { 755 fprintf(stderr, 756 "Can't specify both binary and hex\n"); 757 arg_help(argc, argv, f); 758 } 759 if (opt.vendor != NULL && strcmp(opt.vendor, "help") == 0) 760 logpage_help(); 761 if (opt.page == NONE) { 762 fprintf(stderr, "Missing page_id (-p).\n"); 763 arg_help(argc, argv, f); 764 } 765 open_dev(opt.dev, &fd, 0, 1); 766 get_nsid(fd, &path, &nsid); 767 if (nsid == 0) { 768 nsid = NVME_GLOBAL_NAMESPACE_TAG; 769 } else { 770 close(fd); 771 open_dev(path, &fd, 0, 1); 772 } 773 free(path); 774 775 if (read_controller_data(fd, &cdata)) 776 errx(EX_IOERR, "Identify request failed"); 777 778 ns_smart = NVMEV(NVME_CTRLR_DATA_LPA_NS_SMART, cdata.lpa); 779 780 /* 781 * The log page attributes indicate whether or not the controller 782 * supports the SMART/Health information log page on a per 783 * namespace basis. 784 */ 785 if (nsid != NVME_GLOBAL_NAMESPACE_TAG) { 786 if (opt.page != NVME_LOG_HEALTH_INFORMATION) 787 errx(EX_USAGE, "log page %d valid only at controller level", 788 opt.page); 789 if (ns_smart == 0) 790 errx(EX_UNAVAILABLE, 791 "controller does not support per namespace " 792 "smart/health information"); 793 } 794 795 print_fn = print_log_hex; 796 size = DEFAULT_SIZE; 797 if (opt.binary) 798 print_fn = print_bin; 799 if (!opt.binary && !opt.hex) { 800 /* 801 * See if there is a pretty print function for the specified log 802 * page. If one isn't found, we just revert to the default 803 * (print_hex). If there was a vendor specified by the user, and 804 * the page is vendor specific, don't match the print function 805 * unless the vendors match. 806 */ 807 SLIST_FOREACH(lpf, &logpages, link) { 808 if (lpf->vendor != NULL && opt.vendor != NULL && 809 strcmp(lpf->vendor, opt.vendor) != 0) 810 continue; 811 if (opt.page != lpf->log_page) 812 continue; 813 if (lpf->print_fn != NULL) 814 print_fn = lpf->print_fn; 815 size = lpf->size; 816 break; 817 } 818 } 819 820 if (opt.page == NVME_LOG_ERROR) { 821 size = sizeof(struct nvme_error_information_entry); 822 size *= (cdata.elpe + 1); 823 } 824 825 /* Read the log page */ 826 buf = get_log_buffer(size); 827 read_logpage(fd, opt.page, nsid, opt.lsp, opt.lsi, opt.rae, buf, size); 828 print_fn(&cdata, buf, size); 829 830 close(fd); 831 exit(0); 832 } 833