1 /* 2 * Copyright (c) 2016-2026 Chuck Tuffli <chuck@tuffli.net> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <stdbool.h> 19 #include <stddef.h> 20 #include <assert.h> 21 #include <err.h> 22 #include <string.h> 23 #include <sys/endian.h> 24 25 #ifdef LIBXO 26 #include <libxo/xo.h> 27 #endif 28 29 #include "libsmart.h" 30 #include "libsmart_priv.h" 31 #include "libsmart_dev.h" 32 33 /* Default page lists */ 34 35 static smart_page_list_t pg_list_ata = { 36 .pg_count = 2, 37 .pages = { 38 { .id = PAGE_ID_ATA_SMART_READ_DATA, .bytes = 512 }, 39 { .id = PAGE_ID_ATA_SMART_RET_STATUS, .bytes = 4 } 40 } 41 }; 42 43 #define PAGE_ID_NVME_SMART_HEALTH 0x02 44 45 static smart_page_list_t pg_list_nvme = { 46 .pg_count = 1, 47 .pages = { 48 { .id = PAGE_ID_NVME_SMART_HEALTH, .bytes = 512 } 49 } 50 }; 51 52 static smart_page_list_t pg_list_scsi = { 53 .pg_count = 8, 54 .pages = { 55 { .id = PAGE_ID_SCSI_WRITE_ERR, .bytes = 128 }, 56 { .id = PAGE_ID_SCSI_READ_ERR, .bytes = 128 }, 57 { .id = PAGE_ID_SCSI_VERIFY_ERR, .bytes = 128 }, 58 { .id = PAGE_ID_SCSI_NON_MEDIUM_ERR, .bytes = 128 }, 59 { .id = PAGE_ID_SCSI_LAST_N_ERR, .bytes = 128 }, 60 { .id = PAGE_ID_SCSI_TEMPERATURE, .bytes = 64 }, 61 { .id = PAGE_ID_SCSI_START_STOP_CYCLE, .bytes = 128 }, 62 { .id = PAGE_ID_SCSI_INFO_EXCEPTION, .bytes = 64 }, 63 } 64 }; 65 66 static uint32_t __smart_attribute_max(smart_buf_t *sb); 67 static uint32_t __smart_buffer_size(smart_h h); 68 static smart_map_t *__smart_map(smart_h h, smart_buf_t *sb); 69 static smart_page_list_t *__smart_page_list(smart_h h); 70 static int32_t __smart_read_pages(smart_h h, smart_buf_t *sb); 71 72 static const char * 73 smart_proto_str(smart_protocol_e p) 74 { 75 76 switch (p) { 77 case SMART_PROTO_AUTO: 78 return "auto"; 79 case SMART_PROTO_ATA: 80 return "ATA"; 81 case SMART_PROTO_SCSI: 82 return "SCSI"; 83 case SMART_PROTO_NVME: 84 return "NVME"; 85 default: 86 return "Unknown"; 87 } 88 } 89 90 smart_h 91 smart_open(smart_protocol_e protocol, char *devname) 92 { 93 smart_t *s; 94 95 s = device_open(protocol, devname); 96 97 if (s) { 98 dprintf("protocol %s (specified %s%s)\n", 99 smart_proto_str(s->protocol), 100 smart_proto_str(protocol), 101 s->info.tunneled ? ", tunneled ATA" : ""); 102 } 103 104 return s; 105 } 106 107 void 108 smart_close(smart_h h) 109 { 110 111 device_close(h); 112 } 113 114 bool 115 smart_supported(smart_h h) 116 { 117 smart_t *s = h; 118 bool supported = false; 119 120 if (s) { 121 supported = s->info.supported; 122 dprintf("SMART is %ssupported\n", supported ? "" : "not "); 123 } 124 125 return supported; 126 } 127 128 smart_map_t * 129 smart_read(smart_h h) 130 { 131 smart_t *s = h; 132 smart_buf_t *sb = NULL; 133 smart_map_t *sm = NULL; 134 135 sb = calloc(1, sizeof(smart_buf_t)); 136 if (sb) { 137 sb->protocol = s->protocol; 138 139 /* 140 * Need the page list to calculate the buffer size. If one 141 * isn't specified, get the default based on the protocol. 142 */ 143 if (s->pg_list == NULL) { 144 s->pg_list = __smart_page_list(s); 145 if (!s->pg_list) { 146 goto smart_read_out; 147 } 148 } 149 150 sb->b = NULL; 151 sb->bsize = __smart_buffer_size(s); 152 153 if (sb->bsize != 0) { 154 sb->b = malloc(sb->bsize); 155 } 156 157 if (sb->b == NULL) { 158 goto smart_read_out; 159 } 160 161 if (__smart_read_pages(s, sb) < 0) { 162 goto smart_read_out; 163 } 164 165 sb->attr_count = __smart_attribute_max(sb); 166 167 sm = __smart_map(h, sb); 168 if (!sm) { 169 free(sb->b); 170 free(sb); 171 sb = NULL; 172 } 173 } 174 175 smart_read_out: 176 if (!sm) { 177 if (sb) { 178 if (sb->b) { 179 free(sb->b); 180 } 181 182 free(sb); 183 } 184 } 185 186 return sm; 187 } 188 189 void 190 smart_free(smart_map_t *sm) 191 { 192 smart_buf_t *sb = NULL; 193 uint32_t i; 194 195 if (sm == NULL) 196 return; 197 198 sb = sm->sb; 199 200 if (sb) { 201 if (sb->b) { 202 free(sb->b); 203 sb->b = NULL; 204 } 205 206 free(sb); 207 } 208 209 for (i = 0; i < sm->count; i++) { 210 smart_map_t *tm = sm->attr[i].thresh; 211 212 if (tm) { 213 free(tm); 214 } 215 216 if (sm->attr[i].flags & SMART_ATTR_F_ALLOC) { 217 free((void *)(uintptr_t)sm->attr[i].description); 218 } 219 } 220 221 free(sm); 222 } 223 224 /* 225 * Format specifier for the various output types 226 * Provides versions to use with libxo and without 227 * TODO some of this is ATA specific 228 */ 229 #ifndef LIBXO 230 # define __smart_print_val(fmt, ...) printf(fmt, ##__VA_ARGS__) 231 # define VEND_STR "Vendor\t%s\n" 232 # define DEV_STR "Device\t%s\n" 233 # define REV_STR "Revision\t%s\n" 234 # define SERIAL_STR "Serial\t%s\n" 235 # define PAGE_HEX "%#01.1x\t" 236 # define PAGE_DEC "%d\t" 237 # define ID_HEX "%#01.1x\t" 238 # define ID_DEC "%d\t" 239 # define RAW_STR "%s" 240 # define RAW_HEX "%#01.1x" 241 # define RAW_DEC "%d" 242 /* Long integer version of the format macro */ 243 # define RAW_LHEX "%#01.1" PRIx64 244 # define RAW_LDEC "%" PRId64 245 # define THRESH_HEX "\t%#02.2x\t%#01.1x\t%#01.1x" 246 # define THRESH_DEC "\t%d\t%d\t%d" 247 # define DESC_STR "%s" 248 #else 249 # define __smart_print_val(fmt, ...) xo_emit(fmt, ##__VA_ARGS__) 250 # define VEND_STR "{L:Vendor}{P:\t}{:vendor/%s}\n" 251 # define DEV_STR "{L:Device}{P:\t}{:device/%s}\n" 252 # define REV_STR "{L:Revision}{P:\t}{:rev/%s}\n" 253 # define SERIAL_STR "{L:Serial}{P:\t}{:serial/%s}\n" 254 # define PAGE_HEX "{k:page/%#01.1x}{P:\t}" 255 # define PAGE_DEC "{k:page/%d}{P:\t}" 256 # define ID_HEX "{k:id/%#01.1x}{P:\t}" 257 # define ID_DEC "{k:id/%d}{P:\t}" 258 # define RAW_STR "{k:raw/%s}" 259 # define RAW_HEX "{k:raw/%#01.1x}" 260 # define RAW_DEC "{k:raw/%d}" 261 /* Long integer version of the format macro */ 262 # define RAW_LHEX "{k:raw/%#01.1" PRIx64 "}" 263 # define RAW_LDEC "{k:raw/%" PRId64 "}" 264 # define THRESH_HEX "{P:\t}{k:flags/%#02.2x}{P:\t}{k:nominal/%#01.1x}{P:\t}{k:worst/%#01.1x}" 265 # define THRESH_DEC "{P:\t}{k:flags/%d}{P:\t}{k:nominal/%d}{P:\t}{k:worst/%d}" 266 # define DESC_STR "{:description}{P:\t}" 267 #endif 268 269 #define THRESH_COUNT 3 270 271 272 /* Convert an 128-bit unsigned integer to a string */ 273 static char * 274 __smart_u128_str(smart_attr_t *sa) 275 { 276 /* Max size is log10(x) = log2(x) / log2(10) ~= log2(x) / 3.322 */ 277 #define MAX_LEN (128 / 3 + 1 + 1) 278 static char s[MAX_LEN]; 279 char *p = s + MAX_LEN - 1; 280 uint32_t *a = (uint32_t *)sa->raw; 281 uint64_t r, d; 282 283 *p-- = '\0'; 284 285 do { 286 r = a[3]; 287 288 d = r / 10; 289 r = ((r - d * 10) << 32) + a[2]; 290 a[3] = d; 291 292 d = r / 10; 293 r = ((r - d * 10) << 32) + a[1]; 294 a[2] = d; 295 296 d = r / 10; 297 r = ((r - d * 10) << 32) + a[0]; 298 a[1] = d; 299 300 d = r / 10; 301 r = r - d * 10; 302 a[0] = d; 303 304 *p-- = '0' + r; 305 } while (a[0] || a[1] || a[2] || a[3]); 306 307 p++; 308 309 while ((*p == '0') && (p < &s[sizeof(s) - 2])) 310 p++; 311 312 return p; 313 } 314 315 static void 316 __smart_print_thresh(smart_map_t *tm, uint32_t flags) 317 { 318 bool do_hex = false; 319 320 if (!tm) { 321 return; 322 } 323 324 if (flags & SMART_OPEN_F_HEX) 325 do_hex = true; 326 327 __smart_print_val(do_hex ? THRESH_HEX : THRESH_DEC, 328 *((uint16_t *)tm->attr[0].raw), 329 *((uint8_t *)tm->attr[1].raw), 330 *((uint8_t *)tm->attr[2].raw)); 331 } 332 333 /* Does the attribute match one requested by the caller? */ 334 static bool 335 __smart_attr_match(smart_matches_t *match, smart_attr_t *attr) 336 { 337 uint32_t i; 338 339 assert((match != NULL) && (attr != NULL)); 340 341 for (i = 0; i < match->count; i++) { 342 if ((match->m[i].page != -1) && ((uint32_t)match->m[i].page != attr->page)) 343 continue; 344 345 if ((uint32_t)match->m[i].id == attr->id) 346 return true; 347 } 348 349 return false; 350 } 351 352 void 353 smart_print(__attribute__((unused)) smart_h h, smart_map_t *sm, smart_matches_t *which, uint32_t flags) 354 { 355 uint32_t i; 356 bool do_hex = false, do_descr = false; 357 uint32_t bytes = 0; 358 359 if (!sm) { 360 return; 361 } 362 363 if (flags & SMART_OPEN_F_HEX) 364 do_hex = true; 365 if (flags & SMART_OPEN_F_DESCR) 366 do_descr = true; 367 368 #ifdef LIBXO 369 xo_open_container("attributes"); 370 xo_open_list("attribute"); 371 #endif 372 for (i = 0; i < sm->count; i++) { 373 /* If we're printing a specific attribute, is this it? */ 374 if ((which != NULL) && !__smart_attr_match(which, &sm->attr[i])) { 375 continue; 376 } 377 378 #ifdef LIBXO 379 xo_open_instance("attribute"); 380 #endif 381 /* Print the page / attribute ID if selecting all attributes */ 382 if (which == NULL) { 383 if (do_descr && (sm->attr[i].description != NULL)) 384 __smart_print_val(DESC_STR, sm->attr[i].description); 385 else { 386 __smart_print_val(do_hex ? PAGE_HEX : PAGE_DEC, sm->attr[i].page); 387 __smart_print_val(do_hex ? ID_HEX : ID_DEC, sm->attr[i].id); 388 } 389 } 390 391 bytes = sm->attr[i].bytes; 392 393 /* Print the attribute based on its size */ 394 if (sm->attr[i].flags & SMART_ATTR_F_STR) { 395 __smart_print_val(RAW_STR, (char *)sm->attr[i].raw); 396 } else if (bytes > 8) { 397 if (do_hex) 398 ; 399 else 400 __smart_print_val(RAW_STR, 401 __smart_u128_str(&sm->attr[i])); 402 403 } else if (bytes > 4) { 404 uint64_t v64 = 0; 405 uint64_t mask = UINT64_MAX; 406 407 memcpy(&v64, sm->attr[i].raw, bytes); 408 409 if (sm->attr[i].flags & SMART_ATTR_F_BE) { 410 v64 = be64toh(v64); 411 } else { 412 v64 = le64toh(v64); 413 } 414 415 mask >>= 8 * (sizeof(uint64_t) - bytes); 416 417 v64 &= mask; 418 419 __smart_print_val(do_hex ? RAW_LHEX : RAW_LDEC, v64); 420 421 } else if (bytes > 2) { 422 uint32_t v32 = 0; 423 uint32_t mask = UINT32_MAX; 424 425 memcpy(&v32, sm->attr[i].raw, bytes); 426 427 if (sm->attr[i].flags & SMART_ATTR_F_BE) { 428 v32 = be32toh(v32); 429 } else { 430 v32 = le32toh(v32); 431 } 432 433 mask >>= 8 * (sizeof(uint32_t) - bytes); 434 435 v32 &= mask; 436 437 __smart_print_val(do_hex ? RAW_HEX : RAW_DEC, v32); 438 439 } else if (bytes > 1) { 440 uint16_t v16 = 0; 441 uint16_t mask = UINT16_MAX; 442 443 memcpy(&v16, sm->attr[i].raw, bytes); 444 445 if (sm->attr[i].flags & SMART_ATTR_F_BE) { 446 v16 = be16toh(v16); 447 } else { 448 v16 = le16toh(v16); 449 } 450 451 mask >>= 8 * (sizeof(uint16_t) - bytes); 452 453 v16 &= mask; 454 455 __smart_print_val(do_hex ? RAW_HEX : RAW_DEC, v16); 456 457 } else if (bytes > 0) { 458 uint8_t v8 = *((uint8_t *)sm->attr[i].raw); 459 460 __smart_print_val(do_hex ? RAW_HEX : RAW_DEC, v8); 461 } 462 463 if ((flags & SMART_OPEN_F_THRESH) && sm->attr[i].thresh) { 464 xo_open_container("threshold"); 465 __smart_print_thresh(sm->attr[i].thresh, flags); 466 xo_close_container("threshold"); 467 } 468 469 __smart_print_val("\n"); 470 471 #ifdef LIBXO 472 xo_close_instance("attribute"); 473 #endif 474 } 475 #ifdef LIBXO 476 xo_close_list("attribute"); 477 xo_close_container("attributes"); 478 #endif 479 } 480 481 void 482 smart_print_device_info(smart_h h) 483 { 484 smart_t *s = h; 485 486 if (!s) { 487 return; 488 } 489 490 if (*s->info.vendor != '\0') 491 __smart_print_val(VEND_STR, s->info.vendor); 492 if (*s->info.device != '\0') 493 __smart_print_val(DEV_STR, s->info.device); 494 if (*s->info.rev != '\0') 495 __smart_print_val(REV_STR, s->info.device); 496 if (*s->info.serial != '\0') 497 __smart_print_val(SERIAL_STR, s->info.serial); 498 } 499 500 static uint32_t 501 __smart_attr_max_ata(smart_buf_t *sb) 502 { 503 uint32_t max = 0; 504 505 if (sb) { 506 max = 30; 507 } 508 509 return max; 510 } 511 512 static uint32_t 513 __smart_attr_max_nvme(smart_buf_t *sb) 514 { 515 uint32_t max = 0; 516 517 if (sb) { 518 max = 512; 519 } 520 521 return max; 522 } 523 524 static uint32_t 525 __smart_attr_max_scsi(smart_buf_t *sb) 526 { 527 uint32_t max = 0; 528 529 if (sb) { 530 max = 512; 531 } 532 533 return max; 534 } 535 536 static uint32_t 537 __smart_attribute_max(smart_buf_t *sb) 538 { 539 uint32_t count = 0; 540 541 if (sb != NULL) { 542 switch (sb->protocol) { 543 case SMART_PROTO_ATA: 544 count = __smart_attr_max_ata(sb); 545 break; 546 case SMART_PROTO_NVME: 547 count = __smart_attr_max_nvme(sb); 548 break; 549 case SMART_PROTO_SCSI: 550 count = __smart_attr_max_scsi(sb); 551 break; 552 default: 553 ; 554 } 555 } 556 557 return count; 558 } 559 560 /** 561 * Return the total buffer size needed by the protocol's page list 562 */ 563 static uint32_t 564 __smart_buffer_size(smart_h h) 565 { 566 smart_t *s = h; 567 uint32_t size = 0; 568 569 if ((s != NULL) && (s->pg_list != NULL)) { 570 smart_page_list_t *plist = s->pg_list; 571 uint32_t p = 0; 572 573 for (p = 0; p < plist->pg_count; p++) { 574 size += plist->pages[p].bytes; 575 } 576 } 577 578 return size; 579 } 580 581 /* 582 * Map SMART READ DATA threshold attributes 583 * 584 * Read the 3 consecutive values (flags, nominal, and worst) 585 */ 586 static smart_map_t * 587 __smart_map_ata_thresh(uint8_t *b) 588 { 589 smart_map_t *sm = NULL; 590 591 sm = malloc(sizeof(smart_map_t) + (THRESH_COUNT * sizeof(smart_attr_t))); 592 if (sm) { 593 uint32_t i; 594 595 sm->count = THRESH_COUNT; 596 597 sm->attr[0].page = 0; 598 sm->attr[0].id = 0; 599 sm->attr[0].bytes = 2; 600 sm->attr[0].flags = 0; 601 sm->attr[0].raw = b; 602 sm->attr[0].thresh = NULL; 603 604 b +=2; 605 606 for (i = 1; i < sm->count; i++) { 607 sm->attr[i].page = 0; 608 sm->attr[i].id = i; 609 sm->attr[i].bytes = 1; 610 sm->attr[i].flags = 0; 611 sm->attr[i].raw = b; 612 sm->attr[i].thresh = NULL; 613 614 b ++; 615 } 616 } 617 618 return sm; 619 } 620 621 /* 622 * Map SMART READ DATA attributes 623 * 624 * The format for the READ DATA buffer is: 625 * 2 bytes Revision 626 * 360 bytes Attributes (12 bytes each) 627 * 628 * Each attribute consists of: 629 * 1 byte ID 630 * 2 byte Status Flags 631 * 1 byte Nominal value 632 * 1 byte Worst value 633 * 7 byte Raw value 634 * Note that many attributes do not use the entire 7 bytes of the raw value. 635 */ 636 static void 637 __smart_map_ata_read_data(smart_map_t *sm, void *buf, size_t bsize) 638 { 639 uint8_t *b = NULL; 640 uint8_t *b_end = NULL; 641 uint32_t max_attr = 0; 642 uint32_t a; 643 644 max_attr = __smart_attr_max_ata(sm->sb); 645 a = sm->count; 646 647 b = buf; 648 649 /* skip revision */ 650 b += 2; 651 652 b_end = b + (max_attr * 12); 653 if (b_end > (b + bsize)) { 654 sm->count = 0; 655 return; 656 } 657 658 while (b < b_end) { 659 if (*b != 0) { 660 if ((a - sm->count) >= max_attr) { 661 warnx("More attributes (%d) than fit in map", 662 a - sm->count); 663 break; 664 } 665 666 sm->attr[a].page = PAGE_ID_ATA_SMART_READ_DATA; 667 sm->attr[a].id = b[0]; 668 sm->attr[a].description = __smart_ata_desc( 669 PAGE_ID_ATA_SMART_READ_DATA, sm->attr[a].id); 670 sm->attr[a].bytes = 7; 671 sm->attr[a].flags = 0; 672 sm->attr[a].raw = b + 5; 673 sm->attr[a].thresh = __smart_map_ata_thresh(b + 1); 674 675 a++; 676 } 677 678 b += 12; 679 } 680 681 sm->count = a; 682 } 683 684 static void 685 __smart_map_ata_return_status(smart_map_t *sm, void *buf) 686 { 687 uint8_t *b = NULL; 688 uint32_t a; 689 690 a = sm->count; 691 692 b = buf; 693 694 sm->attr[a].page = PAGE_ID_ATA_SMART_RET_STATUS; 695 sm->attr[a].id = 0; 696 sm->attr[a].description = __smart_ata_desc(PAGE_ID_ATA_SMART_RET_STATUS, 697 sm->attr[a].id); 698 sm->attr[a].bytes = 1; 699 sm->attr[a].flags = 0; 700 sm->attr[a].raw = b; 701 sm->attr[a].thresh = NULL; 702 703 a++; 704 705 sm->count = a; 706 } 707 708 static void 709 __smart_map_ata(smart_h h, smart_buf_t *sb, smart_map_t *sm) 710 { 711 smart_t *s = h; 712 smart_page_list_t *pg_list = NULL; 713 uint8_t *b = NULL; 714 uint32_t p; 715 716 pg_list = s->pg_list; 717 b = sb->b; 718 719 sm->count = 0; 720 721 for (p = 0; p < pg_list->pg_count; p++) { 722 switch (pg_list->pages[p].id) { 723 case PAGE_ID_ATA_SMART_READ_DATA: 724 __smart_map_ata_read_data(sm, b, pg_list->pages[p].bytes); 725 break; 726 case PAGE_ID_ATA_SMART_RET_STATUS: 727 __smart_map_ata_return_status(sm, b); 728 break; 729 } 730 731 b += pg_list->pages[p].bytes; 732 } 733 } 734 735 #ifndef ARRAYLEN 736 #define ARRAYLEN(p) sizeof(p)/sizeof(p[0]) 737 #endif 738 739 #define NVME_VS(mjr,mnr,ter) (((mjr) << 16) | ((mnr) << 8) | (ter)) 740 #define NVME_VS_1_0 NVME_VS(1,0,0) 741 #define NVME_VS_1_1 NVME_VS(1,1,0) 742 #define NVME_VS_1_2 NVME_VS(1,2,0) 743 #define NVME_VS_1_2_1 NVME_VS(1,2,1) 744 #define NVME_VS_1_3 NVME_VS(1,3,0) 745 #define NVME_VS_1_4 NVME_VS(1,4,0) 746 static struct { 747 uint32_t off; /* buffer offset */ 748 uint32_t bytes; /* size in bytes */ 749 uint32_t ver; /* first version available */ 750 const char *description; 751 } __smart_nvme_values[] = { 752 { 0, 1, NVME_VS_1_0, "Critical Warning" }, 753 { 1, 2, NVME_VS_1_0, "Composite Temperature" }, 754 { 3, 1, NVME_VS_1_0, "Available Spare" }, 755 { 4, 1, NVME_VS_1_0, "Available Spare Threshold" }, 756 { 5, 1, NVME_VS_1_0, "Percentage Used" }, 757 { 6, 1, NVME_VS_1_4, "Endurance Group Critical Warning Summary" }, 758 { 32, 16, NVME_VS_1_0, "Data Units Read" }, 759 { 48, 16, NVME_VS_1_0, "Data Units Written" }, 760 { 64, 16, NVME_VS_1_0, "Host Read Commands" }, 761 { 80, 16, NVME_VS_1_0, "Host Write Commands" }, 762 { 96, 16, NVME_VS_1_0, "Controller Busy Time" }, 763 { 112, 16, NVME_VS_1_0, "Power Cycles" }, 764 { 128, 16, NVME_VS_1_0, "Power On Hours" }, 765 { 144, 16, NVME_VS_1_0, "Unsafe Shutdowns" }, 766 { 160, 16, NVME_VS_1_0, "Media and Data Integrity Errors" }, 767 { 176, 16, NVME_VS_1_0, "Number of Error Information Log Entries" }, 768 { 192, 4, NVME_VS_1_2, "Warning Composite Temperature Time" }, 769 { 196, 4, NVME_VS_1_2, "Critical Composite Temperature Time" }, 770 { 200, 2, NVME_VS_1_2, "Temperature Sensor 1" }, 771 { 202, 2, NVME_VS_1_2, "Temperature Sensor 2" }, 772 { 204, 2, NVME_VS_1_2, "Temperature Sensor 3" }, 773 { 206, 2, NVME_VS_1_2, "Temperature Sensor 4" }, 774 { 208, 2, NVME_VS_1_2, "Temperature Sensor 5" }, 775 { 210, 2, NVME_VS_1_2, "Temperature Sensor 6" }, 776 { 212, 2, NVME_VS_1_2, "Temperature Sensor 7" }, 777 { 214, 2, NVME_VS_1_2, "Temperature Sensor 8" }, 778 { 216, 4, NVME_VS_1_3, "Thermal Management Temperature 1 Transition Count" }, 779 { 220, 4, NVME_VS_1_3, "Thermal Management Temperature 2 Transition Count" }, 780 { 224, 4, NVME_VS_1_3, "Total Time For Thermal Management Temperature 1" }, 781 { 228, 4, NVME_VS_1_3, "Total Time For Thermal Management Temperature 2" }, 782 }; 783 784 /** 785 * NVMe doesn't define attribute IDs like ATA does, but we can 786 * approximate this behavior by treating the byte offset as the 787 * attribute ID. 788 */ 789 static void 790 __smart_map_nvme(smart_buf_t *sb, smart_map_t *sm) 791 { 792 uint8_t *b = NULL; 793 uint32_t vs = NVME_VS_1_0; // XXX assume device is 1.0 794 uint32_t i, a; 795 796 sm->count = 0; 797 b = sb->b; 798 799 for (i = 0, a = 0; i < ARRAYLEN(__smart_nvme_values); i++) { 800 if (vs >= __smart_nvme_values[i].ver) { 801 sm->attr[a].page = 0x2; 802 sm->attr[a].id = __smart_nvme_values[i].off; 803 sm->attr[a].description = __smart_nvme_values[i].description; 804 sm->attr[a].bytes = __smart_nvme_values[i].bytes; 805 sm->attr[a].flags = 0; 806 sm->attr[a].raw = b + __smart_nvme_values[i].off; 807 sm->attr[a].thresh = NULL; 808 809 a++; 810 } 811 } 812 813 sm->count = a; 814 } 815 816 /* 817 * Create a SMART map for SCSI error counter pages 818 * 819 * Several SCSI log pages have a similar format for the error counter log 820 * pages 821 */ 822 static void 823 __smart_map_scsi_err_page(smart_map_t *sm, void *b) 824 { 825 struct scsi_err_page { 826 uint8_t page_code; 827 uint8_t subpage_code; 828 uint16_t page_length; 829 uint8_t param[]; 830 } __attribute__((packed)) *err = b; 831 struct scsi_err_counter_param { 832 uint16_t code; 833 uint8_t format:2, 834 tmc:2, 835 etc:1, 836 tsd:1, 837 :1, 838 du:1; 839 uint8_t length; 840 uint8_t counter[]; 841 } __attribute__((packed)) *param = NULL; 842 uint32_t a, p, page_length; 843 const char *cmd = NULL, *desc = NULL; 844 845 switch (err->page_code) { 846 case PAGE_ID_SCSI_WRITE_ERR: 847 cmd = "Write"; 848 break; 849 case PAGE_ID_SCSI_READ_ERR: 850 cmd = "Read"; 851 break; 852 case PAGE_ID_SCSI_VERIFY_ERR: 853 cmd = "Verify"; 854 break; 855 case PAGE_ID_SCSI_NON_MEDIUM_ERR: 856 cmd = "Non-Medium"; 857 break; 858 default: 859 fprintf(stderr, "Unknown command %#x\n", err->page_code); 860 cmd = "Unknown"; 861 break; 862 } 863 864 a = sm->count; 865 866 p = 0; 867 page_length = be16toh(err->page_length); 868 869 while (p < page_length) { 870 param = (struct scsi_err_counter_param *) (err->param + p); 871 872 sm->attr[a].page = err->page_code; 873 sm->attr[a].id = be16toh(param->code); 874 desc = __smart_scsi_err_desc(sm->attr[a].id); 875 if (desc != NULL) { 876 size_t bytes; 877 char *str; 878 879 bytes = snprintf(NULL, 0, "%s %s", cmd, desc); 880 str = malloc(bytes + 1); 881 if (str != NULL) { 882 snprintf(str, bytes + 1, "%s %s", cmd, desc); 883 sm->attr[a].description = str; 884 sm->attr[a].flags |= SMART_ATTR_F_ALLOC; 885 } 886 } 887 sm->attr[a].bytes = param->length; 888 sm->attr[a].flags = SMART_ATTR_F_BE; 889 sm->attr[a].raw = param->counter; 890 sm->attr[a].thresh = NULL; 891 892 p += 4 + param->length; 893 894 a++; 895 } 896 897 sm->count = a; 898 } 899 900 static void 901 __smart_map_scsi_last_err(smart_map_t *sm, void *b) 902 { 903 struct scsi_last_n_error_event_page { 904 uint8_t page_code:6, 905 spf:1, 906 ds:1; 907 uint8_t subpage_code; 908 uint16_t page_length; 909 uint8_t event[]; 910 } __attribute__((packed)) *lastn = b; 911 struct scsi_last_n_error_event { 912 uint16_t code; 913 uint8_t format:2, 914 tmc:2, 915 etc:1, 916 tsd:1, 917 :1, 918 du:1; 919 uint8_t length; 920 uint8_t data[]; 921 } __attribute__((packed)) *event = NULL; 922 uint32_t a, p, page_length; 923 924 a = sm->count; 925 926 p = 0; 927 page_length = be16toh(lastn->page_length); 928 929 while (p < page_length) { 930 event = (struct scsi_last_n_error_event *) (lastn->event + p); 931 932 sm->attr[a].page = lastn->page_code; 933 sm->attr[a].id = be16toh(event->code); 934 sm->attr[a].bytes = event->length; 935 sm->attr[a].flags = SMART_ATTR_F_BE; 936 sm->attr[a].raw = event->data; 937 sm->attr[a].thresh = NULL; 938 939 p += 4 + event->length; 940 941 a++; 942 } 943 944 sm->count = a; 945 } 946 947 static void 948 __smart_map_scsi_temp(smart_map_t *sm, void *b) 949 { 950 struct scsi_temperature_log_page { 951 uint8_t page_code; 952 uint8_t subpage_code; 953 uint16_t page_length; 954 struct scsi_temperature_log_entry { 955 uint16_t code; 956 uint8_t control; 957 uint8_t length; 958 uint8_t rsvd; 959 uint8_t temperature; 960 } param[]; 961 } __attribute__((packed)) *temp = b; 962 uint32_t a, p, count; 963 964 count = be16toh(temp->page_length) / sizeof(struct scsi_temperature_log_entry); 965 966 a = sm->count; 967 968 for (p = 0; p < count; p++) { 969 uint16_t code = be16toh(temp->param[p].code); 970 switch (code) { 971 case 0: 972 case 1: 973 sm->attr[a].page = temp->page_code; 974 sm->attr[a].id = be16toh(temp->param[p].code); 975 sm->attr[a].description = code == 0 ? "Temperature" : "Reference Temperature"; 976 sm->attr[a].bytes = 1; 977 sm->attr[a].flags = 0; 978 sm->attr[a].raw = &(temp->param[p].temperature); 979 sm->attr[a].thresh = NULL; 980 a++; 981 break; 982 default: 983 break; 984 } 985 } 986 987 sm->count = a; 988 } 989 990 static void 991 __smart_map_scsi_start_stop(smart_map_t *sm, void *b) 992 { 993 struct scsi_start_stop_page { 994 uint8_t page_code; 995 #define START_STOP_CODE_DATE_MFG 0x0001 996 #define START_STOP_CODE_DATE_ACCTN 0x0002 997 #define START_STOP_CODE_CYCLES_LIFE 0x0003 998 #define START_STOP_CODE_CYCLES_ACCUM 0x0004 999 #define START_STOP_CODE_LOAD_LIFE 0x0005 1000 #define START_STOP_CODE_LOAD_ACCUM 0x0006 1001 uint8_t subpage_code; 1002 uint16_t page_length; 1003 uint8_t param[]; 1004 } __attribute__((packed)) *sstop = b; 1005 struct scsi_start_stop_param { 1006 uint16_t code; 1007 uint8_t format:2, 1008 tmc:2, 1009 etc:1, 1010 tsd:1, 1011 :1, 1012 du:1; 1013 uint8_t length; 1014 uint8_t data[]; 1015 } __attribute__((packed)) *param; 1016 uint32_t a, p, page_length; 1017 1018 a = sm->count; 1019 1020 p = 0; 1021 page_length = be16toh(sstop->page_length); 1022 1023 while (p < page_length) { 1024 param = (struct scsi_start_stop_param *) (sstop->param + p); 1025 1026 sm->attr[a].page = sstop->page_code; 1027 sm->attr[a].id = be16toh(param->code); 1028 sm->attr[a].bytes = param->length; 1029 1030 switch (sm->attr[a].id) { 1031 case START_STOP_CODE_DATE_MFG: 1032 sm->attr[a].description = "Date of Manufacture"; 1033 sm->attr[a].flags = SMART_ATTR_F_STR; 1034 break; 1035 case START_STOP_CODE_DATE_ACCTN: 1036 sm->attr[a].description = "Accounting Date"; 1037 sm->attr[a].flags = SMART_ATTR_F_STR; 1038 break; 1039 case START_STOP_CODE_CYCLES_LIFE: 1040 sm->attr[a].description = "Specified Cycle Count Over Device Lifetime"; 1041 sm->attr[a].flags = SMART_ATTR_F_BE; 1042 break; 1043 case START_STOP_CODE_CYCLES_ACCUM: 1044 sm->attr[a].description = "Accumulated Start-Stop Cycles"; 1045 sm->attr[a].flags = SMART_ATTR_F_BE; 1046 break; 1047 case START_STOP_CODE_LOAD_LIFE: 1048 sm->attr[a].description = "Specified Load-Unload Count Over Device Lifetime"; 1049 sm->attr[a].flags = SMART_ATTR_F_BE; 1050 break; 1051 case START_STOP_CODE_LOAD_ACCUM: 1052 sm->attr[a].description = "Accumulated Load-Unload Cycles"; 1053 sm->attr[a].flags = SMART_ATTR_F_BE; 1054 break; 1055 } 1056 1057 sm->attr[a].raw = param->data; 1058 sm->attr[a].thresh = NULL; 1059 1060 p += 4 + param->length; 1061 1062 a++; 1063 } 1064 1065 sm->count = a; 1066 } 1067 1068 static void 1069 __smart_map_scsi_info_exception(smart_map_t *sm, void *b) 1070 { 1071 struct scsi_info_exception_log_page { 1072 uint8_t page_code; 1073 uint8_t subpage_code; 1074 uint16_t page_length; 1075 uint8_t param[]; 1076 } __attribute__((packed)) *ie = b; 1077 struct scsi_ie_param { 1078 uint16_t code; 1079 uint8_t control; 1080 uint8_t length; 1081 uint8_t asc; /* IE Additional Sense Code */ 1082 uint8_t ascq; /* IE Additional Sense Code Qualifier */ 1083 uint8_t temp_recent; 1084 uint8_t temp_trip_point; 1085 uint8_t temp_max; 1086 } __attribute__((packed)) *param; 1087 uint32_t a, p, page_length; 1088 1089 a = sm->count; 1090 1091 p = 0; 1092 page_length = be16toh(ie->page_length); 1093 1094 while (p < page_length) { 1095 param = (struct scsi_ie_param *)(ie->param + p); 1096 1097 p += 4 + param->length; 1098 1099 sm->attr[a].page = ie->page_code; 1100 sm->attr[a].id = offsetof(struct scsi_ie_param, asc); 1101 sm->attr[a].description = "Informational Exception ASC"; 1102 sm->attr[a].bytes = 1; 1103 sm->attr[a].flags = 0; 1104 sm->attr[a].raw = ¶m->asc; 1105 sm->attr[a].thresh = NULL; 1106 a++; 1107 1108 sm->attr[a].page = ie->page_code; 1109 sm->attr[a].id = offsetof(struct scsi_ie_param, ascq); 1110 sm->attr[a].description = "Informational Exception ASCQ"; 1111 sm->attr[a].bytes = 1; 1112 sm->attr[a].flags = 0; 1113 sm->attr[a].raw = ¶m->ascq; 1114 sm->attr[a].thresh = NULL; 1115 a++; 1116 1117 sm->attr[a].page = ie->page_code; 1118 sm->attr[a].id = offsetof(struct scsi_ie_param, temp_recent); 1119 sm->attr[a].description = "Informational Exception Most recent temperature"; 1120 sm->attr[a].bytes = 1; 1121 sm->attr[a].flags = 0; 1122 sm->attr[a].raw = ¶m->temp_recent; 1123 sm->attr[a].thresh = NULL; 1124 a++; 1125 1126 sm->attr[a].page = ie->page_code; 1127 sm->attr[a].id = offsetof(struct scsi_ie_param, temp_trip_point); 1128 sm->attr[a].description = "Informational Exception Vendor HDA temperature trip point"; 1129 sm->attr[a].bytes = 1; 1130 sm->attr[a].flags = 0; 1131 sm->attr[a].raw = ¶m->temp_trip_point; 1132 sm->attr[a].thresh = NULL; 1133 a++; 1134 1135 sm->attr[a].page = ie->page_code; 1136 sm->attr[a].id = offsetof(struct scsi_ie_param, temp_max); 1137 sm->attr[a].description = "Informational Exception Maximum temperature"; 1138 sm->attr[a].bytes = 1; 1139 sm->attr[a].flags = 0; 1140 sm->attr[a].raw = ¶m->temp_max; 1141 sm->attr[a].thresh = NULL; 1142 a++; 1143 } 1144 1145 sm->count = a; 1146 } 1147 1148 /* 1149 * Create a map based on the page list 1150 */ 1151 static void 1152 __smart_map_scsi(smart_h h, smart_buf_t *sb, smart_map_t *sm) 1153 { 1154 smart_t *s = h; 1155 smart_page_list_t *pg_list = NULL; 1156 uint8_t *b = NULL; 1157 uint32_t p; 1158 1159 pg_list = s->pg_list; 1160 b = sb->b; 1161 1162 sm->count = 0; 1163 1164 for (p = 0; p < pg_list->pg_count; p++) { 1165 switch (pg_list->pages[p].id) { 1166 case PAGE_ID_SCSI_WRITE_ERR: 1167 case PAGE_ID_SCSI_READ_ERR: 1168 case PAGE_ID_SCSI_VERIFY_ERR: 1169 case PAGE_ID_SCSI_NON_MEDIUM_ERR: 1170 __smart_map_scsi_err_page(sm, b); 1171 break; 1172 case PAGE_ID_SCSI_LAST_N_ERR: 1173 __smart_map_scsi_last_err(sm, b); 1174 break; 1175 case PAGE_ID_SCSI_TEMPERATURE: 1176 __smart_map_scsi_temp(sm, b); 1177 break; 1178 case PAGE_ID_SCSI_START_STOP_CYCLE: 1179 __smart_map_scsi_start_stop(sm, b); 1180 break; 1181 case PAGE_ID_SCSI_INFO_EXCEPTION: 1182 __smart_map_scsi_info_exception(sm, b); 1183 break; 1184 } 1185 1186 b += pg_list->pages[p].bytes; 1187 } 1188 } 1189 1190 /** 1191 * Create a map of SMART values 1192 */ 1193 static void 1194 __smart_attribute_map(smart_h h, smart_buf_t *sb, smart_map_t *sm) 1195 { 1196 1197 if (!sb || !sm) { 1198 return; 1199 } 1200 1201 switch (sb->protocol) { 1202 case SMART_PROTO_ATA: 1203 __smart_map_ata(h, sb, sm); 1204 break; 1205 case SMART_PROTO_NVME: 1206 __smart_map_nvme(sb, sm); 1207 break; 1208 case SMART_PROTO_SCSI: 1209 __smart_map_scsi(h, sb, sm); 1210 break; 1211 default: 1212 sm->count = 0; 1213 } 1214 } 1215 1216 static smart_map_t * 1217 __smart_map(smart_h h, smart_buf_t *sb) 1218 { 1219 smart_map_t *sm = NULL; 1220 uint32_t max = 0; 1221 1222 max = sb->attr_count; 1223 if (max == 0) { 1224 warnx("Attribute count is zero?!?"); 1225 return NULL; 1226 } 1227 1228 sm = malloc(sizeof(smart_map_t) + (max * sizeof(smart_attr_t))); 1229 if (sm) { 1230 memset(sm, 0, sizeof(smart_map_t) + (max * sizeof(smart_attr_t))); 1231 sm->sb = sb; 1232 1233 /* count starts as the max but is adjusted to reflect the actual number */ 1234 sm->count = max; 1235 1236 __smart_attribute_map(h, sb, sm); 1237 } 1238 1239 return sm; 1240 } 1241 1242 typedef struct { 1243 uint8_t page_code; 1244 uint8_t subpage_code; 1245 uint16_t page_length; 1246 uint8_t supported_pages[]; 1247 } __attribute__((packed)) scsi_supported_log_pages; 1248 1249 static smart_page_list_t * 1250 __smart_page_list_scsi(smart_t *s) 1251 { 1252 smart_page_list_t *pg_list = NULL; 1253 scsi_supported_log_pages *b = NULL; 1254 uint32_t bsize = 68; /* 4 byte header + 63 entries + 1 just cuz */ 1255 int32_t rc; 1256 1257 b = malloc(bsize); 1258 if (!b) { 1259 return NULL; 1260 } 1261 1262 /* Supported Pages page ID is 0 */ 1263 rc = device_read_log(s, PAGE_ID_SCSI_SUPPORTED_PAGES, (uint8_t *)b, 1264 bsize); 1265 if (rc < 0) { 1266 fprintf(stderr, "Read Supported Log Pages failed\n"); 1267 } else { 1268 uint8_t *supported_page = b->supported_pages; 1269 uint32_t n_supported = be16toh(b->page_length); 1270 uint32_t pg, p, pmax = pg_list_scsi.pg_count; 1271 1272 /* Build a page list using only pages the device supports */ 1273 pg_list = malloc(sizeof(pg_list_scsi)); 1274 if (pg_list == NULL) { 1275 n_supported = 0; 1276 } else { 1277 pg_list->pg_count = 0; 1278 } 1279 1280 /* 1281 * Loop through all supported pages looking for those related 1282 * to SMART. The below assumes the supported page list from the 1283 * device and in pg_lsit_scsi are sorted in increasing order. 1284 */ 1285 dprintf("Supported SCSI pages:\n"); 1286 for (pg = 0, p = 0; (pg < n_supported) && (p < pmax); pg++) { 1287 dprintf("\t[%u] = %#x\n", pg, supported_page[pg]); 1288 while ((supported_page[pg] > pg_list_scsi.pages[p].id) && 1289 (p < pmax)) { 1290 p++; 1291 } 1292 1293 if (supported_page[pg] == pg_list_scsi.pages[p].id) { 1294 pg_list->pages[pg_list->pg_count] = pg_list_scsi.pages[p]; 1295 pg_list->pg_count++; 1296 p++; 1297 } 1298 } 1299 } 1300 1301 free(b); 1302 1303 return pg_list; 1304 } 1305 1306 static smart_page_list_t * 1307 __smart_page_list(smart_h h) 1308 { 1309 smart_t *s = h; 1310 smart_page_list_t *pg_list = NULL; 1311 1312 if (!s) { 1313 return NULL; 1314 } 1315 1316 switch (s->protocol) { 1317 case SMART_PROTO_ATA: 1318 pg_list = &pg_list_ata; 1319 break; 1320 case SMART_PROTO_NVME: 1321 pg_list = &pg_list_nvme; 1322 break; 1323 case SMART_PROTO_SCSI: 1324 pg_list = __smart_page_list_scsi(s); 1325 break; 1326 default: 1327 pg_list = NULL; 1328 } 1329 1330 return pg_list; 1331 } 1332 1333 static int32_t 1334 __smart_read_pages(smart_h h, smart_buf_t *sb) 1335 { 1336 smart_t *s = h; 1337 smart_page_list_t *plist = NULL; 1338 uint8_t *buf = NULL; 1339 int32_t rc = 0; 1340 uint32_t p = 0; 1341 1342 plist = s->pg_list; 1343 1344 buf = sb->b; 1345 1346 for (p = 0; p < s->pg_list->pg_count; p++) { 1347 memset(buf, 0, plist->pages[p].bytes); 1348 rc = device_read_log(h, plist->pages[p].id, buf, plist->pages[p].bytes); 1349 if (rc) { 1350 dprintf("bad read (%d) from page %#x (bytes=%zu)\n", rc, 1351 plist->pages[p].id, plist->pages[p].bytes); 1352 break; 1353 } 1354 1355 buf += plist->pages[p].bytes; 1356 } 1357 1358 return rc; 1359 } 1360