1 /* $NetBSD: atactl.c,v 1.34 2004/10/08 18:53:42 soren Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Ken Hornstein. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * atactl(8) - a program to control ATA devices. 41 */ 42 #include <sys/cdefs.h> 43 44 #ifndef lint 45 __RCSID("$NetBSD: atactl.c,v 1.34 2004/10/08 18:53:42 soren Exp $"); 46 #endif 47 48 49 #include <sys/param.h> 50 #include <sys/ioctl.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <unistd.h> 58 #include <util.h> 59 60 #include <dev/ata/atareg.h> 61 #include <sys/ataio.h> 62 63 struct ata_smart_error { 64 struct { 65 u_int8_t device_control; 66 u_int8_t features; 67 u_int8_t sector_count; 68 u_int8_t sector_number; 69 u_int8_t cylinder_low; 70 u_int8_t cylinder_high; 71 u_int8_t device_head; 72 u_int8_t command; 73 u_int8_t timestamp[4]; 74 } command[5]; 75 struct { 76 u_int8_t reserved; 77 u_int8_t error; 78 u_int8_t sector_count; 79 u_int8_t sector_number; 80 u_int8_t cylinder_low; 81 u_int8_t cylinder_high; 82 u_int8_t device_head; 83 u_int8_t status; 84 u_int8_t extended_error[19]; 85 u_int8_t state; 86 u_int8_t lifetime[2]; 87 } error_data; 88 } __attribute__((packed)); 89 90 struct ata_smart_errorlog { 91 u_int8_t data_structure_revision; 92 u_int8_t mostrecenterror; 93 struct ata_smart_error log_entries[5]; 94 u_int16_t device_error_count; 95 u_int8_t reserved[57]; 96 u_int8_t checksum; 97 } __attribute__((packed)); 98 99 struct command { 100 const char *cmd_name; 101 const char *arg_names; 102 void (*cmd_func)(int, char *[]); 103 }; 104 105 struct bitinfo { 106 u_int bitmask; 107 const char *string; 108 }; 109 110 int main(int, char *[]); 111 void usage(void); 112 void ata_command(struct atareq *); 113 void print_bitinfo(const char *, const char *, u_int, struct bitinfo *); 114 void print_bitinfo2(const char *, const char *, u_int, u_int, struct bitinfo *); 115 void print_smart_status(void *, void *); 116 void print_error_entry(int, struct ata_smart_error *); 117 void print_selftest_entry(int, struct ata_smart_selftest *); 118 119 void print_error(void *); 120 void print_selftest(void *); 121 122 int is_smart(void); 123 124 int fd; /* file descriptor for device */ 125 const char *dvname; /* device name */ 126 char dvname_store[MAXPATHLEN]; /* for opendisk(3) */ 127 const char *cmdname; /* command user issued */ 128 const char *argnames; /* helpstring: expected arguments */ 129 130 void device_identify(int, char *[]); 131 void device_setidle(int, char *[]); 132 void device_idle(int, char *[]); 133 void device_checkpower(int, char *[]); 134 void device_smart(int, char *[]); 135 136 void device_smart_temp(struct ata_smart_attr *, uint64_t); 137 138 struct command device_commands[] = { 139 { "identify", "", device_identify }, 140 { "setidle", "idle-timer", device_setidle }, 141 { "setstandby", "standby-timer", device_setidle }, 142 { "idle", "", device_idle }, 143 { "standby", "", device_idle }, 144 { "sleep", "", device_idle }, 145 { "checkpower", "", device_checkpower }, 146 { "smart", "enable|disable|status|offline #|error-log|selftest-log", 147 device_smart }, 148 { NULL, NULL, NULL }, 149 }; 150 151 void bus_reset __P((int, char *[])); 152 153 struct command bus_commands[] = { 154 { "reset", "", bus_reset }, 155 { NULL, NULL, NULL }, 156 }; 157 158 /* 159 * Tables containing bitmasks used for error reporting and 160 * device identification. 161 */ 162 163 struct bitinfo ata_caps[] = { 164 { WDC_CAP_DMA, "DMA" }, 165 { WDC_CAP_LBA, "LBA" }, 166 { ATA_CAP_STBY, "ATA standby timer values" }, 167 { WDC_CAP_IORDY, "IORDY operation" }, 168 { WDC_CAP_IORDY_DSBL, "IORDY disabling" }, 169 { 0, NULL }, 170 }; 171 172 struct bitinfo ata_vers[] = { 173 { WDC_VER_ATA1, "ATA-1" }, 174 { WDC_VER_ATA2, "ATA-2" }, 175 { WDC_VER_ATA3, "ATA-3" }, 176 { WDC_VER_ATA4, "ATA-4" }, 177 { WDC_VER_ATA5, "ATA-5" }, 178 { WDC_VER_ATA6, "ATA-6" }, 179 { WDC_VER_ATA7, "ATA-7" }, 180 { 0, NULL }, 181 }; 182 183 struct bitinfo ata_cmd_set1[] = { 184 { WDC_CMD1_NOP, "NOP command" }, 185 { WDC_CMD1_RB, "READ BUFFER command" }, 186 { WDC_CMD1_WB, "WRITE BUFFER command" }, 187 { WDC_CMD1_HPA, "Host Protected Area feature set" }, 188 { WDC_CMD1_DVRST, "DEVICE RESET command" }, 189 { WDC_CMD1_SRV, "SERVICE interrupt" }, 190 { WDC_CMD1_RLSE, "release interrupt" }, 191 { WDC_CMD1_AHEAD, "look-ahead" }, 192 { WDC_CMD1_CACHE, "write cache" }, 193 { WDC_CMD1_PKT, "PACKET command feature set" }, 194 { WDC_CMD1_PM, "Power Management feature set" }, 195 { WDC_CMD1_REMOV, "Removable Media feature set" }, 196 { WDC_CMD1_SEC, "Security Mode feature set" }, 197 { WDC_CMD1_SMART, "SMART feature set" }, 198 { 0, NULL }, 199 }; 200 201 struct bitinfo ata_cmd_set2[] = { 202 { ATA_CMD2_FCE, "FLUSH CACHE EXT command" }, 203 { WDC_CMD2_FC, "FLUSH CACHE command" }, 204 { WDC_CMD2_DCO, "Device Configuration Overlay feature set" }, 205 { ATA_CMD2_LBA48, "48-bit Address feature set" }, 206 { WDC_CMD2_AAM, "Automatic Acoustic Management feature set" }, 207 { WDC_CMD2_SM, "SET MAX security extension" }, 208 { WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" }, 209 { WDC_CMD2_PUIS, "Power-Up In Standby feature set" }, 210 { WDC_CMD2_RMSN, "Removable Media Status Notification feature set" }, 211 { ATA_CMD2_APM, "Advanced Power Management feature set" }, 212 { ATA_CMD2_CFA, "CFA feature set" }, 213 { ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" }, 214 { WDC_CMD2_DM, "DOWNLOAD MICROCODE command" }, 215 { 0, NULL }, 216 }; 217 218 struct bitinfo ata_cmd_ext[] = { 219 { ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" }, 220 { ATA_CMDE_TL, "Time-limited Read/Write" }, 221 { ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" }, 222 { ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" }, 223 { ATA_CMDE_WWN, "World Wide name" }, 224 { ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" }, 225 { ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" }, 226 { ATA_CMDE_GPL, "General Purpose Logging feature set" }, 227 { ATA_CMDE_STREAM, "Streaming feature set" }, 228 { ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" }, 229 { ATA_CMDE_MS, "Media serial number" }, 230 { ATA_CMDE_SST, "SMART self-test" }, 231 { ATA_CMDE_SEL, "SMART error logging" }, 232 { 0, NULL }, 233 }; 234 235 static const struct { 236 const int id; 237 const char *name; 238 void (*special)(struct ata_smart_attr *, uint64_t); 239 } smart_attrs[] = { 240 { 1, "Raw read error rate" }, 241 { 2, "Throughput performance" }, 242 { 3, "Spin-up time" }, 243 { 4, "Start/stop count" }, 244 { 5, "Reallocated sector count" }, 245 { 7, "Seek error rate" }, 246 { 8, "Seek time performance" }, 247 { 9, "Power-on hours count" }, 248 { 10, "Spin retry count" }, 249 { 11, "Calibration retry count" }, 250 { 12, "Device power cycle count" }, 251 { 191, "Gsense error rate" }, 252 { 192, "Power-off retract count" }, 253 { 193, "Load cycle count" }, 254 { 194, "Temperature", device_smart_temp}, 255 { 195, "Hardware ECC Recovered" }, 256 { 196, "Reallocated event count" }, 257 { 197, "Current pending sector" }, 258 { 198, "Offline uncorrectable" }, 259 { 199, "Ultra DMA CRC error count" }, 260 { 200, "Write error rate" }, 261 { 201, "Soft read error rate" }, 262 { 202, "Data address mark errors" }, 263 { 203, "Run out cancel" }, 264 { 204, "Soft ECC correction" }, 265 { 205, "Thermal asperity check" }, 266 { 206, "Flying height" }, 267 { 207, "Spin high current" }, 268 { 208, "Spin buzz" }, 269 { 209, "Offline seek performance" }, 270 { 220, "Disk shift" }, 271 { 221, "G-Sense error rate" }, 272 { 222, "Loaded hours" }, 273 { 223, "Load/unload retry count" }, 274 { 224, "Load friction" }, 275 { 225, "Load/unload cycle count" }, 276 { 226, "Load-in time" }, 277 { 227, "Torque amplification count" }, 278 { 228, "Power-off retract count" }, 279 { 230, "GMR head amplitude" }, 280 { 231, "Temperature", device_smart_temp }, 281 { 240, "Head flying hours" }, 282 { 250, "Read error retry rate" }, 283 { 0, "Unknown" }, 284 }; 285 286 int 287 main(int argc, char *argv[]) 288 { 289 int i; 290 struct command *commands = NULL; 291 292 /* Must have at least: device command */ 293 if (argc < 3) 294 usage(); 295 296 /* Skip program name, get and skip device name and command. */ 297 dvname = argv[1]; 298 cmdname = argv[2]; 299 argv += 3; 300 argc -= 3; 301 302 /* 303 * Open the device 304 */ 305 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0); 306 if (fd == -1) { 307 if (errno == ENOENT) { 308 /* 309 * Device doesn't exist. Probably trying to open 310 * a device which doesn't use disk semantics for 311 * device name. Try again, specifying "cooked", 312 * which leaves off the "r" in front of the device's 313 * name. 314 */ 315 fd = opendisk(dvname, O_RDWR, dvname_store, 316 sizeof(dvname_store), 1); 317 if (fd == -1) 318 err(1, "%s", dvname); 319 } else 320 err(1, "%s", dvname); 321 } 322 323 /* 324 * Point the dvname at the actual device name that opendisk() opened. 325 */ 326 dvname = dvname_store; 327 328 /* Look up and call the command. */ 329 for (i = 0; device_commands[i].cmd_name != NULL; i++) { 330 if (strcmp(cmdname, device_commands[i].cmd_name) == 0) { 331 commands = &device_commands[i]; 332 break; 333 } 334 } 335 if (commands == NULL) { 336 for (i = 0; bus_commands[i].cmd_name != NULL; i++) { 337 if (strcmp(cmdname, bus_commands[i].cmd_name) == 0) { 338 commands = &bus_commands[i]; 339 break; 340 } 341 } 342 } 343 if (commands == NULL) 344 errx(1, "unknown command: %s", cmdname); 345 346 argnames = commands->arg_names; 347 348 (*commands->cmd_func)(argc, argv); 349 exit(0); 350 } 351 352 void 353 usage(void) 354 { 355 int i; 356 357 fprintf(stderr, "usage: %s device command [arg [...]]\n", 358 getprogname()); 359 360 fprintf(stderr, " Available device commands:\n"); 361 for (i=0; device_commands[i].cmd_name != NULL; i++) 362 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name, 363 device_commands[i].arg_names); 364 365 fprintf(stderr, " Available bus commands:\n"); 366 for (i=0; bus_commands[i].cmd_name != NULL; i++) 367 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name, 368 bus_commands[i].arg_names); 369 370 exit(1); 371 } 372 373 /* 374 * Wrapper that calls ATAIOCCOMMAND and checks for errors 375 */ 376 377 void 378 ata_command(struct atareq *req) 379 { 380 int error; 381 382 error = ioctl(fd, ATAIOCCOMMAND, req); 383 384 if (error == -1) 385 err(1, "ATAIOCCOMMAND failed"); 386 387 switch (req->retsts) { 388 389 case ATACMD_OK: 390 return; 391 case ATACMD_TIMEOUT: 392 fprintf(stderr, "ATA command timed out\n"); 393 exit(1); 394 case ATACMD_DF: 395 fprintf(stderr, "ATA device returned a Device Fault\n"); 396 exit(1); 397 case ATACMD_ERROR: 398 if (req->error & WDCE_ABRT) 399 fprintf(stderr, "ATA device returned Aborted " 400 "Command\n"); 401 else 402 fprintf(stderr, "ATA device returned error register " 403 "%0x\n", req->error); 404 exit(1); 405 default: 406 fprintf(stderr, "ATAIOCCOMMAND returned unknown result code " 407 "%d\n", req->retsts); 408 exit(1); 409 } 410 } 411 412 /* 413 * Print out strings associated with particular bitmasks 414 */ 415 416 void 417 print_bitinfo(const char *bf, const char *af, u_int bits, struct bitinfo *binfo) 418 { 419 420 for (; binfo->bitmask != 0; binfo++) 421 if (bits & binfo->bitmask) 422 printf("%s%s%s", bf, binfo->string, af); 423 } 424 425 void 426 print_bitinfo2(const char *bf, const char *af, u_int bits, u_int enables, struct bitinfo *binfo) 427 { 428 429 for (; binfo->bitmask != 0; binfo++) 430 if (bits & binfo->bitmask) 431 printf("%s%s (%s)%s", bf, binfo->string, 432 (enables & binfo->bitmask) ? "enabled" : "disabled", 433 af); 434 } 435 436 437 /* 438 * Try to print SMART temperature field 439 */ 440 441 void 442 device_smart_temp(struct ata_smart_attr *attr, uint64_t raw_value) 443 { 444 printf("%" PRIu8, attr->raw[0]); 445 if (attr->raw[0] != raw_value) 446 printf(" Lifetime max/min %" PRIu8 "/%" PRIu8, 447 attr->raw[2], attr->raw[4]); 448 } 449 450 451 /* 452 * Print out SMART attribute thresholds and values 453 */ 454 455 void 456 print_smart_status(void *vbuf, void *tbuf) 457 { 458 struct ata_smart_attributes *value_buf = vbuf; 459 struct ata_smart_thresholds *threshold_buf = tbuf; 460 struct ata_smart_attr *attr; 461 uint64_t raw_value; 462 int flags; 463 int i, j; 464 int aid; 465 u_int8_t checksum; 466 467 for (i = checksum = 0; i < 512; i++) 468 checksum += ((u_int8_t *) value_buf)[i]; 469 if (checksum != 0) { 470 fprintf(stderr, "SMART attribute values checksum error\n"); 471 return; 472 } 473 474 for (i = checksum = 0; i < 512; i++) 475 checksum += ((u_int8_t *) threshold_buf)[i]; 476 if (checksum != 0) { 477 fprintf(stderr, "SMART attribute thresholds checksum error\n"); 478 return; 479 } 480 481 printf("id value thresh crit collect reliability description\t\t\traw\n"); 482 for (i = 0; i < 256; i++) { 483 int thresh = 0; 484 485 attr = NULL; 486 487 for (j = 0; j < 30; j++) { 488 if (value_buf->attributes[j].id == i) 489 attr = &value_buf->attributes[j]; 490 if (threshold_buf->thresholds[j].id == i) 491 thresh = threshold_buf->thresholds[j].value; 492 } 493 494 if (thresh && attr == NULL) 495 errx(1, "threshold but not attr %d", i); 496 if (attr == NULL) 497 continue; 498 499 if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF) 500 continue; 501 502 for (aid = 0; 503 smart_attrs[aid].id != i && smart_attrs[aid].id != 0; 504 aid++) 505 ; 506 507 flags = attr->flags; 508 509 printf("%3d %3d %3d %-3s %-7s %stive %-24s\t", 510 i, attr->value, thresh, 511 flags & WDSM_ATTR_ADVISORY ? "yes" : "no", 512 flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline", 513 attr->value > thresh ? "posi" : "nega", 514 smart_attrs[aid].name); 515 516 for (j = 0, raw_value = 0; j < 6; j++) 517 raw_value += ((uint64_t)attr->raw[j]) << (8*j); 518 519 if (smart_attrs[aid].special) 520 (*smart_attrs[aid].special)(attr, raw_value); 521 else 522 printf("%" PRIu64, raw_value); 523 printf("\n"); 524 } 525 } 526 527 struct { 528 int number; 529 const char *name; 530 } selftest_name[] = { 531 { 0, "Off-line" }, 532 { 1, "Short off-line" }, 533 { 2, "Extended off-line" }, 534 { 127, "Abort off-line test" }, 535 { 129, "Short captive" }, 536 { 130, "Extended captive" }, 537 { 256, "Unknown test" }, /* larger then u_int8_t */ 538 { 0, NULL } 539 }; 540 541 const char *selftest_status[] = { 542 "No error", 543 "Aborted by the host", 544 "Interruped by the host by reset", 545 "Fatal error or unknown test error", 546 "Unknown test element failed", 547 "Electrical test element failed", 548 "The Servo (and/or seek) test element failed", 549 "Read element of test failed", 550 "Reserved", 551 "Reserved", 552 "Reserved", 553 "Reserved", 554 "Reserved", 555 "Reserved", 556 "Reserved", 557 "Self-test in progress" 558 }; 559 560 void 561 print_error_entry(int num, struct ata_smart_error *le) 562 { 563 int i; 564 565 printf("Log entry: %d\n", num); 566 567 for (i = 0; i < 5; i++) 568 printf("\tCommand %d: dc=%02x sf=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x cmd=%02x time=%02x%02x%02x%02x\n", i, 569 le->command[i].device_control, 570 le->command[i].features, 571 le->command[i].sector_count, 572 le->command[i].sector_number, 573 le->command[i].cylinder_low, 574 le->command[i].cylinder_high, 575 le->command[i].device_head, 576 le->command[i].command, 577 le->command[i].timestamp[3], 578 le->command[i].timestamp[2], 579 le->command[i].timestamp[1], 580 le->command[i].timestamp[0]); 581 printf("\tError: err=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x status=%02x state=%02x lifetime=%02x%02x\n", 582 le->error_data.error, 583 le->error_data.sector_count, 584 le->error_data.sector_number, 585 le->error_data.cylinder_low, 586 le->error_data.cylinder_high, 587 le->error_data.device_head, 588 le->error_data.status, 589 le->error_data.state, 590 le->error_data.lifetime[1], 591 le->error_data.lifetime[0]); 592 printf("\tExtended: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 593 le->error_data.extended_error[0], 594 le->error_data.extended_error[1], 595 le->error_data.extended_error[2], 596 le->error_data.extended_error[3], 597 le->error_data.extended_error[4], 598 le->error_data.extended_error[5], 599 le->error_data.extended_error[6], 600 le->error_data.extended_error[7], 601 le->error_data.extended_error[8], 602 le->error_data.extended_error[9], 603 le->error_data.extended_error[10], 604 le->error_data.extended_error[11], 605 le->error_data.extended_error[12], 606 le->error_data.extended_error[13], 607 le->error_data.extended_error[14], 608 le->error_data.extended_error[15], 609 le->error_data.extended_error[15], 610 le->error_data.extended_error[17], 611 le->error_data.extended_error[18]); 612 } 613 614 void 615 print_error(void *buf) 616 { 617 struct ata_smart_errorlog *erlog = buf; 618 u_int8_t checksum; 619 int i; 620 621 for (i = checksum = 0; i < 512; i++) 622 checksum += ((u_int8_t *) buf)[i]; 623 if (checksum != 0) { 624 fprintf(stderr, "SMART error log checksum error\n"); 625 return; 626 } 627 628 if (erlog->data_structure_revision != 1) { 629 fprintf(stderr, "Log revision not 1"); 630 return; 631 } 632 633 if (erlog->mostrecenterror == 0) { 634 printf("No errors have been logged\n"); 635 return; 636 } 637 638 if (erlog->mostrecenterror > 5) { 639 fprintf(stderr, "Most recent error is too large\n"); 640 return; 641 } 642 643 for (i = erlog->mostrecenterror; i < 5; i++) 644 print_error_entry(i, &erlog->log_entries[i]); 645 for (i = 0; i < erlog->mostrecenterror; i++) 646 print_error_entry(i, &erlog->log_entries[i]); 647 printf("device error count: %d\n", erlog->device_error_count); 648 } 649 650 void 651 print_selftest_entry(int num, struct ata_smart_selftest *le) 652 { 653 unsigned char *p; 654 int i; 655 656 /* check if all zero */ 657 for (p = (void *)le, i = 0; i < sizeof(*le); i++) 658 if (p[i] != 0) 659 break; 660 if (i == sizeof(*le)) 661 return; 662 663 printf("Log entry: %d\n", num); 664 665 /* Get test name */ 666 for (i = 0; selftest_name[i].name != NULL; i++) 667 if (selftest_name[i].number == le->number) 668 break; 669 670 if (selftest_name[i].name == NULL) 671 printf("\tName: (%d)\n", le->number); 672 else 673 printf("\tName: %s\n", selftest_name[i].name); 674 printf("\tStatus: %s\n", selftest_status[le->status >> 4]); 675 /* XXX This generally should not be set when a self-test is completed, 676 and at any rate is useless. - mycroft */ 677 if (le->status >> 4 == 15) 678 printf("\tPercent of test remaining: %1d0\n", le->status & 0xf); 679 else if (le->status >> 4 != 0) 680 printf("\tLBA first error: %d\n", le->lba_first_error); 681 } 682 683 void 684 print_selftest(void *buf) 685 { 686 struct ata_smart_selftestlog *stlog = buf; 687 u_int8_t checksum; 688 int i; 689 690 for (i = checksum = 0; i < 512; i++) 691 checksum += ((u_int8_t *) buf)[i]; 692 if (checksum != 0) { 693 fprintf(stderr, "SMART selftest log checksum error\n"); 694 return; 695 } 696 697 if (stlog->data_structure_revision != 1) { 698 fprintf(stderr, "Log revision not 1"); 699 return; 700 } 701 702 if (stlog->mostrecenttest == 0) { 703 printf("No self-tests have been logged\n"); 704 return; 705 } 706 707 if (stlog->mostrecenttest > 22) { 708 fprintf(stderr, "Most recent test is too large\n"); 709 return; 710 } 711 712 for (i = stlog->mostrecenttest; i < 22; i++) 713 print_selftest_entry(i, &stlog->log_entries[i]); 714 for (i = 0; i < stlog->mostrecenttest; i++) 715 print_selftest_entry(i, &stlog->log_entries[i]); 716 } 717 718 /* 719 * is_smart: 720 * 721 * Detect whether device supports SMART and SMART is enabled. 722 */ 723 724 int 725 is_smart(void) 726 { 727 int retval = 0; 728 struct atareq req; 729 unsigned char inbuf[DEV_BSIZE]; 730 struct ataparams *inqbuf; 731 char *status; 732 733 memset(&inbuf, 0, sizeof(inbuf)); 734 memset(&req, 0, sizeof(req)); 735 736 inqbuf = (struct ataparams *) inbuf; 737 738 req.flags = ATACMD_READ; 739 req.command = WDCC_IDENTIFY; 740 req.databuf = (caddr_t) inbuf; 741 req.datalen = sizeof(inbuf); 742 req.timeout = 1000; 743 744 ata_command(&req); 745 746 if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) { 747 if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) { 748 fprintf(stderr, "SMART unsupported\n"); 749 } else { 750 if (inqbuf->atap_ata_major <= WDC_VER_ATA5 || 751 inqbuf->atap_cmd_set2 == 0xffff || 752 inqbuf->atap_cmd_set2 == 0x0000) { 753 status = "status unknown"; 754 retval = 2; 755 } else { 756 if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) { 757 status = "enabled"; 758 retval = 1; 759 } else { 760 status = "disabled"; 761 } 762 } 763 printf("SMART supported, SMART %s\n", status); 764 } 765 } 766 return retval; 767 } 768 769 /* 770 * DEVICE COMMANDS 771 */ 772 773 /* 774 * device_identify: 775 * 776 * Display the identity of the device 777 */ 778 void 779 device_identify(int argc, char *argv[]) 780 { 781 struct ataparams *inqbuf; 782 struct atareq req; 783 unsigned char inbuf[DEV_BSIZE]; 784 #if BYTE_ORDER == LITTLE_ENDIAN 785 int i; 786 u_int16_t *p; 787 #endif 788 789 /* No arguments. */ 790 if (argc != 0) 791 usage(); 792 793 memset(&inbuf, 0, sizeof(inbuf)); 794 memset(&req, 0, sizeof(req)); 795 796 inqbuf = (struct ataparams *) inbuf; 797 798 req.flags = ATACMD_READ; 799 req.command = WDCC_IDENTIFY; 800 req.databuf = (caddr_t) inbuf; 801 req.datalen = sizeof(inbuf); 802 req.timeout = 1000; 803 804 ata_command(&req); 805 806 #if BYTE_ORDER == LITTLE_ENDIAN 807 /* 808 * On little endian machines, we need to shuffle the string 809 * byte order. However, we don't have to do this for NEC or 810 * Mitsumi ATAPI devices 811 */ 812 813 if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI && 814 ((inqbuf->atap_model[0] == 'N' && 815 inqbuf->atap_model[1] == 'E') || 816 (inqbuf->atap_model[0] == 'F' && 817 inqbuf->atap_model[1] == 'X')))) { 818 for (i = 0 ; i < sizeof(inqbuf->atap_model); i += 2) { 819 p = (u_short *) (inqbuf->atap_model + i); 820 *p = ntohs(*p); 821 } 822 for (i = 0 ; i < sizeof(inqbuf->atap_serial); i += 2) { 823 p = (u_short *) (inqbuf->atap_serial + i); 824 *p = ntohs(*p); 825 } 826 for (i = 0 ; i < sizeof(inqbuf->atap_revision); i += 2) { 827 p = (u_short *) (inqbuf->atap_revision + i); 828 *p = ntohs(*p); 829 } 830 } 831 #endif 832 833 /* 834 * Strip blanks off of the info strings. Yuck, I wish this was 835 * cleaner. 836 */ 837 838 if (inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] == ' ') { 839 inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] = '\0'; 840 while (inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] == ' ') 841 inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] = '\0'; 842 } 843 844 if (inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] == ' ') { 845 inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] = '\0'; 846 while (inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] == ' ') 847 inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] = '\0'; 848 } 849 850 if (inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] == ' ') { 851 inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] = '\0'; 852 while (inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] == ' ') 853 inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] = '\0'; 854 } 855 856 printf("Model: %.*s, Rev: %.*s, Serial #: %.*s\n", 857 (int) sizeof(inqbuf->atap_model), inqbuf->atap_model, 858 (int) sizeof(inqbuf->atap_revision), inqbuf->atap_revision, 859 (int) sizeof(inqbuf->atap_serial), inqbuf->atap_serial); 860 861 printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ? 862 "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" : 863 "removable"); 864 865 if ((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == 0) 866 printf("Cylinders: %d, heads: %d, sec/track: %d, total " 867 "sectors: %d\n", inqbuf->atap_cylinders, 868 inqbuf->atap_heads, inqbuf->atap_sectors, 869 (inqbuf->atap_capacity[1] << 16) | 870 inqbuf->atap_capacity[0]); 871 872 if (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK) 873 printf("Device supports command queue depth of %d\n", 874 inqbuf->atap_queuedepth & 0xf); 875 876 printf("Device capabilities:\n"); 877 print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps); 878 879 if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) { 880 printf("Device supports following standards:\n"); 881 print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers); 882 printf("\n"); 883 } 884 885 if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff && 886 inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) { 887 printf("Command set support:\n"); 888 if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff) 889 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1, 890 inqbuf->atap_cmd1_en, ata_cmd_set1); 891 else 892 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1, 893 ata_cmd_set1); 894 if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff) 895 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2, 896 inqbuf->atap_cmd2_en, ata_cmd_set2); 897 else 898 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2, 899 ata_cmd_set2); 900 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff) 901 print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext, 902 ata_cmd_ext); 903 } 904 905 return; 906 } 907 908 /* 909 * device idle: 910 * 911 * issue the IDLE IMMEDIATE command to the drive 912 */ 913 914 void 915 device_idle(int argc, char *argv[]) 916 { 917 struct atareq req; 918 919 /* No arguments. */ 920 if (argc != 0) 921 usage(); 922 923 memset(&req, 0, sizeof(req)); 924 925 if (strcmp(cmdname, "idle") == 0) 926 req.command = WDCC_IDLE_IMMED; 927 else if (strcmp(cmdname, "standby") == 0) 928 req.command = WDCC_STANDBY_IMMED; 929 else 930 req.command = WDCC_SLEEP; 931 932 req.timeout = 1000; 933 934 ata_command(&req); 935 936 return; 937 } 938 939 /* 940 * Set the idle timer on the disk. Set it for either idle mode or 941 * standby mode, depending on how we were invoked. 942 */ 943 944 void 945 device_setidle(int argc, char *argv[]) 946 { 947 unsigned long idle; 948 struct atareq req; 949 char *end; 950 951 /* Only one argument */ 952 if (argc != 1) 953 usage(); 954 955 idle = strtoul(argv[0], &end, 0); 956 957 if (*end != '\0') { 958 fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]); 959 exit(1); 960 } 961 962 if (idle > 19800) { 963 fprintf(stderr, "Idle time has a maximum value of 5.5 " 964 "hours\n"); 965 exit(1); 966 } 967 968 if (idle != 0 && idle < 5) { 969 fprintf(stderr, "Idle timer must be at least 5 seconds\n"); 970 exit(1); 971 } 972 973 memset(&req, 0, sizeof(req)); 974 975 if (idle <= 240*5) 976 req.sec_count = idle / 5; 977 else 978 req.sec_count = idle / (30*60) + 240; 979 980 req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE; 981 req.timeout = 1000; 982 983 ata_command(&req); 984 985 return; 986 } 987 988 /* 989 * Query the device for the current power mode 990 */ 991 992 void 993 device_checkpower(int argc, char *argv[]) 994 { 995 struct atareq req; 996 997 /* No arguments. */ 998 if (argc != 0) 999 usage(); 1000 1001 memset(&req, 0, sizeof(req)); 1002 1003 req.command = WDCC_CHECK_PWR; 1004 req.timeout = 1000; 1005 req.flags = ATACMD_READREG; 1006 1007 ata_command(&req); 1008 1009 printf("Current power status: "); 1010 1011 switch (req.sec_count) { 1012 case 0x00: 1013 printf("Standby mode\n"); 1014 break; 1015 case 0x80: 1016 printf("Idle mode\n"); 1017 break; 1018 case 0xff: 1019 printf("Active mode\n"); 1020 break; 1021 default: 1022 printf("Unknown power code (%02x)\n", req.sec_count); 1023 } 1024 1025 return; 1026 } 1027 1028 /* 1029 * device_smart: 1030 * 1031 * Display SMART status 1032 */ 1033 void 1034 device_smart(int argc, char *argv[]) 1035 { 1036 struct atareq req; 1037 unsigned char inbuf[DEV_BSIZE]; 1038 unsigned char inbuf2[DEV_BSIZE]; 1039 1040 if (argc < 1) 1041 usage(); 1042 1043 if (strcmp(argv[0], "enable") == 0) { 1044 memset(&req, 0, sizeof(req)); 1045 1046 req.features = WDSM_ENABLE_OPS; 1047 req.command = WDCC_SMART; 1048 req.cylinder = htole16(WDSMART_CYL); 1049 req.timeout = 1000; 1050 1051 ata_command(&req); 1052 1053 is_smart(); 1054 } else if (strcmp(argv[0], "disable") == 0) { 1055 memset(&req, 0, sizeof(req)); 1056 1057 req.features = WDSM_DISABLE_OPS; 1058 req.command = WDCC_SMART; 1059 req.cylinder = htole16(WDSMART_CYL); 1060 req.timeout = 1000; 1061 1062 ata_command(&req); 1063 1064 is_smart(); 1065 } else if (strcmp(argv[0], "status") == 0) { 1066 if (!is_smart()) { 1067 fprintf(stderr, "SMART not supported\n"); 1068 return; 1069 } 1070 1071 memset(&inbuf, 0, sizeof(inbuf)); 1072 memset(&req, 0, sizeof(req)); 1073 1074 req.features = WDSM_STATUS; 1075 req.command = WDCC_SMART; 1076 req.cylinder = htole16(WDSMART_CYL); 1077 req.timeout = 1000; 1078 1079 ata_command(&req); 1080 1081 if (req.cylinder != htole16(WDSMART_CYL)) { 1082 fprintf(stderr, "Threshold exceeds condition\n"); 1083 } 1084 1085 /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional 1086 * features, the following ata_command()'s may error 1087 * and exit(). 1088 */ 1089 1090 memset(&inbuf, 0, sizeof(inbuf)); 1091 memset(&req, 0, sizeof(req)); 1092 1093 req.flags = ATACMD_READ; 1094 req.features = WDSM_RD_DATA; 1095 req.command = WDCC_SMART; 1096 req.databuf = (caddr_t) inbuf; 1097 req.datalen = sizeof(inbuf); 1098 req.cylinder = htole16(WDSMART_CYL); 1099 req.timeout = 1000; 1100 1101 ata_command(&req); 1102 1103 memset(&inbuf2, 0, sizeof(inbuf2)); 1104 memset(&req, 0, sizeof(req)); 1105 1106 req.flags = ATACMD_READ; 1107 req.features = WDSM_RD_THRESHOLDS; 1108 req.command = WDCC_SMART; 1109 req.databuf = (caddr_t) inbuf2; 1110 req.datalen = sizeof(inbuf2); 1111 req.cylinder = htole16(WDSMART_CYL); 1112 req.timeout = 1000; 1113 1114 ata_command(&req); 1115 1116 print_smart_status(inbuf, inbuf2); 1117 1118 } else if (strcmp(argv[0], "offline") == 0) { 1119 if (argc != 2) 1120 usage(); 1121 if (!is_smart()) { 1122 fprintf(stderr, "SMART not supported\n"); 1123 return; 1124 } 1125 1126 memset(&req, 0, sizeof(req)); 1127 1128 req.features = WDSM_EXEC_OFFL_IMM; 1129 req.command = WDCC_SMART; 1130 req.cylinder = htole16(WDSMART_CYL); 1131 req.sec_num = atol(argv[1]); 1132 req.timeout = 10000; 1133 1134 ata_command(&req); 1135 } else if (strcmp(argv[0], "error-log") == 0) { 1136 if (!is_smart()) { 1137 fprintf(stderr, "SMART not supported\n"); 1138 return; 1139 } 1140 1141 memset(&inbuf, 0, sizeof(inbuf)); 1142 memset(&req, 0, sizeof(req)); 1143 1144 req.flags = ATACMD_READ; 1145 req.features = WDSM_RD_LOG; 1146 req.sec_count = 1; 1147 req.sec_num = 1; 1148 req.command = WDCC_SMART; 1149 req.databuf = (caddr_t) inbuf; 1150 req.datalen = sizeof(inbuf); 1151 req.cylinder = htole16(WDSMART_CYL); 1152 req.timeout = 1000; 1153 1154 ata_command(&req); 1155 1156 print_error(inbuf); 1157 } else if (strcmp(argv[0], "selftest-log") == 0) { 1158 if (!is_smart()) { 1159 fprintf(stderr, "SMART not supported\n"); 1160 return; 1161 } 1162 1163 memset(&inbuf, 0, sizeof(inbuf)); 1164 memset(&req, 0, sizeof(req)); 1165 1166 req.flags = ATACMD_READ; 1167 req.features = WDSM_RD_LOG; 1168 req.sec_count = 1; 1169 req.sec_num = 6; 1170 req.command = WDCC_SMART; 1171 req.databuf = (caddr_t) inbuf; 1172 req.datalen = sizeof(inbuf); 1173 req.cylinder = htole16(WDSMART_CYL); 1174 req.timeout = 1000; 1175 1176 ata_command(&req); 1177 1178 print_selftest(inbuf); 1179 1180 } else { 1181 usage(); 1182 } 1183 return; 1184 } 1185 1186 /* 1187 * bus_reset: 1188 * Reset an ATA bus (will reset all devices on the bus) 1189 */ 1190 void 1191 bus_reset(int argc, char *argv[]) 1192 { 1193 int error; 1194 1195 /* no args */ 1196 if (argc != 0) 1197 usage(); 1198 1199 error = ioctl(fd, ATABUSIORESET, NULL); 1200 1201 if (error == -1) 1202 err(1, "ATABUSIORESET failed"); 1203 } 1204