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 = fw->afi >> NVME_FIRMWARE_PAGE_AFI_SLOT_SHIFT; 409 afi_slot &= NVME_FIRMWARE_PAGE_AFI_SLOT_MASK; 410 411 oacs_fw = (cdata->oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) & 412 NVME_CTRLR_DATA_OACS_FIRMWARE_MASK; 413 fw_num_slots = (cdata->frmw >> NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT) & 414 NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK; 415 416 printf("Firmware Slot Log\n"); 417 printf("=================\n"); 418 419 if (oacs_fw == 0) 420 slots = 1; 421 else 422 slots = MIN(fw_num_slots, MAX_FW_SLOTS); 423 424 for (i = 0; i < slots; i++) { 425 printf("Slot %d: ", i + 1); 426 if (afi_slot == i + 1) 427 status = " Active"; 428 else 429 status = "Inactive"; 430 431 if (fw->revision[i] == 0LLU) 432 printf("Empty\n"); 433 else 434 if (isprint(*(char *)&fw->revision[i])) 435 printf("[%s] %.8s\n", status, 436 (char *)&fw->revision[i]); 437 else 438 printf("[%s] %016jx\n", status, 439 fw->revision[i]); 440 } 441 } 442 443 static void 444 print_log_ns(const struct nvme_controller_data *cdata __unused, void *buf, 445 uint32_t size __unused) 446 { 447 struct nvme_ns_list *nsl; 448 u_int i; 449 450 nsl = (struct nvme_ns_list *)buf; 451 printf("Changed Namespace List\n"); 452 printf("======================\n"); 453 454 for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) { 455 printf("%08x\n", nsl->ns[i]); 456 } 457 } 458 459 static void 460 print_log_command_effects(const struct nvme_controller_data *cdata __unused, 461 void *buf, uint32_t size __unused) 462 { 463 struct nvme_command_effects_page *ce; 464 u_int i; 465 uint32_t s; 466 467 ce = (struct nvme_command_effects_page *)buf; 468 printf("Commands Supported and Effects\n"); 469 printf("==============================\n"); 470 printf(" Command\tLBCC\tNCC\tNIC\tCCC\tCSE\tUUID\n"); 471 472 for (i = 0; i < 255; i++) { 473 s = ce->acs[i]; 474 if (((s >> NVME_CE_PAGE_CSUP_SHIFT) & 475 NVME_CE_PAGE_CSUP_MASK) == 0) 476 continue; 477 printf("Admin\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 478 ((s >> NVME_CE_PAGE_LBCC_SHIFT) & 479 NVME_CE_PAGE_LBCC_MASK) ? "Yes" : "No", 480 ((s >> NVME_CE_PAGE_NCC_SHIFT) & 481 NVME_CE_PAGE_NCC_MASK) ? "Yes" : "No", 482 ((s >> NVME_CE_PAGE_NIC_SHIFT) & 483 NVME_CE_PAGE_NIC_MASK) ? "Yes" : "No", 484 ((s >> NVME_CE_PAGE_CCC_SHIFT) & 485 NVME_CE_PAGE_CCC_MASK) ? "Yes" : "No", 486 ((s >> NVME_CE_PAGE_CSE_SHIFT) & 487 NVME_CE_PAGE_CSE_MASK), 488 ((s >> NVME_CE_PAGE_UUID_SHIFT) & 489 NVME_CE_PAGE_UUID_MASK) ? "Yes" : "No"); 490 } 491 for (i = 0; i < 255; i++) { 492 s = ce->iocs[i]; 493 if (((s >> NVME_CE_PAGE_CSUP_SHIFT) & 494 NVME_CE_PAGE_CSUP_MASK) == 0) 495 continue; 496 printf("I/O\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 497 ((s >> NVME_CE_PAGE_LBCC_SHIFT) & 498 NVME_CE_PAGE_LBCC_MASK) ? "Yes" : "No", 499 ((s >> NVME_CE_PAGE_NCC_SHIFT) & 500 NVME_CE_PAGE_NCC_MASK) ? "Yes" : "No", 501 ((s >> NVME_CE_PAGE_NIC_SHIFT) & 502 NVME_CE_PAGE_NIC_MASK) ? "Yes" : "No", 503 ((s >> NVME_CE_PAGE_CCC_SHIFT) & 504 NVME_CE_PAGE_CCC_MASK) ? "Yes" : "No", 505 ((s >> NVME_CE_PAGE_CSE_SHIFT) & 506 NVME_CE_PAGE_CSE_MASK), 507 ((s >> NVME_CE_PAGE_UUID_SHIFT) & 508 NVME_CE_PAGE_UUID_MASK) ? "Yes" : "No"); 509 } 510 } 511 512 static void 513 print_log_res_notification(const struct nvme_controller_data *cdata __unused, 514 void *buf, uint32_t size __unused) 515 { 516 struct nvme_res_notification_page *rn; 517 518 rn = (struct nvme_res_notification_page *)buf; 519 printf("Reservation Notification\n"); 520 printf("========================\n"); 521 522 printf("Log Page Count: %ju\n", rn->log_page_count); 523 printf("Log Page Type: "); 524 switch (rn->log_page_type) { 525 case 0: 526 printf("Empty Log Page\n"); 527 break; 528 case 1: 529 printf("Registration Preempted\n"); 530 break; 531 case 2: 532 printf("Reservation Released\n"); 533 break; 534 case 3: 535 printf("Reservation Preempted\n"); 536 break; 537 default: 538 printf("Unknown %x\n", rn->log_page_type); 539 break; 540 }; 541 printf("Number of Available Log Pages: %d\n", rn->available_log_pages); 542 printf("Namespace ID: 0x%x\n", rn->nsid); 543 } 544 545 static void 546 print_log_sanitize_status(const struct nvme_controller_data *cdata __unused, 547 void *buf, uint32_t size __unused) 548 { 549 struct nvme_sanitize_status_page *ss; 550 u_int p; 551 552 ss = (struct nvme_sanitize_status_page *)buf; 553 printf("Sanitize Status\n"); 554 printf("===============\n"); 555 556 printf("Sanitize Progress: %u%% (%u/65535)\n", 557 (ss->sprog * 100 + 32768) / 65536, ss->sprog); 558 printf("Sanitize Status: "); 559 switch ((ss->sstat >> NVME_SS_PAGE_SSTAT_STATUS_SHIFT) & 560 NVME_SS_PAGE_SSTAT_STATUS_MASK) { 561 case NVME_SS_PAGE_SSTAT_STATUS_NEVER: 562 printf("Never sanitized"); 563 break; 564 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED: 565 printf("Completed"); 566 break; 567 case NVME_SS_PAGE_SSTAT_STATUS_INPROG: 568 printf("In Progress"); 569 break; 570 case NVME_SS_PAGE_SSTAT_STATUS_FAILED: 571 printf("Failed"); 572 break; 573 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD: 574 printf("Completed with deallocation"); 575 break; 576 default: 577 printf("Unknown"); 578 break; 579 } 580 p = (ss->sstat >> NVME_SS_PAGE_SSTAT_PASSES_SHIFT) & 581 NVME_SS_PAGE_SSTAT_PASSES_MASK; 582 if (p > 0) 583 printf(", %d passes", p); 584 if ((ss->sstat >> NVME_SS_PAGE_SSTAT_GDE_SHIFT) & 585 NVME_SS_PAGE_SSTAT_GDE_MASK) 586 printf(", Global Data Erased"); 587 printf("\n"); 588 printf("Sanitize Command Dword 10: 0x%x\n", ss->scdw10); 589 printf("Time For Overwrite: %u sec\n", ss->etfo); 590 printf("Time For Block Erase: %u sec\n", ss->etfbe); 591 printf("Time For Crypto Erase: %u sec\n", ss->etfce); 592 printf("Time For Overwrite No-Deallocate: %u sec\n", ss->etfownd); 593 printf("Time For Block Erase No-Deallocate: %u sec\n", ss->etfbewnd); 594 printf("Time For Crypto Erase No-Deallocate: %u sec\n", ss->etfcewnd); 595 } 596 597 static const char * 598 self_test_res[] = { 599 [0] = "completed without error", 600 [1] = "aborted by a Device Self-test command", 601 [2] = "aborted by a Controller Level Reset", 602 [3] = "aborted due to namespace removal", 603 [4] = "aborted due to Format NVM command", 604 [5] = "failed due to fatal or unknown test error", 605 [6] = "completed with an unknown segment that failed", 606 [7] = "completed with one or more failed segments", 607 [8] = "aborted for unknown reason", 608 [9] = "aborted due to a sanitize operation", 609 }; 610 static uint32_t self_test_res_max = nitems(self_test_res); 611 612 static void 613 print_log_self_test_status(const struct nvme_controller_data *cdata __unused, 614 void *buf, uint32_t size __unused) 615 { 616 struct nvme_device_self_test_page *dst; 617 uint32_t r; 618 619 dst = buf; 620 printf("Device Self-test Status\n"); 621 printf("=======================\n"); 622 623 printf("Current Operation: "); 624 switch (dst->curr_operation) { 625 case 0x0: 626 printf("No device self-test operation in progress\n"); 627 break; 628 case 0x1: 629 printf("Short device self-test operation in progress\n"); 630 break; 631 case 0x2: 632 printf("Extended device self-test operation in progress\n"); 633 break; 634 case 0xe: 635 printf("Vendor specific\n"); 636 break; 637 default: 638 printf("Reserved (0x%x)\n", dst->curr_operation); 639 } 640 641 if (dst->curr_operation != 0) 642 printf("Current Completion: %u%%\n", dst->curr_compl & 0x7f); 643 644 printf("Results\n"); 645 for (r = 0; r < 20; r++) { 646 uint64_t failing_lba; 647 uint8_t code, res; 648 649 code = (dst->result[r].status >> 4) & 0xf; 650 res = dst->result[r].status & 0xf; 651 652 if (res == 0xf) 653 continue; 654 655 printf("[%2u] ", r); 656 switch (code) { 657 case 0x1: 658 printf("Short device self-test"); 659 break; 660 case 0x2: 661 printf("Extended device self-test"); 662 break; 663 case 0xe: 664 printf("Vendor specific"); 665 break; 666 default: 667 printf("Reserved (0x%x)", code); 668 } 669 if (res < self_test_res_max) 670 printf(" %s", self_test_res[res]); 671 else 672 printf(" Reserved status 0x%x", res); 673 674 if (res == 7) 675 printf(" starting in segment %u", dst->result[r].segment_num); 676 677 #define BIT(b) (1 << (b)) 678 if (dst->result[r].valid_diag_info & BIT(0)) 679 printf(" NSID=0x%x", dst->result[r].nsid); 680 if (dst->result[r].valid_diag_info & BIT(1)) { 681 memcpy(&failing_lba, dst->result[r].failing_lba, 682 sizeof(failing_lba)); 683 printf(" FLBA=0x%jx", failing_lba); 684 } 685 if (dst->result[r].valid_diag_info & BIT(2)) 686 printf(" SCT=0x%x", dst->result[r].status_code_type); 687 if (dst->result[r].valid_diag_info & BIT(3)) 688 printf(" SC=0x%x", dst->result[r].status_code); 689 #undef BIT 690 printf("\n"); 691 } 692 } 693 694 /* 695 * Table of log page printer / sizing. 696 * 697 * Make sure you keep all the pages of one vendor together so -v help 698 * lists all the vendors pages. 699 */ 700 NVME_LOGPAGE(error, 701 NVME_LOG_ERROR, NULL, "Drive Error Log", 702 print_log_error, 0); 703 NVME_LOGPAGE(health, 704 NVME_LOG_HEALTH_INFORMATION, NULL, "Health/SMART Data", 705 print_log_health, sizeof(struct nvme_health_information_page)); 706 NVME_LOGPAGE(fw, 707 NVME_LOG_FIRMWARE_SLOT, NULL, "Firmware Information", 708 print_log_firmware, sizeof(struct nvme_firmware_page)); 709 NVME_LOGPAGE(ns, 710 NVME_LOG_CHANGED_NAMESPACE, NULL, "Changed Namespace List", 711 print_log_ns, sizeof(struct nvme_ns_list)); 712 NVME_LOGPAGE(ce, 713 NVME_LOG_COMMAND_EFFECT, NULL, "Commands Supported and Effects", 714 print_log_command_effects, sizeof(struct nvme_command_effects_page)); 715 NVME_LOGPAGE(dst, 716 NVME_LOG_DEVICE_SELF_TEST, NULL, "Device Self-test", 717 print_log_self_test_status, sizeof(struct nvme_device_self_test_page)); 718 NVME_LOGPAGE(thi, 719 NVME_LOG_TELEMETRY_HOST_INITIATED, NULL, "Telemetry Host-Initiated", 720 NULL, DEFAULT_SIZE); 721 NVME_LOGPAGE(tci, 722 NVME_LOG_TELEMETRY_CONTROLLER_INITIATED, NULL, "Telemetry Controller-Initiated", 723 NULL, DEFAULT_SIZE); 724 NVME_LOGPAGE(egi, 725 NVME_LOG_ENDURANCE_GROUP_INFORMATION, NULL, "Endurance Group Information", 726 NULL, DEFAULT_SIZE); 727 NVME_LOGPAGE(plpns, 728 NVME_LOG_PREDICTABLE_LATENCY_PER_NVM_SET, NULL, "Predictable Latency Per NVM Set", 729 NULL, DEFAULT_SIZE); 730 NVME_LOGPAGE(ple, 731 NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE, NULL, "Predictable Latency Event Aggregate", 732 NULL, DEFAULT_SIZE); 733 NVME_LOGPAGE(ana, 734 NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS, NULL, "Asymmetric Namespace Access", 735 NULL, DEFAULT_SIZE); 736 NVME_LOGPAGE(pel, 737 NVME_LOG_PERSISTENT_EVENT_LOG, NULL, "Persistent Event Log", 738 NULL, DEFAULT_SIZE); 739 NVME_LOGPAGE(lbasi, 740 NVME_LOG_LBA_STATUS_INFORMATION, NULL, "LBA Status Information", 741 NULL, DEFAULT_SIZE); 742 NVME_LOGPAGE(egea, 743 NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE, NULL, "Endurance Group Event Aggregate", 744 NULL, DEFAULT_SIZE); 745 NVME_LOGPAGE(res_notification, 746 NVME_LOG_RES_NOTIFICATION, NULL, "Reservation Notification", 747 print_log_res_notification, sizeof(struct nvme_res_notification_page)); 748 NVME_LOGPAGE(sanitize_status, 749 NVME_LOG_SANITIZE_STATUS, NULL, "Sanitize Status", 750 print_log_sanitize_status, sizeof(struct nvme_sanitize_status_page)); 751 752 static void 753 logpage_help(void) 754 { 755 const struct logpage_function *f; 756 const char *v; 757 758 fprintf(stderr, "\n"); 759 fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name"); 760 fprintf(stderr, "-------- ---------- ----------\n"); 761 SLIST_FOREACH(f, &logpages, link) { 762 v = f->vendor == NULL ? "-" : f->vendor; 763 fprintf(stderr, "0x%02x %-10s %s\n", f->log_page, v, f->name); 764 } 765 766 exit(EX_USAGE); 767 } 768 769 static void 770 logpage(const struct cmd *f, int argc, char *argv[]) 771 { 772 int fd; 773 char *path; 774 uint32_t nsid, size; 775 void *buf; 776 const struct logpage_function *lpf; 777 struct nvme_controller_data cdata; 778 print_fn_t print_fn; 779 uint8_t ns_smart; 780 781 if (arg_parse(argc, argv, f)) 782 return; 783 if (opt.hex && opt.binary) { 784 fprintf(stderr, 785 "Can't specify both binary and hex\n"); 786 arg_help(argc, argv, f); 787 } 788 if (opt.vendor != NULL && strcmp(opt.vendor, "help") == 0) 789 logpage_help(); 790 if (opt.page == NONE) { 791 fprintf(stderr, "Missing page_id (-p).\n"); 792 arg_help(argc, argv, f); 793 } 794 open_dev(opt.dev, &fd, 0, 1); 795 get_nsid(fd, &path, &nsid); 796 if (nsid == 0) { 797 nsid = NVME_GLOBAL_NAMESPACE_TAG; 798 } else { 799 close(fd); 800 open_dev(path, &fd, 0, 1); 801 } 802 free(path); 803 804 if (read_controller_data(fd, &cdata)) 805 errx(EX_IOERR, "Identify request failed"); 806 807 ns_smart = (cdata.lpa >> NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT) & 808 NVME_CTRLR_DATA_LPA_NS_SMART_MASK; 809 810 /* 811 * The log page attributes indicate whether or not the controller 812 * supports the SMART/Health information log page on a per 813 * namespace basis. 814 */ 815 if (nsid != NVME_GLOBAL_NAMESPACE_TAG) { 816 if (opt.page != NVME_LOG_HEALTH_INFORMATION) 817 errx(EX_USAGE, "log page %d valid only at controller level", 818 opt.page); 819 if (ns_smart == 0) 820 errx(EX_UNAVAILABLE, 821 "controller does not support per namespace " 822 "smart/health information"); 823 } 824 825 print_fn = print_log_hex; 826 size = DEFAULT_SIZE; 827 if (opt.binary) 828 print_fn = print_bin; 829 if (!opt.binary && !opt.hex) { 830 /* 831 * See if there is a pretty print function for the specified log 832 * page. If one isn't found, we just revert to the default 833 * (print_hex). If there was a vendor specified by the user, and 834 * the page is vendor specific, don't match the print function 835 * unless the vendors match. 836 */ 837 SLIST_FOREACH(lpf, &logpages, link) { 838 if (lpf->vendor != NULL && opt.vendor != NULL && 839 strcmp(lpf->vendor, opt.vendor) != 0) 840 continue; 841 if (opt.page != lpf->log_page) 842 continue; 843 if (lpf->print_fn != NULL) 844 print_fn = lpf->print_fn; 845 size = lpf->size; 846 break; 847 } 848 } 849 850 if (opt.page == NVME_LOG_ERROR) { 851 size = sizeof(struct nvme_error_information_entry); 852 size *= (cdata.elpe + 1); 853 } 854 855 /* Read the log page */ 856 buf = get_log_buffer(size); 857 read_logpage(fd, opt.page, nsid, opt.lsp, opt.lsi, opt.rae, buf, size); 858 print_fn(&cdata, buf, size); 859 860 close(fd); 861 exit(0); 862 } 863