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