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