1 /*- 2 * Copyright (c) 2013 EMC Corp. 3 * All rights reserved. 4 * 5 * Copyright (C) 2012-2013 Intel Corporation 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 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 <unistd.h> 45 #include <sys/endian.h> 46 47 #if _BYTE_ORDER != _LITTLE_ENDIAN 48 #error "Code only works on little endian machines" 49 #endif 50 51 #include "nvmecontrol.h" 52 53 #define DEFAULT_SIZE (4096) 54 #define MAX_FW_SLOTS (7) 55 56 typedef void (*print_fn_t)(void *buf, uint32_t size); 57 58 struct kv_name 59 { 60 uint32_t key; 61 const char *name; 62 }; 63 64 static const char * 65 kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key) 66 { 67 static char bad[32]; 68 size_t i; 69 70 for (i = 0; i < kv_count; i++, kv++) 71 if (kv->key == key) 72 return kv->name; 73 snprintf(bad, sizeof(bad), "Attribute %#x", key); 74 return bad; 75 } 76 77 static void 78 print_bin(void *data, uint32_t length) 79 { 80 write(STDOUT_FILENO, data, length); 81 } 82 83 static void * 84 get_log_buffer(uint32_t size) 85 { 86 void *buf; 87 88 if ((buf = malloc(size)) == NULL) 89 errx(1, "unable to malloc %u bytes", size); 90 91 memset(buf, 0, size); 92 return (buf); 93 } 94 95 void 96 read_logpage(int fd, uint8_t log_page, int nsid, void *payload, 97 uint32_t payload_size) 98 { 99 struct nvme_pt_command pt; 100 101 memset(&pt, 0, sizeof(pt)); 102 pt.cmd.opc = NVME_OPC_GET_LOG_PAGE; 103 pt.cmd.nsid = nsid; 104 pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16; 105 pt.cmd.cdw10 |= log_page; 106 pt.buf = payload; 107 pt.len = payload_size; 108 pt.is_read = 1; 109 110 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) 111 err(1, "get log page request failed"); 112 113 if (nvme_completion_is_error(&pt.cpl)) 114 errx(1, "get log page request returned error"); 115 } 116 117 static void 118 print_log_error(void *buf, uint32_t size) 119 { 120 int i, nentries; 121 struct nvme_error_information_entry *entry = buf; 122 struct nvme_status *status; 123 124 printf("Error Information Log\n"); 125 printf("=====================\n"); 126 127 if (entry->error_count == 0) { 128 printf("No error entries found\n"); 129 return; 130 } 131 132 nentries = size/sizeof(struct nvme_error_information_entry); 133 for (i = 0; i < nentries; i++, entry++) { 134 if (entry->error_count == 0) 135 break; 136 137 status = &entry->status; 138 printf("Entry %02d\n", i + 1); 139 printf("=========\n"); 140 printf(" Error count: %ju\n", entry->error_count); 141 printf(" Submission queue ID: %u\n", entry->sqid); 142 printf(" Command ID: %u\n", entry->cid); 143 /* TODO: Export nvme_status_string structures from kernel? */ 144 printf(" Status:\n"); 145 printf(" Phase tag: %d\n", status->p); 146 printf(" Status code: %d\n", status->sc); 147 printf(" Status code type: %d\n", status->sct); 148 printf(" More: %d\n", status->m); 149 printf(" DNR: %d\n", status->dnr); 150 printf(" Error location: %u\n", entry->error_location); 151 printf(" LBA: %ju\n", entry->lba); 152 printf(" Namespace ID: %u\n", entry->nsid); 153 printf(" Vendor specific info: %u\n", entry->vendor_specific); 154 } 155 } 156 157 static void 158 print_temp(uint16_t t) 159 { 160 printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, (float)t * 9 / 5 - 459.67); 161 } 162 163 164 static void 165 print_log_health(void *buf, uint32_t size __unused) 166 { 167 struct nvme_health_information_page *health = buf; 168 char cbuf[UINT128_DIG + 1]; 169 int i; 170 171 printf("SMART/Health Information Log\n"); 172 printf("============================\n"); 173 174 printf("Critical Warning State: 0x%02x\n", 175 health->critical_warning.raw); 176 printf(" Available spare: %d\n", 177 health->critical_warning.bits.available_spare); 178 printf(" Temperature: %d\n", 179 health->critical_warning.bits.temperature); 180 printf(" Device reliability: %d\n", 181 health->critical_warning.bits.device_reliability); 182 printf(" Read only: %d\n", 183 health->critical_warning.bits.read_only); 184 printf(" Volatile memory backup: %d\n", 185 health->critical_warning.bits.volatile_memory_backup); 186 printf("Temperature: "); 187 print_temp(health->temperature); 188 printf("Available spare: %u\n", 189 health->available_spare); 190 printf("Available spare threshold: %u\n", 191 health->available_spare_threshold); 192 printf("Percentage used: %u\n", 193 health->percentage_used); 194 195 printf("Data units (512,000 byte) read: %s\n", 196 uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf))); 197 printf("Data units written: %s\n", 198 uint128_to_str(to128(health->data_units_written), cbuf, sizeof(cbuf))); 199 printf("Host read commands: %s\n", 200 uint128_to_str(to128(health->host_read_commands), cbuf, sizeof(cbuf))); 201 printf("Host write commands: %s\n", 202 uint128_to_str(to128(health->host_write_commands), cbuf, sizeof(cbuf))); 203 printf("Controller busy time (minutes): %s\n", 204 uint128_to_str(to128(health->controller_busy_time), cbuf, sizeof(cbuf))); 205 printf("Power cycles: %s\n", 206 uint128_to_str(to128(health->power_cycles), cbuf, sizeof(cbuf))); 207 printf("Power on hours: %s\n", 208 uint128_to_str(to128(health->power_on_hours), cbuf, sizeof(cbuf))); 209 printf("Unsafe shutdowns: %s\n", 210 uint128_to_str(to128(health->unsafe_shutdowns), cbuf, sizeof(cbuf))); 211 printf("Media errors: %s\n", 212 uint128_to_str(to128(health->media_errors), cbuf, sizeof(cbuf))); 213 printf("No. error info log entries: %s\n", 214 uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf))); 215 216 printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); 217 printf("Error Temp Composite Time: %d\n", health->error_temp_time); 218 for (i = 0; i < 7; i++) { 219 if (health->temp_sensor[i] == 0) 220 continue; 221 printf("Temperature Sensor %d: ", i + 1); 222 print_temp(health->temp_sensor[i]); 223 } 224 } 225 226 static void 227 print_log_firmware(void *buf, uint32_t size __unused) 228 { 229 int i; 230 const char *status; 231 struct nvme_firmware_page *fw = buf; 232 233 printf("Firmware Slot Log\n"); 234 printf("=================\n"); 235 236 for (i = 0; i < MAX_FW_SLOTS; i++) { 237 printf("Slot %d: ", i + 1); 238 if (fw->afi.slot == i + 1) 239 status = " Active"; 240 else 241 status = "Inactive"; 242 243 if (fw->revision[i] == 0LLU) 244 printf("Empty\n"); 245 else 246 if (isprint(*(char *)&fw->revision[i])) 247 printf("[%s] %.8s\n", status, 248 (char *)&fw->revision[i]); 249 else 250 printf("[%s] %016jx\n", status, 251 fw->revision[i]); 252 } 253 } 254 255 /* 256 * Intel specific log pages from 257 * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/ssd-dc-p3700-spec.pdf 258 * 259 * Though the version as of this date has a typo for the size of log page 0xca, 260 * offset 147: it is only 1 byte, not 6. 261 */ 262 static void 263 print_intel_temp_stats(void *buf, uint32_t size __unused) 264 { 265 struct intel_log_temp_stats *temp = buf; 266 267 printf("Intel Temperature Log\n"); 268 printf("=====================\n"); 269 270 printf("Current: "); 271 print_temp(temp->current); 272 printf("Overtemp Last Flags %#jx\n", (uintmax_t)temp->overtemp_flag_last); 273 printf("Overtemp Lifetime Flags %#jx\n", (uintmax_t)temp->overtemp_flag_life); 274 printf("Max Temperature "); 275 print_temp(temp->max_temp); 276 printf("Min Temperature "); 277 print_temp(temp->min_temp); 278 printf("Max Operating Temperature "); 279 print_temp(temp->max_oper_temp); 280 printf("Min Operating Temperature "); 281 print_temp(temp->min_oper_temp); 282 printf("Estimated Temperature Offset: %ju C/K\n", (uintmax_t)temp->est_offset); 283 } 284 285 /* 286 * Format from Table 22, section 5.7 IO Command Latency Statistics. 287 * Read and write stats pages have identical encoding. 288 */ 289 static void 290 print_intel_read_write_lat_log(void *buf, uint32_t size __unused) 291 { 292 const char *walker = buf; 293 int i; 294 295 printf("Major: %d\n", le16dec(walker + 0)); 296 printf("Minor: %d\n", le16dec(walker + 2)); 297 for (i = 0; i < 32; i++) 298 printf("%4dus-%4dus: %ju\n", i * 32, (i + 1) * 32, (uintmax_t)le32dec(walker + 4 + i * 4)); 299 for (i = 1; i < 32; i++) 300 printf("%4dms-%4dms: %ju\n", i, i + 1, (uintmax_t)le32dec(walker + 132 + i * 4)); 301 for (i = 1; i < 32; i++) 302 printf("%4dms-%4dms: %ju\n", i * 32, (i + 1) * 32, (uintmax_t)le32dec(walker + 256 + i * 4)); 303 } 304 305 static void 306 print_intel_read_lat_log(void *buf, uint32_t size) 307 { 308 309 printf("Intel Read Latency Log\n"); 310 printf("======================\n"); 311 print_intel_read_write_lat_log(buf, size); 312 } 313 314 static void 315 print_intel_write_lat_log(void *buf, uint32_t size) 316 { 317 318 printf("Intel Write Latency Log\n"); 319 printf("=======================\n"); 320 print_intel_read_write_lat_log(buf, size); 321 } 322 323 /* 324 * Table 19. 5.4 SMART Attributes. Samsung also implements this and some extra data not documented. 325 */ 326 static void 327 print_intel_add_smart(void *buf, uint32_t size __unused) 328 { 329 uint8_t *walker = buf; 330 uint8_t *end = walker + 150; 331 const char *name; 332 uint64_t raw; 333 uint8_t normalized; 334 335 static struct kv_name kv[] = 336 { 337 { 0xab, "Program Fail Count" }, 338 { 0xac, "Erase Fail Count" }, 339 { 0xad, "Wear Leveling Count" }, 340 { 0xb8, "End to End Error Count" }, 341 { 0xc7, "CRC Error Count" }, 342 { 0xe2, "Timed: Media Wear" }, 343 { 0xe3, "Timed: Host Read %" }, 344 { 0xe4, "Timed: Elapsed Time" }, 345 { 0xea, "Thermal Throttle Status" }, 346 { 0xf0, "Retry Buffer Overflows" }, 347 { 0xf3, "PLL Lock Loss Count" }, 348 { 0xf4, "NAND Bytes Written" }, 349 { 0xf5, "Host Bytes Written" }, 350 }; 351 352 printf("Additional SMART Data Log\n"); 353 printf("=========================\n"); 354 /* 355 * walker[0] = Key 356 * walker[1,2] = reserved 357 * walker[3] = Normalized Value 358 * walker[4] = reserved 359 * walker[5..10] = Little Endian Raw value 360 * (or other represenations) 361 * walker[11] = reserved 362 */ 363 while (walker < end) { 364 name = kv_lookup(kv, nitems(kv), *walker); 365 normalized = walker[3]; 366 raw = le48dec(walker + 5); 367 switch (*walker){ 368 case 0: 369 break; 370 case 0xad: 371 printf("%-32s: %3d min: %u max: %u ave: %u\n", name, normalized, 372 le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9)); 373 break; 374 case 0xe2: 375 printf("%-32s: %3d %.3f%%\n", name, normalized, raw / 1024.0); 376 break; 377 case 0xea: 378 printf("%-32s: %3d %d%% %d times\n", name, normalized, walker[5], le32dec(walker+6)); 379 break; 380 default: 381 printf("%-32s: %3d %ju\n", name, normalized, (uintmax_t)raw); 382 break; 383 } 384 walker += 12; 385 } 386 } 387 388 /* 389 * HGST's 0xc1 page. This is a grab bag of additional data. Please see 390 * https://www.hgst.com/sites/default/files/resources/US_SN150_ProdManual.pdf 391 * https://www.hgst.com/sites/default/files/resources/US_SN100_ProdManual.pdf 392 * Appendix A for details 393 */ 394 395 typedef void (*subprint_fn_t)(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 396 397 struct subpage_print 398 { 399 uint16_t key; 400 subprint_fn_t fn; 401 }; 402 403 static void print_hgst_info_write_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 404 static void print_hgst_info_read_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 405 static void print_hgst_info_verify_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 406 static void print_hgst_info_self_test(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 407 static void print_hgst_info_background_scan(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 408 static void print_hgst_info_erase_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 409 static void print_hgst_info_erase_counts(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 410 static void print_hgst_info_temp_history(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 411 static void print_hgst_info_ssd_perf(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 412 static void print_hgst_info_firmware_load(void *buf, uint16_t subtype, uint8_t res, uint32_t size); 413 414 static struct subpage_print hgst_subpage[] = { 415 { 0x02, print_hgst_info_write_errors }, 416 { 0x03, print_hgst_info_read_errors }, 417 { 0x05, print_hgst_info_verify_errors }, 418 { 0x10, print_hgst_info_self_test }, 419 { 0x15, print_hgst_info_background_scan }, 420 { 0x30, print_hgst_info_erase_errors }, 421 { 0x31, print_hgst_info_erase_counts }, 422 { 0x32, print_hgst_info_temp_history }, 423 { 0x37, print_hgst_info_ssd_perf }, 424 { 0x38, print_hgst_info_firmware_load }, 425 }; 426 427 /* Print a subpage that is basically just key value pairs */ 428 static void 429 print_hgst_info_subpage_gen(void *buf, uint16_t subtype __unused, uint32_t size, 430 const struct kv_name *kv, size_t kv_count) 431 { 432 uint8_t *wsp, *esp; 433 uint16_t ptype; 434 uint8_t plen; 435 uint64_t param; 436 int i; 437 438 wsp = buf; 439 esp = wsp + size; 440 while (wsp < esp) { 441 ptype = le16dec(wsp); 442 wsp += 2; 443 wsp++; /* Flags, just ignore */ 444 plen = *wsp++; 445 param = 0; 446 for (i = 0; i < plen; i++) 447 param |= (uint64_t)*wsp++ << (i * 8); 448 printf(" %-30s: %jd\n", kv_lookup(kv, kv_count, ptype), (uintmax_t)param); 449 } 450 } 451 452 static void 453 print_hgst_info_write_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) 454 { 455 static struct kv_name kv[] = 456 { 457 { 0x0000, "Corrected Without Delay" }, 458 { 0x0001, "Corrected Maybe Delayed" }, 459 { 0x0002, "Re-Writes" }, 460 { 0x0003, "Errors Corrected" }, 461 { 0x0004, "Correct Algorithm Used" }, 462 { 0x0005, "Bytes Processed" }, 463 { 0x0006, "Uncorrected Errors" }, 464 { 0x8000, "Flash Write Commands" }, 465 { 0x8001, "HGST Special" }, 466 }; 467 468 printf("Write Errors Subpage:\n"); 469 print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); 470 } 471 472 static void 473 print_hgst_info_read_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) 474 { 475 static struct kv_name kv[] = 476 { 477 { 0x0000, "Corrected Without Delay" }, 478 { 0x0001, "Corrected Maybe Delayed" }, 479 { 0x0002, "Re-Reads" }, 480 { 0x0003, "Errors Corrected" }, 481 { 0x0004, "Correct Algorithm Used" }, 482 { 0x0005, "Bytes Processed" }, 483 { 0x0006, "Uncorrected Errors" }, 484 { 0x8000, "Flash Read Commands" }, 485 { 0x8001, "XOR Recovered" }, 486 { 0x8002, "Total Corrected Bits" }, 487 }; 488 489 printf("Read Errors Subpage:\n"); 490 print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); 491 } 492 493 static void 494 print_hgst_info_verify_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) 495 { 496 static struct kv_name kv[] = 497 { 498 { 0x0000, "Corrected Without Delay" }, 499 { 0x0001, "Corrected Maybe Delayed" }, 500 { 0x0002, "Re-Reads" }, 501 { 0x0003, "Errors Corrected" }, 502 { 0x0004, "Correct Algorithm Used" }, 503 { 0x0005, "Bytes Processed" }, 504 { 0x0006, "Uncorrected Errors" }, 505 { 0x8000, "Commands Processed" }, 506 }; 507 508 printf("Verify Errors Subpage:\n"); 509 print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); 510 } 511 512 static void 513 print_hgst_info_self_test(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) 514 { 515 size_t i; 516 uint8_t *walker = buf; 517 uint16_t code, hrs; 518 uint32_t lba; 519 520 printf("Self Test Subpage:\n"); 521 for (i = 0; i < size / 20; i++) { /* Each entry is 20 bytes */ 522 code = le16dec(walker); 523 walker += 2; 524 walker++; /* Ignore fixed flags */ 525 if (*walker == 0) /* Last entry is zero length */ 526 break; 527 if (*walker++ != 0x10) { 528 printf("Bad length for self test report\n"); 529 return; 530 } 531 printf(" %-30s: %d\n", "Recent Test", code); 532 printf(" %-28s: %#x\n", "Self-Test Results", *walker & 0xf); 533 printf(" %-28s: %#x\n", "Self-Test Code", (*walker >> 5) & 0x7); 534 walker++; 535 printf(" %-28s: %#x\n", "Self-Test Number", *walker++); 536 hrs = le16dec(walker); 537 walker += 2; 538 lba = le32dec(walker); 539 walker += 4; 540 printf(" %-28s: %u\n", "Total Power On Hrs", hrs); 541 printf(" %-28s: %#jx (%jd)\n", "LBA", (uintmax_t)lba, (uintmax_t)lba); 542 printf(" %-28s: %#x\n", "Sense Key", *walker++ & 0xf); 543 printf(" %-28s: %#x\n", "Additional Sense Code", *walker++); 544 printf(" %-28s: %#x\n", "Additional Sense Qualifier", *walker++); 545 printf(" %-28s: %#x\n", "Vendor Specific Detail", *walker++); 546 } 547 } 548 549 static void 550 print_hgst_info_background_scan(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) 551 { 552 uint8_t *walker = buf; 553 uint8_t status; 554 uint16_t code, nscan, progress; 555 uint32_t pom, nand; 556 557 printf("Background Media Scan Subpage:\n"); 558 /* Decode the header */ 559 code = le16dec(walker); 560 walker += 2; 561 walker++; /* Ignore fixed flags */ 562 if (*walker++ != 0x10) { 563 printf("Bad length for background scan header\n"); 564 return; 565 } 566 if (code != 0) { 567 printf("Expceted code 0, found code %#x\n", code); 568 return; 569 } 570 pom = le32dec(walker); 571 walker += 4; 572 walker++; /* Reserved */ 573 status = *walker++; 574 nscan = le16dec(walker); 575 walker += 2; 576 progress = le16dec(walker); 577 walker += 2; 578 walker += 6; /* Reserved */ 579 printf(" %-30s: %d\n", "Power On Minutes", pom); 580 printf(" %-30s: %x (%s)\n", "BMS Status", status, 581 status == 0 ? "idle" : (status == 1 ? "active" : (status == 8 ? "suspended" : "unknown"))); 582 printf(" %-30s: %d\n", "Number of BMS", nscan); 583 printf(" %-30s: %d\n", "Progress Current BMS", progress); 584 /* Report retirements */ 585 if (walker - (uint8_t *)buf != 20) { 586 printf("Coding error, offset not 20\n"); 587 return; 588 } 589 size -= 20; 590 printf(" %-30s: %d\n", "BMS retirements", size / 0x18); 591 while (size > 0) { 592 code = le16dec(walker); 593 walker += 2; 594 walker++; 595 if (*walker++ != 0x14) { 596 printf("Bad length parameter\n"); 597 return; 598 } 599 pom = le32dec(walker); 600 walker += 4; 601 /* 602 * Spec sheet says the following are hard coded, if true, just 603 * print the NAND retirement. 604 */ 605 if (walker[0] == 0x41 && 606 walker[1] == 0x0b && 607 walker[2] == 0x01 && 608 walker[3] == 0x00 && 609 walker[4] == 0x00 && 610 walker[5] == 0x00 && 611 walker[6] == 0x00 && 612 walker[7] == 0x00) { 613 walker += 8; 614 walker += 4; /* Skip reserved */ 615 nand = le32dec(walker); 616 walker += 4; 617 printf(" %-30s: %d\n", "Retirement number", code); 618 printf(" %-28s: %#x\n", "NAND (C/T)BBBPPP", nand); 619 } else { 620 printf("Parameter %#x entry corrupt\n", code); 621 walker += 16; 622 } 623 } 624 } 625 626 static void 627 print_hgst_info_erase_errors(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) 628 { 629 static struct kv_name kv[] = 630 { 631 { 0x0000, "Corrected Without Delay" }, 632 { 0x0001, "Corrected Maybe Delayed" }, 633 { 0x0002, "Re-Erase" }, 634 { 0x0003, "Errors Corrected" }, 635 { 0x0004, "Correct Algorithm Used" }, 636 { 0x0005, "Bytes Processed" }, 637 { 0x0006, "Uncorrected Errors" }, 638 { 0x8000, "Flash Erase Commands" }, 639 { 0x8001, "Mfg Defect Count" }, 640 { 0x8002, "Grown Defect Count" }, 641 { 0x8003, "Erase Count -- User" }, 642 { 0x8004, "Erase Count -- System" }, 643 }; 644 645 printf("Erase Errors Subpage:\n"); 646 print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); 647 } 648 649 static void 650 print_hgst_info_erase_counts(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) 651 { 652 /* My drive doesn't export this -- so not coding up */ 653 printf("XXX: Erase counts subpage: %p, %#x %d\n", buf, subtype, size); 654 } 655 656 static void 657 print_hgst_info_temp_history(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size __unused) 658 { 659 uint8_t *walker = buf; 660 uint32_t min; 661 662 printf("Temperature History:\n"); 663 printf(" %-30s: %d C\n", "Current Temperature", *walker++); 664 printf(" %-30s: %d C\n", "Reference Temperature", *walker++); 665 printf(" %-30s: %d C\n", "Maximum Temperature", *walker++); 666 printf(" %-30s: %d C\n", "Minimum Temperature", *walker++); 667 min = le32dec(walker); 668 walker += 4; 669 printf(" %-30s: %d:%02d:00\n", "Max Temperature Time", min / 60, min % 60); 670 min = le32dec(walker); 671 walker += 4; 672 printf(" %-30s: %d:%02d:00\n", "Over Temperature Duration", min / 60, min % 60); 673 min = le32dec(walker); 674 walker += 4; 675 printf(" %-30s: %d:%02d:00\n", "Min Temperature Time", min / 60, min % 60); 676 } 677 678 static void 679 print_hgst_info_ssd_perf(void *buf, uint16_t subtype __unused, uint8_t res, uint32_t size __unused) 680 { 681 uint8_t *walker = buf; 682 uint64_t val; 683 684 printf("SSD Performance Subpage Type %d:\n", res); 685 val = le64dec(walker); 686 walker += 8; 687 printf(" %-30s: %ju\n", "Host Read Commands", val); 688 val = le64dec(walker); 689 walker += 8; 690 printf(" %-30s: %ju\n", "Host Read Blocks", val); 691 val = le64dec(walker); 692 walker += 8; 693 printf(" %-30s: %ju\n", "Host Cache Read Hits Commands", val); 694 val = le64dec(walker); 695 walker += 8; 696 printf(" %-30s: %ju\n", "Host Cache Read Hits Blocks", val); 697 val = le64dec(walker); 698 walker += 8; 699 printf(" %-30s: %ju\n", "Host Read Commands Stalled", val); 700 val = le64dec(walker); 701 walker += 8; 702 printf(" %-30s: %ju\n", "Host Write Commands", val); 703 val = le64dec(walker); 704 walker += 8; 705 printf(" %-30s: %ju\n", "Host Write Blocks", val); 706 val = le64dec(walker); 707 walker += 8; 708 printf(" %-30s: %ju\n", "Host Write Odd Start Commands", val); 709 val = le64dec(walker); 710 walker += 8; 711 printf(" %-30s: %ju\n", "Host Write Odd End Commands", val); 712 val = le64dec(walker); 713 walker += 8; 714 printf(" %-30s: %ju\n", "Host Write Commands Stalled", val); 715 val = le64dec(walker); 716 walker += 8; 717 printf(" %-30s: %ju\n", "NAND Read Commands", val); 718 val = le64dec(walker); 719 walker += 8; 720 printf(" %-30s: %ju\n", "NAND Read Blocks", val); 721 val = le64dec(walker); 722 walker += 8; 723 printf(" %-30s: %ju\n", "NAND Write Commands", val); 724 val = le64dec(walker); 725 walker += 8; 726 printf(" %-30s: %ju\n", "NAND Write Blocks", val); 727 val = le64dec(walker); 728 walker += 8; 729 printf(" %-30s: %ju\n", "NAND Read Before Writes", val); 730 } 731 732 static void 733 print_hgst_info_firmware_load(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size __unused) 734 { 735 uint8_t *walker = buf; 736 737 printf("Firmware Load Subpage:\n"); 738 printf(" %-30s: %d\n", "Firmware Downloads", le32dec(walker)); 739 } 740 741 static void 742 kv_indirect(void *buf, uint32_t subtype, uint8_t res, uint32_t size, struct subpage_print *sp, size_t nsp) 743 { 744 size_t i; 745 746 for (i = 0; i < nsp; i++, sp++) { 747 if (sp->key == subtype) { 748 sp->fn(buf, subtype, res, size); 749 return; 750 } 751 } 752 printf("No handler for page type %x\n", subtype); 753 } 754 755 static void 756 print_hgst_info_log(void *buf, uint32_t size __unused) 757 { 758 uint8_t *walker, *end, *subpage; 759 int pages; 760 uint16_t len; 761 uint8_t subtype, res; 762 763 printf("HGST Extra Info Log\n"); 764 printf("===================\n"); 765 766 walker = buf; 767 pages = *walker++; 768 walker++; 769 len = le16dec(walker); 770 walker += 2; 771 end = walker + len; /* Length is exclusive of this header */ 772 773 while (walker < end) { 774 subpage = walker + 4; 775 subtype = *walker++ & 0x3f; /* subtype */ 776 res = *walker++; /* Reserved */ 777 len = le16dec(walker); 778 walker += len + 2; /* Length, not incl header */ 779 if (walker > end) { 780 printf("Ooops! Off the end of the list\n"); 781 break; 782 } 783 kv_indirect(subpage, subtype, res, len, hgst_subpage, nitems(hgst_subpage)); 784 } 785 } 786 787 /* 788 * Table of log page printer / sizing. 789 * 790 * This includes Intel specific pages that are widely implemented. 791 * Make sure you keep all the pages of one vendor together so -v help 792 * lists all the vendors pages. 793 */ 794 static struct logpage_function { 795 uint8_t log_page; 796 const char *vendor; 797 const char *name; 798 print_fn_t print_fn; 799 size_t size; 800 } logfuncs[] = { 801 {NVME_LOG_ERROR, NULL, "Drive Error Log", 802 print_log_error, 0}, 803 {NVME_LOG_HEALTH_INFORMATION, NULL, "Health/SMART Data", 804 print_log_health, sizeof(struct nvme_health_information_page)}, 805 {NVME_LOG_FIRMWARE_SLOT, NULL, "Firmware Information", 806 print_log_firmware, sizeof(struct nvme_firmware_page)}, 807 {HGST_INFO_LOG, "hgst", "Detailed Health/SMART", 808 print_hgst_info_log, DEFAULT_SIZE}, 809 {HGST_INFO_LOG, "wds", "Detailed Health/SMART", 810 print_hgst_info_log, DEFAULT_SIZE}, 811 {INTEL_LOG_TEMP_STATS, "intel", "Temperature Stats", 812 print_intel_temp_stats, sizeof(struct intel_log_temp_stats)}, 813 {INTEL_LOG_READ_LAT_LOG, "intel", "Read Latencies", 814 print_intel_read_lat_log, DEFAULT_SIZE}, 815 {INTEL_LOG_WRITE_LAT_LOG, "intel", "Write Latencies", 816 print_intel_write_lat_log, DEFAULT_SIZE}, 817 {INTEL_LOG_ADD_SMART, "intel", "Extra Health/SMART Data", 818 print_intel_add_smart, DEFAULT_SIZE}, 819 {INTEL_LOG_ADD_SMART, "samsung", "Extra Health/SMART Data", 820 print_intel_add_smart, DEFAULT_SIZE}, 821 822 {0, NULL, NULL, NULL, 0}, 823 }; 824 825 static void 826 logpage_usage(void) 827 { 828 fprintf(stderr, "usage:\n"); 829 fprintf(stderr, LOGPAGE_USAGE); 830 exit(1); 831 } 832 833 static void 834 logpage_help(void) 835 { 836 struct logpage_function *f; 837 const char *v; 838 839 fprintf(stderr, "\n"); 840 fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name"); 841 fprintf(stderr, "-------- ---------- ----------\n"); 842 for (f = logfuncs; f->log_page > 0; f++) { 843 v = f->vendor == NULL ? "-" : f->vendor; 844 fprintf(stderr, "0x%02x %-10s %s\n", f->log_page, v, f->name); 845 } 846 847 exit(1); 848 } 849 850 void 851 logpage(int argc, char *argv[]) 852 { 853 int fd, nsid; 854 int log_page = 0, pageflag = false; 855 int binflag = false, hexflag = false, ns_specified; 856 char ch, *p; 857 char cname[64]; 858 uint32_t size; 859 void *buf; 860 const char *vendor = NULL; 861 struct logpage_function *f; 862 struct nvme_controller_data cdata; 863 print_fn_t print_fn; 864 865 while ((ch = getopt(argc, argv, "bp:xv:")) != -1) { 866 switch (ch) { 867 case 'b': 868 binflag = true; 869 break; 870 case 'p': 871 if (strcmp(optarg, "help") == 0) 872 logpage_help(); 873 874 /* TODO: Add human-readable ASCII page IDs */ 875 log_page = strtol(optarg, &p, 0); 876 if (p != NULL && *p != '\0') { 877 fprintf(stderr, 878 "\"%s\" not valid log page id.\n", 879 optarg); 880 logpage_usage(); 881 } 882 pageflag = true; 883 break; 884 case 'x': 885 hexflag = true; 886 break; 887 case 'v': 888 if (strcmp(optarg, "help") == 0) 889 logpage_help(); 890 vendor = optarg; 891 break; 892 } 893 } 894 895 if (!pageflag) { 896 printf("Missing page_id (-p).\n"); 897 logpage_usage(); 898 } 899 900 /* Check that a controller and/or namespace was specified. */ 901 if (optind >= argc) 902 logpage_usage(); 903 904 if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { 905 ns_specified = true; 906 parse_ns_str(argv[optind], cname, &nsid); 907 open_dev(cname, &fd, 1, 1); 908 } else { 909 ns_specified = false; 910 nsid = NVME_GLOBAL_NAMESPACE_TAG; 911 open_dev(argv[optind], &fd, 1, 1); 912 } 913 914 read_controller_data(fd, &cdata); 915 916 /* 917 * The log page attribtues indicate whether or not the controller 918 * supports the SMART/Health information log page on a per 919 * namespace basis. 920 */ 921 if (ns_specified) { 922 if (log_page != NVME_LOG_HEALTH_INFORMATION) 923 errx(1, "log page %d valid only at controller level", 924 log_page); 925 if (cdata.lpa.ns_smart == 0) 926 errx(1, 927 "controller does not support per namespace " 928 "smart/health information"); 929 } 930 931 print_fn = print_hex; 932 size = DEFAULT_SIZE; 933 if (binflag) 934 print_fn = print_bin; 935 if (!binflag && !hexflag) { 936 /* 937 * See if there is a pretty print function for the specified log 938 * page. If one isn't found, we just revert to the default 939 * (print_hex). If there was a vendor specified bt the user, and 940 * the page is vendor specific, don't match the print function 941 * unless the vendors match. 942 */ 943 for (f = logfuncs; f->log_page > 0; f++) { 944 if (f->vendor != NULL && vendor != NULL && 945 strcmp(f->vendor, vendor) != 0) 946 continue; 947 if (log_page != f->log_page) 948 continue; 949 print_fn = f->print_fn; 950 size = f->size; 951 break; 952 } 953 } 954 955 if (log_page == NVME_LOG_ERROR) { 956 size = sizeof(struct nvme_error_information_entry); 957 size *= (cdata.elpe + 1); 958 } 959 960 /* Read the log page */ 961 buf = get_log_buffer(size); 962 read_logpage(fd, log_page, nsid, buf, size); 963 print_fn(buf, size); 964 965 close(fd); 966 exit(0); 967 } 968