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