1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/ioccom.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <fcntl.h> 42 #include <stdbool.h> 43 #include <stddef.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <sys/endian.h> 49 50 #include "nvmecontrol.h" 51 52 /* Tables for command line parsing */ 53 54 static cmd_fn_t logpage; 55 56 #define NONE 0xffffffffu 57 static struct options { 58 bool binary; 59 bool hex; 60 uint32_t page; 61 uint8_t lsp; 62 uint16_t lsi; 63 bool rae; 64 const char *vendor; 65 const char *dev; 66 } opt = { 67 .binary = false, 68 .hex = false, 69 .page = NONE, 70 .lsp = 0, 71 .lsi = 0, 72 .rae = false, 73 .vendor = NULL, 74 .dev = NULL, 75 }; 76 77 static const struct opts logpage_opts[] = { 78 #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc } 79 OPT("binary", 'b', arg_none, opt, binary, 80 "Dump the log page as binary"), 81 OPT("hex", 'x', arg_none, opt, hex, 82 "Dump the log page as hex"), 83 OPT("page", 'p', arg_uint32, opt, page, 84 "Page to dump"), 85 OPT("lsp", 'f', arg_uint8, opt, lsp, 86 "Log Specific Field"), 87 OPT("lsi", 'i', arg_uint16, opt, lsp, 88 "Log Specific Identifier"), 89 OPT("rae", 'r', arg_none, opt, rae, 90 "Retain Asynchronous Event"), 91 OPT("vendor", 'v', arg_string, opt, vendor, 92 "Vendor specific formatting"), 93 { NULL, 0, arg_none, NULL, NULL } 94 }; 95 #undef OPT 96 97 static const struct args logpage_args[] = { 98 { arg_string, &opt.dev, "<controller id|namespace id>" }, 99 { arg_none, NULL, NULL }, 100 }; 101 102 static struct cmd logpage_cmd = { 103 .name = "logpage", 104 .fn = logpage, 105 .descr = "Print logpages in human-readable form", 106 .ctx_size = sizeof(opt), 107 .opts = logpage_opts, 108 .args = logpage_args, 109 }; 110 111 CMD_COMMAND(logpage_cmd); 112 113 /* End of tables for command line parsing */ 114 115 #define MAX_FW_SLOTS (7) 116 117 static SLIST_HEAD(,logpage_function) logpages; 118 119 static int 120 logpage_compare(struct logpage_function *a, struct logpage_function *b) 121 { 122 int c; 123 124 if ((a->vendor == NULL) != (b->vendor == NULL)) 125 return (a->vendor == NULL ? -1 : 1); 126 if (a->vendor != NULL) { 127 c = strcmp(a->vendor, b->vendor); 128 if (c != 0) 129 return (c); 130 } 131 return ((int)a->log_page - (int)b->log_page); 132 } 133 134 void 135 logpage_register(struct logpage_function *p) 136 { 137 struct logpage_function *l, *a; 138 139 a = NULL; 140 l = SLIST_FIRST(&logpages); 141 while (l != NULL) { 142 if (logpage_compare(l, p) > 0) 143 break; 144 a = l; 145 l = SLIST_NEXT(l, link); 146 } 147 if (a == NULL) 148 SLIST_INSERT_HEAD(&logpages, p, link); 149 else 150 SLIST_INSERT_AFTER(a, p, link); 151 } 152 153 const char * 154 kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key) 155 { 156 static char bad[32]; 157 size_t i; 158 159 for (i = 0; i < kv_count; i++, kv++) 160 if (kv->key == key) 161 return kv->name; 162 snprintf(bad, sizeof(bad), "Attribute %#x", key); 163 return bad; 164 } 165 166 static void 167 print_log_hex(const struct nvme_controller_data *cdata __unused, void *data, uint32_t length) 168 { 169 170 print_hex(data, length); 171 } 172 173 static void 174 print_bin(const struct nvme_controller_data *cdata __unused, void *data, uint32_t length) 175 { 176 177 write(STDOUT_FILENO, data, length); 178 } 179 180 static void * 181 get_log_buffer(uint32_t size) 182 { 183 void *buf; 184 185 if ((buf = malloc(size)) == NULL) 186 errx(1, "unable to malloc %u bytes", size); 187 188 memset(buf, 0, size); 189 return (buf); 190 } 191 192 void 193 read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp, 194 uint16_t lsi, uint8_t rae, void *payload, uint32_t payload_size) 195 { 196 struct nvme_pt_command pt; 197 struct nvme_error_information_entry *err_entry; 198 u_int i, err_pages, numd; 199 200 numd = payload_size / sizeof(uint32_t) - 1; 201 memset(&pt, 0, sizeof(pt)); 202 pt.cmd.opc = NVME_OPC_GET_LOG_PAGE; 203 pt.cmd.nsid = htole32(nsid); 204 pt.cmd.cdw10 = htole32( 205 (numd << 16) | /* NUMDL */ 206 (rae << 15) | /* RAE */ 207 (lsp << 8) | /* LSP */ 208 log_page); /* LID */ 209 pt.cmd.cdw11 = htole32( 210 ((uint32_t)lsi << 16) | /* LSI */ 211 (numd >> 16)); /* NUMDU */ 212 pt.cmd.cdw12 = 0; /* LPOL */ 213 pt.cmd.cdw13 = 0; /* LPOU */ 214 pt.cmd.cdw14 = 0; /* UUID Index */ 215 pt.buf = payload; 216 pt.len = payload_size; 217 pt.is_read = 1; 218 219 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 220 err(1, "get log page request failed"); 221 222 /* Convert data to host endian */ 223 switch (log_page) { 224 case NVME_LOG_ERROR: 225 err_entry = (struct nvme_error_information_entry *)payload; 226 err_pages = payload_size / sizeof(struct nvme_error_information_entry); 227 for (i = 0; i < err_pages; i++) 228 nvme_error_information_entry_swapbytes(err_entry++); 229 break; 230 case NVME_LOG_HEALTH_INFORMATION: 231 nvme_health_information_page_swapbytes( 232 (struct nvme_health_information_page *)payload); 233 break; 234 case NVME_LOG_FIRMWARE_SLOT: 235 nvme_firmware_page_swapbytes( 236 (struct nvme_firmware_page *)payload); 237 break; 238 case NVME_LOG_CHANGED_NAMESPACE: 239 nvme_ns_list_swapbytes((struct nvme_ns_list *)payload); 240 break; 241 case NVME_LOG_COMMAND_EFFECT: 242 nvme_command_effects_page_swapbytes( 243 (struct nvme_command_effects_page *)payload); 244 break; 245 case NVME_LOG_RES_NOTIFICATION: 246 nvme_res_notification_page_swapbytes( 247 (struct nvme_res_notification_page *)payload); 248 break; 249 case NVME_LOG_SANITIZE_STATUS: 250 nvme_sanitize_status_page_swapbytes( 251 (struct nvme_sanitize_status_page *)payload); 252 break; 253 case INTEL_LOG_TEMP_STATS: 254 intel_log_temp_stats_swapbytes( 255 (struct intel_log_temp_stats *)payload); 256 break; 257 default: 258 break; 259 } 260 261 if (nvme_completion_is_error(&pt.cpl)) 262 errx(1, "get log page request returned error"); 263 } 264 265 static void 266 print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size) 267 { 268 int i, nentries; 269 uint16_t status; 270 uint8_t p, sc, sct, m, dnr; 271 struct nvme_error_information_entry *entry = buf; 272 273 printf("Error Information Log\n"); 274 printf("=====================\n"); 275 276 if (entry->error_count == 0) { 277 printf("No error entries found\n"); 278 return; 279 } 280 281 nentries = size/sizeof(struct nvme_error_information_entry); 282 for (i = 0; i < nentries; i++, entry++) { 283 if (entry->error_count == 0) 284 break; 285 286 status = entry->status; 287 288 p = NVME_STATUS_GET_P(status); 289 sc = NVME_STATUS_GET_SC(status); 290 sct = NVME_STATUS_GET_SCT(status); 291 m = NVME_STATUS_GET_M(status); 292 dnr = NVME_STATUS_GET_DNR(status); 293 294 printf("Entry %02d\n", i + 1); 295 printf("=========\n"); 296 printf(" Error count: %ju\n", entry->error_count); 297 printf(" Submission queue ID: %u\n", entry->sqid); 298 printf(" Command ID: %u\n", entry->cid); 299 /* TODO: Export nvme_status_string structures from kernel? */ 300 printf(" Status:\n"); 301 printf(" Phase tag: %d\n", p); 302 printf(" Status code: %d\n", sc); 303 printf(" Status code type: %d\n", sct); 304 printf(" More: %d\n", m); 305 printf(" DNR: %d\n", dnr); 306 printf(" Error location: %u\n", entry->error_location); 307 printf(" LBA: %ju\n", entry->lba); 308 printf(" Namespace ID: %u\n", entry->nsid); 309 printf(" Vendor specific info: %u\n", entry->vendor_specific); 310 printf(" Transport type: %u\n", entry->trtype); 311 printf(" Command specific info:%ju\n", entry->csi); 312 printf(" Transport specific: %u\n", entry->ttsi); 313 } 314 } 315 316 void 317 print_temp(uint16_t t) 318 { 319 printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, (float)t * 9 / 5 - 459.67); 320 } 321 322 323 static void 324 print_log_health(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused) 325 { 326 struct nvme_health_information_page *health = buf; 327 char cbuf[UINT128_DIG + 1]; 328 uint8_t warning; 329 int i; 330 331 warning = health->critical_warning; 332 333 printf("SMART/Health Information Log\n"); 334 printf("============================\n"); 335 336 printf("Critical Warning State: 0x%02x\n", warning); 337 printf(" Available spare: %d\n", 338 !!(warning & NVME_CRIT_WARN_ST_AVAILABLE_SPARE)); 339 printf(" Temperature: %d\n", 340 !!(warning & NVME_CRIT_WARN_ST_TEMPERATURE)); 341 printf(" Device reliability: %d\n", 342 !!(warning & NVME_CRIT_WARN_ST_DEVICE_RELIABILITY)); 343 printf(" Read only: %d\n", 344 !!(warning & NVME_CRIT_WARN_ST_READ_ONLY)); 345 printf(" Volatile memory backup: %d\n", 346 !!(warning & NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP)); 347 printf("Temperature: "); 348 print_temp(health->temperature); 349 printf("Available spare: %u\n", 350 health->available_spare); 351 printf("Available spare threshold: %u\n", 352 health->available_spare_threshold); 353 printf("Percentage used: %u\n", 354 health->percentage_used); 355 356 printf("Data units (512,000 byte) read: %s\n", 357 uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf))); 358 printf("Data units written: %s\n", 359 uint128_to_str(to128(health->data_units_written), cbuf, sizeof(cbuf))); 360 printf("Host read commands: %s\n", 361 uint128_to_str(to128(health->host_read_commands), cbuf, sizeof(cbuf))); 362 printf("Host write commands: %s\n", 363 uint128_to_str(to128(health->host_write_commands), cbuf, sizeof(cbuf))); 364 printf("Controller busy time (minutes): %s\n", 365 uint128_to_str(to128(health->controller_busy_time), cbuf, sizeof(cbuf))); 366 printf("Power cycles: %s\n", 367 uint128_to_str(to128(health->power_cycles), cbuf, sizeof(cbuf))); 368 printf("Power on hours: %s\n", 369 uint128_to_str(to128(health->power_on_hours), cbuf, sizeof(cbuf))); 370 printf("Unsafe shutdowns: %s\n", 371 uint128_to_str(to128(health->unsafe_shutdowns), cbuf, sizeof(cbuf))); 372 printf("Media errors: %s\n", 373 uint128_to_str(to128(health->media_errors), cbuf, sizeof(cbuf))); 374 printf("No. error info log entries: %s\n", 375 uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf))); 376 377 printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); 378 printf("Error Temp Composite Time: %d\n", health->error_temp_time); 379 for (i = 0; i < 8; i++) { 380 if (health->temp_sensor[i] == 0) 381 continue; 382 printf("Temperature Sensor %d: ", i + 1); 383 print_temp(health->temp_sensor[i]); 384 } 385 printf("Temperature 1 Transition Count: %d\n", health->tmt1tc); 386 printf("Temperature 2 Transition Count: %d\n", health->tmt2tc); 387 printf("Total Time For Temperature 1: %d\n", health->ttftmt1); 388 printf("Total Time For Temperature 2: %d\n", health->ttftmt2); 389 } 390 391 static void 392 print_log_firmware(const struct nvme_controller_data *cdata, void *buf, uint32_t size __unused) 393 { 394 int i, slots; 395 const char *status; 396 struct nvme_firmware_page *fw = buf; 397 uint8_t afi_slot; 398 uint16_t oacs_fw; 399 uint8_t fw_num_slots; 400 401 afi_slot = fw->afi >> NVME_FIRMWARE_PAGE_AFI_SLOT_SHIFT; 402 afi_slot &= NVME_FIRMWARE_PAGE_AFI_SLOT_MASK; 403 404 oacs_fw = (cdata->oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) & 405 NVME_CTRLR_DATA_OACS_FIRMWARE_MASK; 406 fw_num_slots = (cdata->frmw >> NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT) & 407 NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK; 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] == 0LLU) 425 printf("Empty\n"); 426 else 427 if (isprint(*(char *)&fw->revision[i])) 428 printf("[%s] %.8s\n", status, 429 (char *)&fw->revision[i]); 430 else 431 printf("[%s] %016jx\n", status, 432 fw->revision[i]); 433 } 434 } 435 436 static void 437 print_log_ns(const struct nvme_controller_data *cdata __unused, void *buf, 438 uint32_t size __unused) 439 { 440 struct nvme_ns_list *nsl; 441 u_int i; 442 443 nsl = (struct nvme_ns_list *)buf; 444 printf("Changed Namespace List\n"); 445 printf("======================\n"); 446 447 for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) { 448 printf("%08x\n", nsl->ns[i]); 449 } 450 } 451 452 static void 453 print_log_command_effects(const struct nvme_controller_data *cdata __unused, 454 void *buf, uint32_t size __unused) 455 { 456 struct nvme_command_effects_page *ce; 457 u_int i; 458 uint32_t s; 459 460 ce = (struct nvme_command_effects_page *)buf; 461 printf("Commands Supported and Effects\n"); 462 printf("==============================\n"); 463 printf(" Command\tLBCC\tNCC\tNIC\tCCC\tCSE\tUUID\n"); 464 465 for (i = 0; i < 255; i++) { 466 s = ce->acs[i]; 467 if (((s >> NVME_CE_PAGE_CSUP_SHIFT) & 468 NVME_CE_PAGE_CSUP_MASK) == 0) 469 continue; 470 printf("Admin\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 471 ((s >> NVME_CE_PAGE_LBCC_SHIFT) & 472 NVME_CE_PAGE_LBCC_MASK) ? "Yes" : "No", 473 ((s >> NVME_CE_PAGE_NCC_SHIFT) & 474 NVME_CE_PAGE_NCC_MASK) ? "Yes" : "No", 475 ((s >> NVME_CE_PAGE_NIC_SHIFT) & 476 NVME_CE_PAGE_NIC_MASK) ? "Yes" : "No", 477 ((s >> NVME_CE_PAGE_CCC_SHIFT) & 478 NVME_CE_PAGE_CCC_MASK) ? "Yes" : "No", 479 ((s >> NVME_CE_PAGE_CSE_SHIFT) & 480 NVME_CE_PAGE_CSE_MASK), 481 ((s >> NVME_CE_PAGE_UUID_SHIFT) & 482 NVME_CE_PAGE_UUID_MASK) ? "Yes" : "No"); 483 } 484 for (i = 0; i < 255; i++) { 485 s = ce->iocs[i]; 486 if (((s >> NVME_CE_PAGE_CSUP_SHIFT) & 487 NVME_CE_PAGE_CSUP_MASK) == 0) 488 continue; 489 printf("I/O\t%02x\t%s\t%s\t%s\t%s\t%u\t%s\n", i, 490 ((s >> NVME_CE_PAGE_LBCC_SHIFT) & 491 NVME_CE_PAGE_LBCC_MASK) ? "Yes" : "No", 492 ((s >> NVME_CE_PAGE_NCC_SHIFT) & 493 NVME_CE_PAGE_NCC_MASK) ? "Yes" : "No", 494 ((s >> NVME_CE_PAGE_NIC_SHIFT) & 495 NVME_CE_PAGE_NIC_MASK) ? "Yes" : "No", 496 ((s >> NVME_CE_PAGE_CCC_SHIFT) & 497 NVME_CE_PAGE_CCC_MASK) ? "Yes" : "No", 498 ((s >> NVME_CE_PAGE_CSE_SHIFT) & 499 NVME_CE_PAGE_CSE_MASK), 500 ((s >> NVME_CE_PAGE_UUID_SHIFT) & 501 NVME_CE_PAGE_UUID_MASK) ? "Yes" : "No"); 502 } 503 } 504 505 static void 506 print_log_res_notification(const struct nvme_controller_data *cdata __unused, 507 void *buf, uint32_t size __unused) 508 { 509 struct nvme_res_notification_page *rn; 510 511 rn = (struct nvme_res_notification_page *)buf; 512 printf("Reservation Notification\n"); 513 printf("========================\n"); 514 515 printf("Log Page Count: %ju\n", rn->log_page_count); 516 printf("Log Page Type: "); 517 switch (rn->log_page_type) { 518 case 0: 519 printf("Empty Log Page\n"); 520 break; 521 case 1: 522 printf("Registration Preempted\n"); 523 break; 524 case 2: 525 printf("Reservation Released\n"); 526 break; 527 case 3: 528 printf("Reservation Preempted\n"); 529 break; 530 default: 531 printf("Unknown %x\n", rn->log_page_type); 532 break; 533 }; 534 printf("Number of Available Log Pages: %d\n", rn->available_log_pages); 535 printf("Namespace ID: 0x%x\n", rn->nsid); 536 } 537 538 static void 539 print_log_sanitize_status(const struct nvme_controller_data *cdata __unused, 540 void *buf, uint32_t size __unused) 541 { 542 struct nvme_sanitize_status_page *ss; 543 u_int p; 544 545 ss = (struct nvme_sanitize_status_page *)buf; 546 printf("Sanitize Status\n"); 547 printf("===============\n"); 548 549 printf("Sanitize Progress: %u%% (%u/65535)\n", 550 (ss->sprog * 100 + 32768) / 65536, ss->sprog); 551 printf("Sanitize Status: "); 552 switch ((ss->sstat >> NVME_SS_PAGE_SSTAT_STATUS_SHIFT) & 553 NVME_SS_PAGE_SSTAT_STATUS_MASK) { 554 case NVME_SS_PAGE_SSTAT_STATUS_NEVER: 555 printf("Never sanitized"); 556 break; 557 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETED: 558 printf("Completed"); 559 break; 560 case NVME_SS_PAGE_SSTAT_STATUS_INPROG: 561 printf("In Progress"); 562 break; 563 case NVME_SS_PAGE_SSTAT_STATUS_FAILED: 564 printf("Failed"); 565 break; 566 case NVME_SS_PAGE_SSTAT_STATUS_COMPLETEDWD: 567 printf("Completed with deallocation"); 568 break; 569 default: 570 printf("Unknown"); 571 break; 572 } 573 p = (ss->sstat >> NVME_SS_PAGE_SSTAT_PASSES_SHIFT) & 574 NVME_SS_PAGE_SSTAT_PASSES_MASK; 575 if (p > 0) 576 printf(", %d passes", p); 577 if ((ss->sstat >> NVME_SS_PAGE_SSTAT_GDE_SHIFT) & 578 NVME_SS_PAGE_SSTAT_GDE_MASK) 579 printf(", Global Data Erased"); 580 printf("\n"); 581 printf("Sanitize Command Dword 10: 0x%x\n", ss->scdw10); 582 printf("Time For Overwrite: %u sec\n", ss->etfo); 583 printf("Time For Block Erase: %u sec\n", ss->etfbe); 584 printf("Time For Crypto Erase: %u sec\n", ss->etfce); 585 printf("Time For Overwrite No-Deallocate: %u sec\n", ss->etfownd); 586 printf("Time For Block Erase No-Deallocate: %u sec\n", ss->etfbewnd); 587 printf("Time For Crypto Erase No-Deallocate: %u sec\n", ss->etfcewnd); 588 } 589 590 /* 591 * Table of log page printer / sizing. 592 * 593 * Make sure you keep all the pages of one vendor together so -v help 594 * lists all the vendors pages. 595 */ 596 NVME_LOGPAGE(error, 597 NVME_LOG_ERROR, NULL, "Drive Error Log", 598 print_log_error, 0); 599 NVME_LOGPAGE(health, 600 NVME_LOG_HEALTH_INFORMATION, NULL, "Health/SMART Data", 601 print_log_health, sizeof(struct nvme_health_information_page)); 602 NVME_LOGPAGE(fw, 603 NVME_LOG_FIRMWARE_SLOT, NULL, "Firmware Information", 604 print_log_firmware, sizeof(struct nvme_firmware_page)); 605 NVME_LOGPAGE(ns, 606 NVME_LOG_CHANGED_NAMESPACE, NULL, "Changed Namespace List", 607 print_log_ns, sizeof(struct nvme_ns_list)); 608 NVME_LOGPAGE(ce, 609 NVME_LOG_COMMAND_EFFECT, NULL, "Commands Supported and Effects", 610 print_log_command_effects, sizeof(struct nvme_command_effects_page)); 611 NVME_LOGPAGE(dst, 612 NVME_LOG_DEVICE_SELF_TEST, NULL, "Device Self-test", 613 NULL, 564); 614 NVME_LOGPAGE(thi, 615 NVME_LOG_TELEMETRY_HOST_INITIATED, NULL, "Telemetry Host-Initiated", 616 NULL, DEFAULT_SIZE); 617 NVME_LOGPAGE(tci, 618 NVME_LOG_TELEMETRY_CONTROLLER_INITIATED, NULL, "Telemetry Controller-Initiated", 619 NULL, DEFAULT_SIZE); 620 NVME_LOGPAGE(egi, 621 NVME_LOG_ENDURANCE_GROUP_INFORMATION, NULL, "Endurance Group Information", 622 NULL, DEFAULT_SIZE); 623 NVME_LOGPAGE(plpns, 624 NVME_LOG_PREDICTABLE_LATENCY_PER_NVM_SET, NULL, "Predictable Latency Per NVM Set", 625 NULL, DEFAULT_SIZE); 626 NVME_LOGPAGE(ple, 627 NVME_LOG_PREDICTABLE_LATENCY_EVENT_AGGREGATE, NULL, "Predictable Latency Event Aggregate", 628 NULL, DEFAULT_SIZE); 629 NVME_LOGPAGE(ana, 630 NVME_LOG_ASYMMETRIC_NAMESPAVE_ACCESS, NULL, "Asymmetric Namespace Access", 631 NULL, DEFAULT_SIZE); 632 NVME_LOGPAGE(pel, 633 NVME_LOG_PERSISTENT_EVENT_LOG, NULL, "Persistent Event Log", 634 NULL, DEFAULT_SIZE); 635 NVME_LOGPAGE(lbasi, 636 NVME_LOG_LBA_STATUS_INFORMATION, NULL, "LBA Status Information", 637 NULL, DEFAULT_SIZE); 638 NVME_LOGPAGE(egea, 639 NVME_LOG_ENDURANCE_GROUP_EVENT_AGGREGATE, NULL, "Endurance Group Event Aggregate", 640 NULL, DEFAULT_SIZE); 641 NVME_LOGPAGE(res_notification, 642 NVME_LOG_RES_NOTIFICATION, NULL, "Reservation Notification", 643 print_log_res_notification, sizeof(struct nvme_res_notification_page)); 644 NVME_LOGPAGE(sanitize_status, 645 NVME_LOG_SANITIZE_STATUS, NULL, "Sanitize Status", 646 print_log_sanitize_status, sizeof(struct nvme_sanitize_status_page)); 647 648 static void 649 logpage_help(void) 650 { 651 const struct logpage_function *f; 652 const char *v; 653 654 fprintf(stderr, "\n"); 655 fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name"); 656 fprintf(stderr, "-------- ---------- ----------\n"); 657 SLIST_FOREACH(f, &logpages, link) { 658 v = f->vendor == NULL ? "-" : f->vendor; 659 fprintf(stderr, "0x%02x %-10s %s\n", f->log_page, v, f->name); 660 } 661 662 exit(1); 663 } 664 665 static void 666 logpage(const struct cmd *f, int argc, char *argv[]) 667 { 668 int fd; 669 char *path; 670 uint32_t nsid, size; 671 void *buf; 672 const struct logpage_function *lpf; 673 struct nvme_controller_data cdata; 674 print_fn_t print_fn; 675 uint8_t ns_smart; 676 677 if (arg_parse(argc, argv, f)) 678 return; 679 if (opt.hex && opt.binary) { 680 fprintf(stderr, 681 "Can't specify both binary and hex\n"); 682 arg_help(argc, argv, f); 683 } 684 if (opt.vendor != NULL && strcmp(opt.vendor, "help") == 0) 685 logpage_help(); 686 if (opt.page == NONE) { 687 fprintf(stderr, "Missing page_id (-p).\n"); 688 arg_help(argc, argv, f); 689 } 690 open_dev(opt.dev, &fd, 1, 1); 691 get_nsid(fd, &path, &nsid); 692 if (nsid == 0) { 693 nsid = NVME_GLOBAL_NAMESPACE_TAG; 694 } else { 695 close(fd); 696 open_dev(path, &fd, 1, 1); 697 } 698 free(path); 699 700 read_controller_data(fd, &cdata); 701 702 ns_smart = (cdata.lpa >> NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT) & 703 NVME_CTRLR_DATA_LPA_NS_SMART_MASK; 704 705 /* 706 * The log page attribtues indicate whether or not the controller 707 * supports the SMART/Health information log page on a per 708 * namespace basis. 709 */ 710 if (nsid != NVME_GLOBAL_NAMESPACE_TAG) { 711 if (opt.page != NVME_LOG_HEALTH_INFORMATION) 712 errx(1, "log page %d valid only at controller level", 713 opt.page); 714 if (ns_smart == 0) 715 errx(1, 716 "controller does not support per namespace " 717 "smart/health information"); 718 } 719 720 print_fn = print_log_hex; 721 size = DEFAULT_SIZE; 722 if (opt.binary) 723 print_fn = print_bin; 724 if (!opt.binary && !opt.hex) { 725 /* 726 * See if there is a pretty print function for the specified log 727 * page. If one isn't found, we just revert to the default 728 * (print_hex). If there was a vendor specified by the user, and 729 * the page is vendor specific, don't match the print function 730 * unless the vendors match. 731 */ 732 SLIST_FOREACH(lpf, &logpages, link) { 733 if (lpf->vendor != NULL && opt.vendor != NULL && 734 strcmp(lpf->vendor, opt.vendor) != 0) 735 continue; 736 if (opt.page != lpf->log_page) 737 continue; 738 if (lpf->print_fn != NULL) 739 print_fn = lpf->print_fn; 740 size = lpf->size; 741 break; 742 } 743 } 744 745 if (opt.page == NVME_LOG_ERROR) { 746 size = sizeof(struct nvme_error_information_entry); 747 size *= (cdata.elpe + 1); 748 } 749 750 /* Read the log page */ 751 buf = get_log_buffer(size); 752 read_logpage(fd, opt.page, nsid, opt.lsp, opt.lsi, opt.rae, buf, size); 753 print_fn(&cdata, buf, size); 754 755 close(fd); 756 exit(0); 757 } 758