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