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