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_FIRMWARE_SLOT: 233 nvme_firmware_page_swapbytes( 234 (struct nvme_firmware_page *)payload); 235 break; 236 case NVME_LOG_CHANGED_NAMESPACE: 237 nvme_ns_list_swapbytes((struct nvme_ns_list *)payload); 238 break; 239 case NVME_LOG_DEVICE_SELF_TEST: 240 nvme_device_self_test_swapbytes( 241 (struct nvme_device_self_test_page *)payload); 242 break; 243 case NVME_LOG_COMMAND_EFFECT: 244 nvme_command_effects_page_swapbytes( 245 (struct nvme_command_effects_page *)payload); 246 break; 247 case NVME_LOG_RES_NOTIFICATION: 248 nvme_res_notification_page_swapbytes( 249 (struct nvme_res_notification_page *)payload); 250 break; 251 case NVME_LOG_SANITIZE_STATUS: 252 nvme_sanitize_status_page_swapbytes( 253 (struct nvme_sanitize_status_page *)payload); 254 break; 255 case INTEL_LOG_TEMP_STATS: 256 intel_log_temp_stats_swapbytes( 257 (struct intel_log_temp_stats *)payload); 258 break; 259 default: 260 break; 261 } 262 263 if (nvme_completion_is_error(&pt.cpl)) 264 errx(EX_IOERR, "get log page request returned error"); 265 } 266 267 static void 268 print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size) 269 { 270 int i, nentries; 271 uint16_t status; 272 uint8_t p, sc, sct, m, dnr; 273 struct nvme_error_information_entry *entry = buf; 274 275 printf("Error Information Log\n"); 276 printf("=====================\n"); 277 278 if (entry->error_count == 0) { 279 printf("No error entries found\n"); 280 return; 281 } 282 283 nentries = size/sizeof(struct nvme_error_information_entry); 284 for (i = 0; i < nentries; i++, entry++) { 285 if (entry->error_count == 0) 286 break; 287 288 status = entry->status; 289 290 p = NVME_STATUS_GET_P(status); 291 sc = NVME_STATUS_GET_SC(status); 292 sct = NVME_STATUS_GET_SCT(status); 293 m = NVME_STATUS_GET_M(status); 294 dnr = NVME_STATUS_GET_DNR(status); 295 296 printf("Entry %02d\n", i + 1); 297 printf("=========\n"); 298 printf(" Error count: %ju\n", entry->error_count); 299 printf(" Submission queue ID: %u\n", entry->sqid); 300 printf(" Command ID: %u\n", entry->cid); 301 /* TODO: Export nvme_status_string structures from kernel? */ 302 printf(" Status:\n"); 303 printf(" Phase tag: %d\n", p); 304 printf(" Status code: %d\n", sc); 305 printf(" Status code type: %d\n", sct); 306 printf(" More: %d\n", m); 307 printf(" DNR: %d\n", dnr); 308 printf(" Error location: %u\n", entry->error_location); 309 printf(" LBA: %ju\n", entry->lba); 310 printf(" Namespace ID: %u\n", entry->nsid); 311 printf(" Vendor specific info: %u\n", entry->vendor_specific); 312 printf(" Transport type: %u\n", entry->trtype); 313 printf(" Command specific info:%ju\n", entry->csi); 314 printf(" Transport specific: %u\n", entry->ttsi); 315 } 316 } 317 318 void 319 print_temp_K(uint16_t t) 320 { 321 printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, (float)t * 9 / 5 - 459.67); 322 } 323 324 void 325 print_temp_C(uint16_t t) 326 { 327 printf("%2.2f K, %u C, %3.2f F\n", (float)t + 273.15, t, (float)t * 9 / 5 + 32); 328 } 329 330 static void 331 print_log_health(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused) 332 { 333 struct nvme_health_information_page *health = buf; 334 char cbuf[UINT128_DIG + 1]; 335 uint8_t warning; 336 int i; 337 338 warning = health->critical_warning; 339 340 printf("SMART/Health Information Log\n"); 341 printf("============================\n"); 342 343 printf("Critical Warning State: 0x%02x\n", warning); 344 printf(" Available spare: %d\n", 345 !!(warning & NVME_CRIT_WARN_ST_AVAILABLE_SPARE)); 346 printf(" Temperature: %d\n", 347 !!(warning & NVME_CRIT_WARN_ST_TEMPERATURE)); 348 printf(" Device reliability: %d\n", 349 !!(warning & NVME_CRIT_WARN_ST_DEVICE_RELIABILITY)); 350 printf(" Read only: %d\n", 351 !!(warning & NVME_CRIT_WARN_ST_READ_ONLY)); 352 printf(" Volatile memory backup: %d\n", 353 !!(warning & NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP)); 354 printf("Temperature: "); 355 print_temp_K(health->temperature); 356 printf("Available spare: %u\n", 357 health->available_spare); 358 printf("Available spare threshold: %u\n", 359 health->available_spare_threshold); 360 printf("Percentage used: %u\n", 361 health->percentage_used); 362 363 printf("Data units (512,000 byte) read: %s\n", 364 uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf))); 365 printf("Data units written: %s\n", 366 uint128_to_str(to128(health->data_units_written), cbuf, sizeof(cbuf))); 367 printf("Host read commands: %s\n", 368 uint128_to_str(to128(health->host_read_commands), cbuf, sizeof(cbuf))); 369 printf("Host write commands: %s\n", 370 uint128_to_str(to128(health->host_write_commands), cbuf, sizeof(cbuf))); 371 printf("Controller busy time (minutes): %s\n", 372 uint128_to_str(to128(health->controller_busy_time), cbuf, sizeof(cbuf))); 373 printf("Power cycles: %s\n", 374 uint128_to_str(to128(health->power_cycles), cbuf, sizeof(cbuf))); 375 printf("Power on hours: %s\n", 376 uint128_to_str(to128(health->power_on_hours), cbuf, sizeof(cbuf))); 377 printf("Unsafe shutdowns: %s\n", 378 uint128_to_str(to128(health->unsafe_shutdowns), cbuf, sizeof(cbuf))); 379 printf("Media errors: %s\n", 380 uint128_to_str(to128(health->media_errors), cbuf, sizeof(cbuf))); 381 printf("No. error info log entries: %s\n", 382 uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf))); 383 384 printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); 385 printf("Error Temp Composite Time: %d\n", health->error_temp_time); 386 for (i = 0; i < 8; i++) { 387 if (health->temp_sensor[i] == 0) 388 continue; 389 printf("Temperature Sensor %d: ", i + 1); 390 print_temp_K(health->temp_sensor[i]); 391 } 392 printf("Temperature 1 Transition Count: %d\n", health->tmt1tc); 393 printf("Temperature 2 Transition Count: %d\n", health->tmt2tc); 394 printf("Total Time For Temperature 1: %d\n", health->ttftmt1); 395 printf("Total Time For Temperature 2: %d\n", health->ttftmt2); 396 } 397 398 static void 399 print_log_firmware(const struct nvme_controller_data *cdata, void *buf, uint32_t size __unused) 400 { 401 int i, slots; 402 const char *status; 403 struct nvme_firmware_page *fw = buf; 404 uint8_t afi_slot; 405 uint16_t oacs_fw; 406 uint8_t fw_num_slots; 407 408 afi_slot = NVMEV(NVME_FIRMWARE_PAGE_AFI_SLOT, fw->afi); 409 410 oacs_fw = NVMEV(NVME_CTRLR_DATA_OACS_FIRMWARE, cdata->oacs); 411 fw_num_slots = NVMEV(NVME_CTRLR_DATA_FRMW_NUM_SLOTS, cdata->frmw); 412 413 printf("Firmware Slot Log\n"); 414 printf("=================\n"); 415 416 if (oacs_fw == 0) 417 slots = 1; 418 else 419 slots = MIN(fw_num_slots, MAX_FW_SLOTS); 420 421 for (i = 0; i < slots; i++) { 422 printf("Slot %d: ", i + 1); 423 if (afi_slot == i + 1) 424 status = " Active"; 425 else 426 status = "Inactive"; 427 428 if (fw->revision[i] == 0LLU) 429 printf("Empty\n"); 430 else 431 if (isprint(*(char *)&fw->revision[i])) 432 printf("[%s] %.8s\n", status, 433 (char *)&fw->revision[i]); 434 else 435 printf("[%s] %016jx\n", status, 436 fw->revision[i]); 437 } 438 } 439 440 static void 441 print_log_ns(const struct nvme_controller_data *cdata __unused, void *buf, 442 uint32_t size __unused) 443 { 444 struct nvme_ns_list *nsl; 445 u_int i; 446 447 nsl = (struct nvme_ns_list *)buf; 448 printf("Changed Namespace List\n"); 449 printf("======================\n"); 450 451 for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) { 452 printf("%08x\n", nsl->ns[i]); 453 } 454 } 455 456 static void 457 print_log_command_effects(const struct nvme_controller_data *cdata __unused, 458 void *buf, uint32_t size __unused) 459 { 460 struct nvme_command_effects_page *ce; 461 u_int i; 462 uint32_t s; 463 464 ce = (struct nvme_command_effects_page *)buf; 465 printf("Commands Supported and Effects\n"); 466 printf("==============================\n"); 467 printf(" Command\tLBCC\tNCC\tNIC\tCCC\tCSE\tUUID\n"); 468 469 for (i = 0; i < 255; i++) { 470 s = ce->acs[i]; 471 if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0) 472 continue; 473 printf("Admin\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 474 NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No", 475 NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No", 476 NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No", 477 NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No", 478 NVMEV(NVME_CE_PAGE_CSE, s), 479 NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No"); 480 } 481 for (i = 0; i < 255; i++) { 482 s = ce->iocs[i]; 483 if (NVMEV(NVME_CE_PAGE_CSUP, s) == 0) 484 continue; 485 printf("I/O\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 486 NVMEV(NVME_CE_PAGE_LBCC, s) != 0 ? "Yes" : "No", 487 NVMEV(NVME_CE_PAGE_NCC, s) != 0 ? "Yes" : "No", 488 NVMEV(NVME_CE_PAGE_NIC, s) != 0 ? "Yes" : "No", 489 NVMEV(NVME_CE_PAGE_CCC, s) != 0 ? "Yes" : "No", 490 NVMEV(NVME_CE_PAGE_CSE, s), 491 NVMEV(NVME_CE_PAGE_UUID, s) != 0 ? "Yes" : "No"); 492 } 493 } 494 495 static void 496 print_log_res_notification(const struct nvme_controller_data *cdata __unused, 497 void *buf, uint32_t size __unused) 498 { 499 struct nvme_res_notification_page *rn; 500 501 rn = (struct nvme_res_notification_page *)buf; 502 printf("Reservation Notification\n"); 503 printf("========================\n"); 504 505 printf("Log Page Count: %ju\n", rn->log_page_count); 506 printf("Log Page Type: "); 507 switch (rn->log_page_type) { 508 case 0: 509 printf("Empty Log Page\n"); 510 break; 511 case 1: 512 printf("Registration Preempted\n"); 513 break; 514 case 2: 515 printf("Reservation Released\n"); 516 break; 517 case 3: 518 printf("Reservation Preempted\n"); 519 break; 520 default: 521 printf("Unknown %x\n", rn->log_page_type); 522 break; 523 }; 524 printf("Number of Available Log Pages: %d\n", rn->available_log_pages); 525 printf("Namespace ID: 0x%x\n", rn->nsid); 526 } 527 528 static void 529 print_log_sanitize_status(const struct nvme_controller_data *cdata __unused, 530 void *buf, uint32_t size __unused) 531 { 532 struct nvme_sanitize_status_page *ss; 533 u_int p; 534 535 ss = (struct nvme_sanitize_status_page *)buf; 536 printf("Sanitize Status\n"); 537 printf("===============\n"); 538 539 printf("Sanitize Progress: %u%% (%u/65535)\n", 540 (ss->sprog * 100 + 32768) / 65536, ss->sprog); 541 printf("Sanitize Status: "); 542 switch (NVMEV(NVME_SS_PAGE_SSTAT_STATUS, ss->sstat)) { 543 case NVME_SS_PAGE_SSTAT_STATUS_NEVER: 544 printf("Never sanitized"); 545 break; 546 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED: 547 printf("Completed"); 548 break; 549 case NVME_SS_PAGE_SSTAT_STATUS_INPROG: 550 printf("In Progress"); 551 break; 552 case NVME_SS_PAGE_SSTAT_STATUS_FAILED: 553 printf("Failed"); 554 break; 555 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD: 556 printf("Completed with deallocation"); 557 break; 558 default: 559 printf("Unknown"); 560 break; 561 } 562 p = NVMEV(NVME_SS_PAGE_SSTAT_PASSES, ss->sstat); 563 if (p > 0) 564 printf(", %d passes", p); 565 if (NVMEV(NVME_SS_PAGE_SSTAT_GDE, ss->sstat) != 0) 566 printf(", Global Data Erased"); 567 printf("\n"); 568 printf("Sanitize Command Dword 10: 0x%x\n", ss->scdw10); 569 printf("Time For Overwrite: %u sec\n", ss->etfo); 570 printf("Time For Block Erase: %u sec\n", ss->etfbe); 571 printf("Time For Crypto Erase: %u sec\n", ss->etfce); 572 printf("Time For Overwrite No-Deallocate: %u sec\n", ss->etfownd); 573 printf("Time For Block Erase No-Deallocate: %u sec\n", ss->etfbewnd); 574 printf("Time For Crypto Erase No-Deallocate: %u sec\n", ss->etfcewnd); 575 } 576 577 static const char * 578 self_test_res[] = { 579 [0] = "completed without error", 580 [1] = "aborted by a Device Self-test command", 581 [2] = "aborted by a Controller Level Reset", 582 [3] = "aborted due to namespace removal", 583 [4] = "aborted due to Format NVM command", 584 [5] = "failed due to fatal or unknown test error", 585 [6] = "completed with an unknown segment that failed", 586 [7] = "completed with one or more failed segments", 587 [8] = "aborted for unknown reason", 588 [9] = "aborted due to a sanitize operation", 589 }; 590 static uint32_t self_test_res_max = nitems(self_test_res); 591 592 static void 593 print_log_self_test_status(const struct nvme_controller_data *cdata __unused, 594 void *buf, uint32_t size __unused) 595 { 596 struct nvme_device_self_test_page *dst; 597 uint32_t r; 598 599 dst = buf; 600 printf("Device Self-test Status\n"); 601 printf("=======================\n"); 602 603 printf("Current Operation: "); 604 switch (dst->curr_operation) { 605 case 0x0: 606 printf("No device self-test operation in progress\n"); 607 break; 608 case 0x1: 609 printf("Short device self-test operation in progress\n"); 610 break; 611 case 0x2: 612 printf("Extended device self-test operation in progress\n"); 613 break; 614 case 0xe: 615 printf("Vendor specific\n"); 616 break; 617 default: 618 printf("Reserved (0x%x)\n", dst->curr_operation); 619 } 620 621 if (dst->curr_operation != 0) 622 printf("Current Completion: %u%%\n", dst->curr_compl & 0x7f); 623 624 printf("Results\n"); 625 for (r = 0; r < 20; r++) { 626 uint64_t failing_lba; 627 uint8_t code, res; 628 629 code = (dst->result[r].status >> 4) & 0xf; 630 res = dst->result[r].status & 0xf; 631 632 if (res == 0xf) 633 continue; 634 635 printf("[%2u] ", r); 636 switch (code) { 637 case 0x1: 638 printf("Short device self-test"); 639 break; 640 case 0x2: 641 printf("Extended device self-test"); 642 break; 643 case 0xe: 644 printf("Vendor specific"); 645 break; 646 default: 647 printf("Reserved (0x%x)", code); 648 } 649 if (res < self_test_res_max) 650 printf(" %s", self_test_res[res]); 651 else 652 printf(" Reserved status 0x%x", res); 653 654 if (res == 7) 655 printf(" starting in segment %u", dst->result[r].segment_num); 656 657 #define BIT(b) (1 << (b)) 658 if (dst->result[r].valid_diag_info & BIT(0)) 659 printf(" NSID=0x%x", dst->result[r].nsid); 660 if (dst->result[r].valid_diag_info & BIT(1)) { 661 memcpy(&failing_lba, dst->result[r].failing_lba, 662 sizeof(failing_lba)); 663 printf(" FLBA=0x%jx", failing_lba); 664 } 665 if (dst->result[r].valid_diag_info & BIT(2)) 666 printf(" SCT=0x%x", dst->result[r].status_code_type); 667 if (dst->result[r].valid_diag_info & BIT(3)) 668 printf(" SC=0x%x", dst->result[r].status_code); 669 #undef BIT 670 printf("\n"); 671 } 672 } 673 674 /* 675 * Table of log page printer / sizing. 676 * 677 * Make sure you keep all the pages of one vendor together so -v help 678 * lists all the vendors pages. 679 */ 680 NVME_LOGPAGE(error, 681 NVME_LOG_ERROR, NULL, "Drive Error Log", 682 print_log_error, 0); 683 NVME_LOGPAGE(health, 684 NVME_LOG_HEALTH_INFORMATION, NULL, "Health/SMART Data", 685 print_log_health, sizeof(struct nvme_health_information_page)); 686 NVME_LOGPAGE(fw, 687 NVME_LOG_FIRMWARE_SLOT, NULL, "Firmware Information", 688 print_log_firmware, sizeof(struct nvme_firmware_page)); 689 NVME_LOGPAGE(ns, 690 NVME_LOG_CHANGED_NAMESPACE, NULL, "Changed Namespace List", 691 print_log_ns, sizeof(struct nvme_ns_list)); 692 NVME_LOGPAGE(ce, 693 NVME_LOG_COMMAND_EFFECT, NULL, "Commands Supported and Effects", 694 print_log_command_effects, sizeof(struct nvme_command_effects_page)); 695 NVME_LOGPAGE(dst, 696 NVME_LOG_DEVICE_SELF_TEST, NULL, "Device Self-test", 697 print_log_self_test_status, sizeof(struct nvme_device_self_test_page)); 698 NVME_LOGPAGE(thi, 699 NVME_LOG_TELEMETRY_HOST_INITIATED, NULL, "Telemetry Host-Initiated", 700 NULL, DEFAULT_SIZE); 701 NVME_LOGPAGE(tci, 702 NVME_LOG_TELEMETRY_CONTROLLER_INITIATED, NULL, "Telemetry Controller-Initiated", 703 NULL, DEFAULT_SIZE); 704 NVME_LOGPAGE(egi, 705 NVME_LOG_ENDURANCE_GROUP_INFORMATION, NULL, "Endurance Group Information", 706 NULL, DEFAULT_SIZE); 707 NVME_LOGPAGE(plpns, 708 NVME_LOG_PREDICTABLE_LATENCY_PER_NVM_SET, NULL, "Predictable Latency Per NVM Set", 709 NULL, DEFAULT_SIZE); 710 NVME_LOGPAGE(ple, 711 NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE, NULL, "Predictable Latency Event Aggregate", 712 NULL, DEFAULT_SIZE); 713 NVME_LOGPAGE(ana, 714 NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS, NULL, "Asymmetric Namespace Access", 715 NULL, DEFAULT_SIZE); 716 NVME_LOGPAGE(pel, 717 NVME_LOG_PERSISTENT_EVENT_LOG, NULL, "Persistent Event Log", 718 NULL, DEFAULT_SIZE); 719 NVME_LOGPAGE(lbasi, 720 NVME_LOG_LBA_STATUS_INFORMATION, NULL, "LBA Status Information", 721 NULL, DEFAULT_SIZE); 722 NVME_LOGPAGE(egea, 723 NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE, NULL, "Endurance Group Event Aggregate", 724 NULL, DEFAULT_SIZE); 725 NVME_LOGPAGE(res_notification, 726 NVME_LOG_RES_NOTIFICATION, NULL, "Reservation Notification", 727 print_log_res_notification, sizeof(struct nvme_res_notification_page)); 728 NVME_LOGPAGE(sanitize_status, 729 NVME_LOG_SANITIZE_STATUS, NULL, "Sanitize Status", 730 print_log_sanitize_status, sizeof(struct nvme_sanitize_status_page)); 731 732 static void 733 logpage_help(void) 734 { 735 const struct logpage_function *f; 736 const char *v; 737 738 fprintf(stderr, "\n"); 739 fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name"); 740 fprintf(stderr, "-------- ---------- ----------\n"); 741 SLIST_FOREACH(f, &logpages, link) { 742 v = f->vendor == NULL ? "-" : f->vendor; 743 fprintf(stderr, "0x%02x %-10s %s\n", f->log_page, v, f->name); 744 } 745 746 exit(EX_USAGE); 747 } 748 749 static void 750 logpage(const struct cmd *f, int argc, char *argv[]) 751 { 752 int fd; 753 char *path; 754 uint32_t nsid, size; 755 void *buf; 756 const struct logpage_function *lpf; 757 struct nvme_controller_data cdata; 758 print_fn_t print_fn; 759 uint8_t ns_smart; 760 761 if (arg_parse(argc, argv, f)) 762 return; 763 if (opt.hex && opt.binary) { 764 fprintf(stderr, 765 "Can't specify both binary and hex\n"); 766 arg_help(argc, argv, f); 767 } 768 if (opt.vendor != NULL && strcmp(opt.vendor, "help") == 0) 769 logpage_help(); 770 if (opt.page == NONE) { 771 fprintf(stderr, "Missing page_id (-p).\n"); 772 arg_help(argc, argv, f); 773 } 774 open_dev(opt.dev, &fd, 0, 1); 775 get_nsid(fd, &path, &nsid); 776 if (nsid == 0) { 777 nsid = NVME_GLOBAL_NAMESPACE_TAG; 778 } else { 779 close(fd); 780 open_dev(path, &fd, 0, 1); 781 } 782 free(path); 783 784 if (read_controller_data(fd, &cdata)) 785 errx(EX_IOERR, "Identify request failed"); 786 787 ns_smart = NVMEV(NVME_CTRLR_DATA_LPA_NS_SMART, cdata.lpa); 788 789 /* 790 * The log page attributes indicate whether or not the controller 791 * supports the SMART/Health information log page on a per 792 * namespace basis. 793 */ 794 if (nsid != NVME_GLOBAL_NAMESPACE_TAG) { 795 if (opt.page != NVME_LOG_HEALTH_INFORMATION) 796 errx(EX_USAGE, "log page %d valid only at controller level", 797 opt.page); 798 if (ns_smart == 0) 799 errx(EX_UNAVAILABLE, 800 "controller does not support per namespace " 801 "smart/health information"); 802 } 803 804 print_fn = print_log_hex; 805 size = DEFAULT_SIZE; 806 if (opt.binary) 807 print_fn = print_bin; 808 if (!opt.binary && !opt.hex) { 809 /* 810 * See if there is a pretty print function for the specified log 811 * page. If one isn't found, we just revert to the default 812 * (print_hex). If there was a vendor specified by the user, and 813 * the page is vendor specific, don't match the print function 814 * unless the vendors match. 815 */ 816 SLIST_FOREACH(lpf, &logpages, link) { 817 if (lpf->vendor != NULL && opt.vendor != NULL && 818 strcmp(lpf->vendor, opt.vendor) != 0) 819 continue; 820 if (opt.page != lpf->log_page) 821 continue; 822 if (lpf->print_fn != NULL) 823 print_fn = lpf->print_fn; 824 size = lpf->size; 825 break; 826 } 827 } 828 829 if (opt.page == NVME_LOG_ERROR) { 830 size = sizeof(struct nvme_error_information_entry); 831 size *= (cdata.elpe + 1); 832 } 833 834 /* Read the log page */ 835 buf = get_log_buffer(size); 836 read_logpage(fd, opt.page, nsid, opt.lsp, opt.lsi, opt.rae, buf, size); 837 print_fn(&cdata, buf, size); 838 839 close(fd); 840 exit(0); 841 } 842