1 /* $NetBSD: atactl.c,v 1.66 2011/10/31 15:26:11 jakllsch 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * atactl(8) - a program to control ATA devices. 34 */ 35 #include <sys/cdefs.h> 36 37 #ifndef lint 38 __RCSID("$NetBSD: atactl.c,v 1.66 2011/10/31 15:26:11 jakllsch Exp $"); 39 #endif 40 41 42 #include <sys/param.h> 43 #include <sys/ioctl.h> 44 #include <err.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <util.h> 52 53 #include <dev/ata/atareg.h> 54 #include <sys/ataio.h> 55 56 struct ata_smart_error { 57 struct { 58 uint8_t device_control; 59 uint8_t features; 60 uint8_t sector_count; 61 uint8_t sector_number; 62 uint8_t cylinder_low; 63 uint8_t cylinder_high; 64 uint8_t device_head; 65 uint8_t command; 66 uint8_t timestamp[4]; 67 } command[5]; 68 struct { 69 uint8_t reserved; 70 uint8_t error; 71 uint8_t sector_count; 72 uint8_t sector_number; 73 uint8_t cylinder_low; 74 uint8_t cylinder_high; 75 uint8_t device_head; 76 uint8_t status; 77 uint8_t extended_error[19]; 78 uint8_t state; 79 uint8_t lifetime[2]; 80 } error_data; 81 } __packed; 82 83 struct ata_smart_errorlog { 84 uint8_t data_structure_revision; 85 uint8_t mostrecenterror; 86 struct ata_smart_error log_entries[5]; 87 uint16_t device_error_count; 88 uint8_t reserved[57]; 89 uint8_t checksum; 90 } __packed; 91 92 struct command { 93 const char *cmd_name; 94 const char *arg_names; 95 void (*cmd_func)(int, char *[]); 96 }; 97 98 struct bitinfo { 99 u_int bitmask; 100 const char *string; 101 }; 102 103 __dead static void usage(void); 104 static void ata_command(struct atareq *); 105 static void print_bitinfo(const char *, const char *, u_int, 106 const struct bitinfo *); 107 static void print_bitinfo2(const char *, const char *, u_int, u_int, 108 const struct bitinfo *); 109 static void print_smart_status(void *, void *); 110 static void print_error_entry(int, const struct ata_smart_error *); 111 static void print_selftest_entry(int, const struct ata_smart_selftest *); 112 113 static void print_error(const void *); 114 static void print_selftest(const void *); 115 116 static const struct ataparams *getataparams(void); 117 118 static int is_smart(void); 119 120 static int fd; /* file descriptor for device */ 121 static const char *dvname; /* device name */ 122 static char dvname_store[MAXPATHLEN]; /* for opendisk(3) */ 123 static const char *cmdname; /* command user issued */ 124 125 static void device_identify(int, char *[]); 126 static void device_setidle(int, char *[]); 127 static void device_idle(int, char *[]); 128 static void device_apm(int, char *[]); 129 static void device_checkpower(int, char *[]); 130 static void device_smart(int, char *[]); 131 static void device_security(int, char *[]); 132 133 static void device_smart_temp(const struct ata_smart_attr *, uint64_t); 134 135 static const struct command device_commands[] = { 136 { "identify", "", device_identify }, 137 { "setidle", "idle-timer", device_setidle }, 138 { "apm", "disable|set #", device_apm }, 139 { "setstandby", "standby-timer", device_setidle }, 140 { "idle", "", device_idle }, 141 { "standby", "", device_idle }, 142 { "sleep", "", device_idle }, 143 { "checkpower", "", device_checkpower }, 144 { "smart", 145 "enable|disable|status|offline #|error-log|selftest-log", 146 device_smart }, 147 { "security", "freeze|status", device_security }, 148 { NULL, NULL, NULL }, 149 }; 150 151 static void bus_reset(int, char *[]); 152 153 static const 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 static const 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 static const 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 static const 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 static const 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 static const 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 bitinfo ata_sata_caps[] = { 236 { SATA_SIGNAL_GEN1, "1.5Gb/s signaling" }, 237 { SATA_SIGNAL_GEN2, "3.0Gb/s signaling" }, 238 { SATA_NATIVE_CMDQ, "Native Command Queuing" }, 239 { SATA_HOST_PWR_MGMT, "Host-Initiated Interface Power Management" }, 240 { SATA_PHY_EVNT_CNT, "PHY Event Counters" }, 241 { 0, NULL }, 242 }; 243 244 static const struct bitinfo ata_sata_feat[] = { 245 { SATA_NONZERO_OFFSETS, "Non-zero Offset DMA" }, 246 { SATA_DMA_SETUP_AUTO, "DMA Setup Auto Activate" }, 247 { SATA_DRIVE_PWR_MGMT, "Device-Initiated Interface Power Managment" }, 248 { SATA_IN_ORDER_DATA, "In-order Data Delivery" }, 249 { SATA_SW_STTNGS_PRS, "Software Settings Preservation" }, 250 { 0, NULL }, 251 }; 252 253 static const struct { 254 const int id; 255 const char *name; 256 void (*special)(const struct ata_smart_attr *, uint64_t); 257 } smart_attrs[] = { 258 { 1, "Raw read error rate", NULL }, 259 { 2, "Throughput performance", NULL }, 260 { 3, "Spin-up time", NULL }, 261 { 4, "Start/stop count", NULL }, 262 { 5, "Reallocated sector count", NULL }, 263 { 6, "Read channel margin", NULL }, 264 { 7, "Seek error rate", NULL }, 265 { 8, "Seek time performance", NULL }, 266 { 9, "Power-on hours count", NULL }, 267 { 10, "Spin retry count", NULL }, 268 { 11, "Calibration retry count", NULL }, 269 { 12, "Device power cycle count", NULL }, 270 { 13, "Soft read error rate", NULL }, 271 { 187, "Reported uncorrect", NULL }, 272 { 189, "High Fly Writes", NULL }, 273 { 190, "Airflow Temperature", device_smart_temp }, 274 { 191, "G-sense error rate", NULL }, 275 { 192, "Power-off retract count", NULL }, 276 { 193, "Load cycle count", NULL }, 277 { 194, "Temperature", device_smart_temp}, 278 { 195, "Hardware ECC Recovered", NULL }, 279 { 196, "Reallocated event count", NULL }, 280 { 197, "Current pending sector", NULL }, 281 { 198, "Offline uncorrectable", NULL }, 282 { 199, "Ultra DMA CRC error count", NULL }, 283 { 200, "Write error rate", NULL }, 284 { 201, "Soft read error rate", NULL }, 285 { 202, "Data address mark errors", NULL }, 286 { 203, "Run out cancel", NULL }, 287 { 204, "Soft ECC correction", NULL }, 288 { 205, "Thermal asperity check", NULL }, 289 { 206, "Flying height", NULL }, 290 { 207, "Spin high current", NULL }, 291 { 208, "Spin buzz", NULL }, 292 { 209, "Offline seek performance", NULL }, 293 { 220, "Disk shift", NULL }, 294 { 221, "G-Sense error rate", NULL }, 295 { 222, "Loaded hours", NULL }, 296 { 223, "Load/unload retry count", NULL }, 297 { 224, "Load friction", NULL }, 298 { 225, "Load/unload cycle count", NULL }, 299 { 226, "Load-in time", NULL }, 300 { 227, "Torque amplification count", NULL }, 301 { 228, "Power-off retract count", NULL }, 302 { 230, "GMR head amplitude", NULL }, 303 { 231, "Temperature", device_smart_temp }, 304 { 240, "Head flying hours", NULL }, 305 { 250, "Read error retry rate", NULL }, 306 { 0, "Unknown", NULL }, 307 }; 308 309 static const struct bitinfo ata_sec_st[] = { 310 { WDC_SEC_SUPP, "supported" }, 311 { WDC_SEC_EN, "enabled" }, 312 { WDC_SEC_LOCKED, "locked" }, 313 { WDC_SEC_FROZEN, "frozen" }, 314 { WDC_SEC_EXP, "expired" }, 315 { WDC_SEC_ESE_SUPP, "enhanced erase support" }, 316 { WDC_SEC_LEV_MAX, "maximum level" }, 317 { 0, NULL }, 318 }; 319 320 int 321 main(int argc, char *argv[]) 322 { 323 int i; 324 const struct command *commands = NULL; 325 326 /* Must have at least: device command */ 327 if (argc < 3) 328 usage(); 329 330 /* Skip program name, get and skip device name and command. */ 331 dvname = argv[1]; 332 cmdname = argv[2]; 333 argv += 3; 334 argc -= 3; 335 336 /* 337 * Open the device 338 */ 339 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0); 340 if (fd == -1) { 341 if (errno == ENOENT) { 342 /* 343 * Device doesn't exist. Probably trying to open 344 * a device which doesn't use disk semantics for 345 * device name. Try again, specifying "cooked", 346 * which leaves off the "r" in front of the device's 347 * name. 348 */ 349 fd = opendisk(dvname, O_RDWR, dvname_store, 350 sizeof(dvname_store), 1); 351 if (fd == -1) 352 err(1, "%s", dvname); 353 } else 354 err(1, "%s", dvname); 355 } 356 357 /* 358 * Point the dvname at the actual device name that opendisk() opened. 359 */ 360 dvname = dvname_store; 361 362 /* Look up and call the command. */ 363 for (i = 0; device_commands[i].cmd_name != NULL; i++) { 364 if (strcmp(cmdname, device_commands[i].cmd_name) == 0) { 365 commands = &device_commands[i]; 366 break; 367 } 368 } 369 if (commands == NULL) { 370 for (i = 0; bus_commands[i].cmd_name != NULL; i++) { 371 if (strcmp(cmdname, bus_commands[i].cmd_name) == 0) { 372 commands = &bus_commands[i]; 373 break; 374 } 375 } 376 } 377 if (commands == NULL) 378 errx(1, "unknown command: %s", cmdname); 379 380 (*commands->cmd_func)(argc, argv); 381 exit(0); 382 } 383 384 static void 385 usage(void) 386 { 387 int i; 388 389 fprintf(stderr, "usage: %s device command [arg [...]]\n", 390 getprogname()); 391 392 fprintf(stderr, " Available device commands:\n"); 393 for (i=0; device_commands[i].cmd_name != NULL; i++) 394 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name, 395 device_commands[i].arg_names); 396 397 fprintf(stderr, " Available bus commands:\n"); 398 for (i=0; bus_commands[i].cmd_name != NULL; i++) 399 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name, 400 bus_commands[i].arg_names); 401 402 exit(1); 403 } 404 405 /* 406 * Wrapper that calls ATAIOCCOMMAND and checks for errors 407 */ 408 409 static void 410 ata_command(struct atareq *req) 411 { 412 int error; 413 414 error = ioctl(fd, ATAIOCCOMMAND, req); 415 416 if (error == -1) 417 err(1, "ATAIOCCOMMAND failed"); 418 419 switch (req->retsts) { 420 421 case ATACMD_OK: 422 return; 423 case ATACMD_TIMEOUT: 424 fprintf(stderr, "ATA command timed out\n"); 425 exit(1); 426 case ATACMD_DF: 427 fprintf(stderr, "ATA device returned a Device Fault\n"); 428 exit(1); 429 case ATACMD_ERROR: 430 if (req->error & WDCE_ABRT) 431 fprintf(stderr, "ATA device returned Aborted " 432 "Command\n"); 433 else 434 fprintf(stderr, "ATA device returned error register " 435 "%0x\n", req->error); 436 exit(1); 437 default: 438 fprintf(stderr, "ATAIOCCOMMAND returned unknown result code " 439 "%d\n", req->retsts); 440 exit(1); 441 } 442 } 443 444 /* 445 * Print out strings associated with particular bitmasks 446 */ 447 448 static void 449 print_bitinfo(const char *bf, const char *af, u_int bits, 450 const struct bitinfo *binfo) 451 { 452 453 for (; binfo->bitmask != 0; binfo++) 454 if (bits & binfo->bitmask) 455 printf("%s%s%s", bf, binfo->string, af); 456 } 457 458 static void 459 print_bitinfo2(const char *bf, const char *af, u_int bits, u_int enables, 460 const struct bitinfo *binfo) 461 { 462 463 for (; binfo->bitmask != 0; binfo++) 464 if (bits & binfo->bitmask) 465 printf("%s%s (%s)%s", bf, binfo->string, 466 (enables & binfo->bitmask) ? "enabled" : "disabled", 467 af); 468 } 469 470 471 /* 472 * Try to print SMART temperature field 473 */ 474 475 static void 476 device_smart_temp(const struct ata_smart_attr *attr, uint64_t raw_value) 477 { 478 printf("%" PRIu8, attr->raw[0]); 479 if (attr->raw[0] != raw_value) 480 printf(" Lifetime min/max %" PRIu8 "/%" PRIu8, 481 attr->raw[2], attr->raw[4]); 482 } 483 484 485 /* 486 * Print out SMART attribute thresholds and values 487 */ 488 489 static void 490 print_smart_status(void *vbuf, void *tbuf) 491 { 492 const struct ata_smart_attributes *value_buf = vbuf; 493 const struct ata_smart_thresholds *threshold_buf = tbuf; 494 const struct ata_smart_attr *attr; 495 uint64_t raw_value; 496 int flags; 497 int i, j; 498 int aid; 499 uint8_t checksum; 500 501 for (i = checksum = 0; i < 512; i++) 502 checksum += ((const uint8_t *) value_buf)[i]; 503 if (checksum != 0) { 504 fprintf(stderr, "SMART attribute values checksum error\n"); 505 return; 506 } 507 508 for (i = checksum = 0; i < 512; i++) 509 checksum += ((const uint8_t *) threshold_buf)[i]; 510 if (checksum != 0) { 511 fprintf(stderr, "SMART attribute thresholds checksum error\n"); 512 return; 513 } 514 515 printf("id value thresh crit collect reliability description" 516 "\t\t\traw\n"); 517 for (i = 0; i < 256; i++) { 518 int thresh = 0; 519 520 attr = NULL; 521 522 for (j = 0; j < 30; j++) { 523 if (value_buf->attributes[j].id == i) 524 attr = &value_buf->attributes[j]; 525 if (threshold_buf->thresholds[j].id == i) 526 thresh = threshold_buf->thresholds[j].value; 527 } 528 529 if (thresh && attr == NULL) 530 errx(1, "threshold but not attr %d", i); 531 if (attr == NULL) 532 continue; 533 534 if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF) 535 continue; 536 537 for (aid = 0; 538 smart_attrs[aid].id != i && smart_attrs[aid].id != 0; 539 aid++) 540 ; 541 542 flags = le16toh(attr->flags); 543 544 printf("%3d %3d %3d %-3s %-7s %stive %-24s\t", 545 i, attr->value, thresh, 546 flags & WDSM_ATTR_ADVISORY ? "yes" : "no", 547 flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline", 548 attr->value > thresh ? "posi" : "nega", 549 smart_attrs[aid].name); 550 551 for (j = 0, raw_value = 0; j < 6; j++) 552 raw_value += ((uint64_t)attr->raw[j]) << (8*j); 553 554 if (smart_attrs[aid].special) 555 (*smart_attrs[aid].special)(attr, raw_value); 556 else 557 printf("%" PRIu64, raw_value); 558 printf("\n"); 559 } 560 } 561 562 static const struct { 563 int number; 564 const char *name; 565 } selftest_name[] = { 566 { 0, "Off-line" }, 567 { 1, "Short off-line" }, 568 { 2, "Extended off-line" }, 569 { 127, "Abort off-line test" }, 570 { 129, "Short captive" }, 571 { 130, "Extended captive" }, 572 { 256, "Unknown test" }, /* larger then uint8_t */ 573 { 0, NULL } 574 }; 575 576 static const char *selftest_status[] = { 577 "No error", 578 "Aborted by the host", 579 "Interrupted by the host by reset", 580 "Fatal error or unknown test error", 581 "Unknown test element failed", 582 "Electrical test element failed", 583 "The Servo (and/or seek) test element failed", 584 "Read element of test failed", 585 "Reserved", 586 "Reserved", 587 "Reserved", 588 "Reserved", 589 "Reserved", 590 "Reserved", 591 "Reserved", 592 "Self-test in progress" 593 }; 594 595 static void 596 print_error_entry(int num, const struct ata_smart_error *le) 597 { 598 int i; 599 600 printf("Log entry: %d\n", num); 601 602 for (i = 0; i < 5; i++) 603 printf("\tCommand %d: dc=%02x sf=%02x sc=%02x sn=%02x cl=%02x " 604 "ch=%02x dh=%02x cmd=%02x time=%02x%02x%02x%02x\n", i, 605 le->command[i].device_control, 606 le->command[i].features, 607 le->command[i].sector_count, 608 le->command[i].sector_number, 609 le->command[i].cylinder_low, 610 le->command[i].cylinder_high, 611 le->command[i].device_head, 612 le->command[i].command, 613 le->command[i].timestamp[3], 614 le->command[i].timestamp[2], 615 le->command[i].timestamp[1], 616 le->command[i].timestamp[0]); 617 printf("\tError: err=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x " 618 "status=%02x state=%02x lifetime=%02x%02x\n", 619 le->error_data.error, 620 le->error_data.sector_count, 621 le->error_data.sector_number, 622 le->error_data.cylinder_low, 623 le->error_data.cylinder_high, 624 le->error_data.device_head, 625 le->error_data.status, 626 le->error_data.state, 627 le->error_data.lifetime[1], 628 le->error_data.lifetime[0]); 629 printf("\tExtended: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x " 630 "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 631 le->error_data.extended_error[0], 632 le->error_data.extended_error[1], 633 le->error_data.extended_error[2], 634 le->error_data.extended_error[3], 635 le->error_data.extended_error[4], 636 le->error_data.extended_error[5], 637 le->error_data.extended_error[6], 638 le->error_data.extended_error[7], 639 le->error_data.extended_error[8], 640 le->error_data.extended_error[9], 641 le->error_data.extended_error[10], 642 le->error_data.extended_error[11], 643 le->error_data.extended_error[12], 644 le->error_data.extended_error[13], 645 le->error_data.extended_error[14], 646 le->error_data.extended_error[15], 647 le->error_data.extended_error[15], 648 le->error_data.extended_error[17], 649 le->error_data.extended_error[18]); 650 } 651 652 static void 653 print_error(const void *buf) 654 { 655 const struct ata_smart_errorlog *erlog = buf; 656 uint8_t checksum; 657 int i; 658 659 for (i = checksum = 0; i < 512; i++) 660 checksum += ((const uint8_t *) buf)[i]; 661 if (checksum != 0) { 662 fprintf(stderr, "SMART error log checksum error\n"); 663 return; 664 } 665 666 if (erlog->data_structure_revision != 1) { 667 fprintf(stderr, "Error log revision not 1 (found 0x%04x)\n", 668 erlog->data_structure_revision); 669 return; 670 } 671 672 if (erlog->mostrecenterror == 0) { 673 printf("No errors have been logged\n"); 674 return; 675 } 676 677 if (erlog->mostrecenterror > 5) { 678 fprintf(stderr, "Most recent error is too large\n"); 679 return; 680 } 681 682 for (i = erlog->mostrecenterror; i < 5; i++) 683 print_error_entry(i, &erlog->log_entries[i]); 684 for (i = 0; i < erlog->mostrecenterror; i++) 685 print_error_entry(i, &erlog->log_entries[i]); 686 printf("device error count: %d\n", erlog->device_error_count); 687 } 688 689 static void 690 print_selftest_entry(int num, const struct ata_smart_selftest *le) 691 { 692 const unsigned char *p; 693 size_t i; 694 695 /* check if all zero */ 696 for (p = (const void *)le, i = 0; i < sizeof(*le); i++) 697 if (p[i] != 0) 698 break; 699 if (i == sizeof(*le)) 700 return; 701 702 printf("Log entry: %d\n", num); 703 704 /* Get test name */ 705 for (i = 0; selftest_name[i].name != NULL; i++) 706 if (selftest_name[i].number == le->number) 707 break; 708 709 if (selftest_name[i].name == NULL) 710 printf("\tName: (%d)\n", le->number); 711 else 712 printf("\tName: %s\n", selftest_name[i].name); 713 printf("\tStatus: %s\n", selftest_status[le->status >> 4]); 714 /* XXX This generally should not be set when a self-test is completed, 715 and at any rate is useless. - mycroft */ 716 if (le->status >> 4 == 15) 717 printf("\tPercent of test remaining: %1d0\n", le->status & 0xf); 718 else if (le->status >> 4 != 0) 719 printf("\tLBA first error: %d\n", le32toh(le->lba_first_error)); 720 } 721 722 static void 723 print_selftest(const void *buf) 724 { 725 const struct ata_smart_selftestlog *stlog = buf; 726 uint8_t checksum; 727 int i; 728 729 for (i = checksum = 0; i < 512; i++) 730 checksum += ((const uint8_t *) buf)[i]; 731 if (checksum != 0) { 732 fprintf(stderr, "SMART selftest log checksum error\n"); 733 return; 734 } 735 736 if (le16toh(stlog->data_structure_revision) != 1) { 737 fprintf(stderr, "Self-test log revision not 1 (found 0x%04x)\n", 738 le16toh(stlog->data_structure_revision)); 739 return; 740 } 741 742 if (stlog->mostrecenttest == 0) { 743 printf("No self-tests have been logged\n"); 744 return; 745 } 746 747 if (stlog->mostrecenttest > 22) { 748 fprintf(stderr, "Most recent test is too large\n"); 749 return; 750 } 751 752 for (i = stlog->mostrecenttest; i < 22; i++) 753 print_selftest_entry(i, &stlog->log_entries[i]); 754 for (i = 0; i < stlog->mostrecenttest; i++) 755 print_selftest_entry(i, &stlog->log_entries[i]); 756 } 757 758 static const struct ataparams * 759 getataparams(void) 760 { 761 struct atareq req; 762 static union { 763 unsigned char inbuf[DEV_BSIZE]; 764 struct ataparams inqbuf; 765 } inbuf; 766 767 memset(&inbuf, 0, sizeof(inbuf)); 768 memset(&req, 0, sizeof(req)); 769 770 req.flags = ATACMD_READ; 771 req.command = WDCC_IDENTIFY; 772 req.databuf = &inbuf; 773 req.datalen = sizeof(inbuf); 774 req.timeout = 1000; 775 776 ata_command(&req); 777 778 return (&inbuf.inqbuf); 779 } 780 781 /* 782 * is_smart: 783 * 784 * Detect whether device supports SMART and SMART is enabled. 785 */ 786 787 static int 788 is_smart(void) 789 { 790 int retval = 0; 791 const struct ataparams *inqbuf; 792 const char *status; 793 794 inqbuf = getataparams(); 795 796 if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) { 797 if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) { 798 fprintf(stderr, "SMART unsupported\n"); 799 } else { 800 if (inqbuf->atap_ata_major <= WDC_VER_ATA5 || 801 inqbuf->atap_cmd_set2 == 0xffff || 802 inqbuf->atap_cmd_set2 == 0x0000) { 803 status = "status unknown"; 804 retval = 2; 805 } else { 806 if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) { 807 status = "enabled"; 808 retval = 1; 809 } else { 810 status = "disabled"; 811 retval = 3; 812 } 813 } 814 printf("SMART supported, SMART %s\n", status); 815 } 816 } 817 return retval; 818 } 819 820 /* 821 * extract_string: copy a block of bytes out of ataparams and make 822 * a proper string out of it, truncating trailing spaces and preserving 823 * strict typing. And also, not doing unaligned accesses. 824 */ 825 static void 826 extract_string(char *buf, size_t bufmax, 827 const uint8_t *bytes, size_t numbytes, 828 int needswap) 829 { 830 unsigned i; 831 size_t j; 832 unsigned char ch1, ch2; 833 834 for (i = 0, j = 0; i < numbytes; i += 2) { 835 ch1 = bytes[i]; 836 ch2 = bytes[i+1]; 837 if (needswap && j < bufmax-1) { 838 buf[j++] = ch2; 839 } 840 if (j < bufmax-1) { 841 buf[j++] = ch1; 842 } 843 if (!needswap && j < bufmax-1) { 844 buf[j++] = ch2; 845 } 846 } 847 while (j > 0 && buf[j-1] == ' ') { 848 j--; 849 } 850 buf[j] = '\0'; 851 } 852 853 /* 854 * DEVICE COMMANDS 855 */ 856 857 /* 858 * device_identify: 859 * 860 * Display the identity of the device 861 */ 862 static void 863 device_identify(int argc, char *argv[]) 864 { 865 const struct ataparams *inqbuf; 866 char model[sizeof(inqbuf->atap_model)+1]; 867 char revision[sizeof(inqbuf->atap_revision)+1]; 868 char serial[sizeof(inqbuf->atap_serial)+1]; 869 char hnum[12]; 870 uint64_t capacity; 871 uint64_t sectors; 872 uint32_t secsize; 873 int lb_per_pb; 874 int needswap = 0; 875 int i; 876 uint8_t checksum; 877 878 /* No arguments. */ 879 if (argc != 0) 880 usage(); 881 882 inqbuf = getataparams(); 883 884 if ((inqbuf->atap_integrity & WDC_INTEGRITY_MAGIC_MASK) == 885 WDC_INTEGRITY_MAGIC) { 886 for (i = checksum = 0; i < 512; i++) 887 checksum += ((const uint8_t *)inqbuf)[i]; 888 if (checksum != 0) 889 puts("IDENTIFY DEVICE data checksum invalid\n"); 890 } 891 892 #if BYTE_ORDER == LITTLE_ENDIAN 893 /* 894 * On little endian machines, we need to shuffle the string 895 * byte order. However, we don't have to do this for NEC or 896 * Mitsumi ATAPI devices 897 */ 898 899 if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI && 900 ((inqbuf->atap_model[0] == 'N' && 901 inqbuf->atap_model[1] == 'E') || 902 (inqbuf->atap_model[0] == 'F' && 903 inqbuf->atap_model[1] == 'X')))) { 904 needswap = 1; 905 } 906 #endif 907 908 /* 909 * Copy the info strings out, stripping off blanks. 910 */ 911 extract_string(model, sizeof(model), 912 inqbuf->atap_model, sizeof(inqbuf->atap_model), 913 needswap); 914 extract_string(revision, sizeof(revision), 915 inqbuf->atap_revision, sizeof(inqbuf->atap_revision), 916 needswap); 917 extract_string(serial, sizeof(serial), 918 inqbuf->atap_serial, sizeof(inqbuf->atap_serial), 919 needswap); 920 921 printf("Model: %s, Rev: %s, Serial #: %s\n", 922 model, revision, serial); 923 924 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff && 925 inqbuf->atap_cmd_ext & ATA_CMDE_WWN) 926 printf("World Wide Name: %016" PRIX64 "\n", 927 ((uint64_t)inqbuf->atap_wwn[0] << 48) | 928 ((uint64_t)inqbuf->atap_wwn[1] << 32) | 929 ((uint64_t)inqbuf->atap_wwn[2] << 16) | 930 ((uint64_t)inqbuf->atap_wwn[3] << 0)); 931 932 printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ? 933 "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" : 934 "removable"); 935 936 if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff && 937 inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) { 938 sectors = 939 ((uint64_t)inqbuf->atap_max_lba[3] << 48) | 940 ((uint64_t)inqbuf->atap_max_lba[2] << 32) | 941 ((uint64_t)inqbuf->atap_max_lba[1] << 16) | 942 ((uint64_t)inqbuf->atap_max_lba[0] << 0); 943 } else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) { 944 sectors = (inqbuf->atap_capacity[1] << 16) | 945 inqbuf->atap_capacity[0]; 946 } else { 947 sectors = inqbuf->atap_cylinders * 948 inqbuf->atap_heads * inqbuf->atap_sectors; 949 } 950 951 secsize = 512; 952 953 if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) { 954 if (inqbuf->atap_secsz & ATA_SECSZ_LLS) { 955 secsize = 2 * /* words to bytes */ 956 (inqbuf->atap_lls_secsz[1] << 16 | 957 inqbuf->atap_lls_secsz[0] << 0); 958 } 959 } 960 961 capacity = sectors * secsize; 962 963 humanize_number(hnum, sizeof(hnum), capacity, "bytes", 964 HN_AUTOSCALE, HN_DIVISOR_1000); 965 966 printf("Capacity %s, %" PRIu64 " sectors, %" PRIu32 " bytes/sector\n", 967 hnum, sectors, secsize); 968 969 printf("Cylinders: %d, heads: %d, sec/track: %d\n", 970 inqbuf->atap_cylinders, inqbuf->atap_heads, 971 inqbuf->atap_sectors); 972 973 lb_per_pb = 1; 974 975 if ((inqbuf->atap_secsz & ATA_SECSZ_VALID_MASK) == ATA_SECSZ_VALID) { 976 if (inqbuf->atap_secsz & ATA_SECSZ_LPS) { 977 lb_per_pb <<= inqbuf->atap_secsz & ATA_SECSZ_LPS_SZMSK; 978 printf("Physical sector size: %d bytes\n", 979 lb_per_pb * secsize); 980 if ((inqbuf->atap_logical_align & 981 ATA_LA_VALID_MASK) == ATA_LA_VALID) { 982 printf("First physically aligned sector: %d\n", 983 lb_per_pb - (inqbuf->atap_logical_align & 984 ATA_LA_MASK)); 985 } 986 } 987 } 988 989 if (((inqbuf->atap_sata_caps & SATA_NATIVE_CMDQ) || 990 (inqbuf->atap_cmd_set2 & ATA_CMD2_RWQ)) && 991 (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK)) 992 printf("Command queue depth: %d\n", 993 (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK) + 1); 994 995 printf("Device capabilities:\n"); 996 print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps); 997 998 if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) { 999 printf("Device supports following standards:\n"); 1000 print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers); 1001 printf("\n"); 1002 } 1003 1004 if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff && 1005 inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) { 1006 printf("Command set support:\n"); 1007 if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff) 1008 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1, 1009 inqbuf->atap_cmd1_en, ata_cmd_set1); 1010 else 1011 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1, 1012 ata_cmd_set1); 1013 if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff) 1014 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2, 1015 inqbuf->atap_cmd2_en, ata_cmd_set2); 1016 else 1017 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2, 1018 ata_cmd_set2); 1019 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff) 1020 print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext, 1021 ata_cmd_ext); 1022 } 1023 1024 if (inqbuf->atap_sata_caps != 0 && inqbuf->atap_sata_caps != 0xffff) { 1025 printf("Serial ATA capabilities:\n"); 1026 print_bitinfo("\t", "\n", 1027 inqbuf->atap_sata_caps, ata_sata_caps); 1028 1029 } 1030 1031 if (inqbuf->atap_sata_features_supp != 0 && 1032 inqbuf->atap_sata_features_supp != 0xffff) { 1033 printf("Serial ATA features:\n"); 1034 if (inqbuf->atap_sata_features_en != 0 && 1035 inqbuf->atap_sata_features_en != 0xffff) 1036 print_bitinfo2("\t", "\n", 1037 inqbuf->atap_sata_features_supp, 1038 inqbuf->atap_sata_features_en, ata_sata_feat); 1039 else 1040 print_bitinfo("\t", "\n", 1041 inqbuf->atap_sata_features_supp, ata_sata_feat); 1042 } 1043 1044 return; 1045 } 1046 1047 /* 1048 * device idle: 1049 * 1050 * issue the IDLE IMMEDIATE command to the drive 1051 */ 1052 static void 1053 device_idle(int argc, char *argv[]) 1054 { 1055 struct atareq req; 1056 1057 /* No arguments. */ 1058 if (argc != 0) 1059 usage(); 1060 1061 memset(&req, 0, sizeof(req)); 1062 1063 if (strcmp(cmdname, "idle") == 0) 1064 req.command = WDCC_IDLE_IMMED; 1065 else if (strcmp(cmdname, "standby") == 0) 1066 req.command = WDCC_STANDBY_IMMED; 1067 else 1068 req.command = WDCC_SLEEP; 1069 1070 req.timeout = 1000; 1071 1072 ata_command(&req); 1073 1074 return; 1075 } 1076 1077 /* 1078 * device apm: 1079 * 1080 * enable/disable/control the APM feature of the drive 1081 */ 1082 static void 1083 device_apm(int argc, char *argv[]) 1084 { 1085 struct atareq req; 1086 long l; 1087 1088 memset(&req, 0, sizeof(req)); 1089 if (argc >= 1) { 1090 req.command = SET_FEATURES; 1091 req.timeout = 1000; 1092 1093 if (strcmp(argv[0], "disable") == 0) 1094 req.features = WDSF_APM_DS; 1095 else if (strcmp(argv[0], "set") == 0 && argc >= 2 && 1096 (l = strtol(argv[1], NULL, 0)) >= 0 && l <= 253) { 1097 1098 req.features = WDSF_APM_EN; 1099 req.sec_count = l + 1; 1100 } else 1101 usage(); 1102 } else 1103 usage(); 1104 1105 ata_command(&req); 1106 } 1107 1108 1109 /* 1110 * Set the idle timer on the disk. Set it for either idle mode or 1111 * standby mode, depending on how we were invoked. 1112 */ 1113 1114 static void 1115 device_setidle(int argc, char *argv[]) 1116 { 1117 unsigned long idle; 1118 struct atareq req; 1119 char *end; 1120 1121 /* Only one argument */ 1122 if (argc != 1) 1123 usage(); 1124 1125 idle = strtoul(argv[0], &end, 0); 1126 1127 if (*end != '\0') { 1128 fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]); 1129 exit(1); 1130 } 1131 1132 if (idle > 19800) { 1133 fprintf(stderr, "Idle time has a maximum value of 5.5 " 1134 "hours\n"); 1135 exit(1); 1136 } 1137 1138 if (idle != 0 && idle < 5) { 1139 fprintf(stderr, "Idle timer must be at least 5 seconds\n"); 1140 exit(1); 1141 } 1142 1143 memset(&req, 0, sizeof(req)); 1144 1145 if (idle <= 240*5) 1146 req.sec_count = idle / 5; 1147 else 1148 req.sec_count = idle / (30*60) + 240; 1149 1150 req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE; 1151 req.timeout = 1000; 1152 1153 ata_command(&req); 1154 1155 return; 1156 } 1157 1158 /* 1159 * Query the device for the current power mode 1160 */ 1161 1162 static void 1163 device_checkpower(int argc, char *argv[]) 1164 { 1165 struct atareq req; 1166 1167 /* No arguments. */ 1168 if (argc != 0) 1169 usage(); 1170 1171 memset(&req, 0, sizeof(req)); 1172 1173 req.command = WDCC_CHECK_PWR; 1174 req.timeout = 1000; 1175 req.flags = ATACMD_READREG; 1176 1177 ata_command(&req); 1178 1179 printf("Current power status: "); 1180 1181 switch (req.sec_count) { 1182 case 0x00: 1183 printf("Standby mode\n"); 1184 break; 1185 case 0x80: 1186 printf("Idle mode\n"); 1187 break; 1188 case 0xff: 1189 printf("Active mode\n"); 1190 break; 1191 default: 1192 printf("Unknown power code (%02x)\n", req.sec_count); 1193 } 1194 1195 return; 1196 } 1197 1198 /* 1199 * device_smart: 1200 * 1201 * Display SMART status 1202 */ 1203 static void 1204 device_smart(int argc, char *argv[]) 1205 { 1206 struct atareq req; 1207 unsigned char inbuf[DEV_BSIZE]; 1208 unsigned char inbuf2[DEV_BSIZE]; 1209 1210 if (argc < 1) 1211 usage(); 1212 1213 if (strcmp(argv[0], "enable") == 0) { 1214 memset(&req, 0, sizeof(req)); 1215 1216 req.features = WDSM_ENABLE_OPS; 1217 req.command = WDCC_SMART; 1218 req.cylinder = WDSMART_CYL; 1219 req.timeout = 1000; 1220 1221 ata_command(&req); 1222 1223 is_smart(); 1224 } else if (strcmp(argv[0], "disable") == 0) { 1225 memset(&req, 0, sizeof(req)); 1226 1227 req.features = WDSM_DISABLE_OPS; 1228 req.command = WDCC_SMART; 1229 req.cylinder = WDSMART_CYL; 1230 req.timeout = 1000; 1231 1232 ata_command(&req); 1233 1234 is_smart(); 1235 } else if (strcmp(argv[0], "status") == 0) { 1236 int rv; 1237 1238 rv = is_smart(); 1239 1240 if (!rv) { 1241 fprintf(stderr, "SMART not supported\n"); 1242 return; 1243 } else if (rv == 3) 1244 return; 1245 1246 memset(&inbuf, 0, sizeof(inbuf)); 1247 memset(&req, 0, sizeof(req)); 1248 1249 req.features = WDSM_STATUS; 1250 req.command = WDCC_SMART; 1251 req.cylinder = WDSMART_CYL; 1252 req.timeout = 1000; 1253 1254 ata_command(&req); 1255 1256 if (req.cylinder != WDSMART_CYL) { 1257 fprintf(stderr, "Threshold exceeds condition\n"); 1258 } 1259 1260 /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional 1261 * features, the following ata_command()'s may error 1262 * and exit(). 1263 */ 1264 1265 memset(&inbuf, 0, sizeof(inbuf)); 1266 memset(&req, 0, sizeof(req)); 1267 1268 req.flags = ATACMD_READ; 1269 req.features = WDSM_RD_DATA; 1270 req.command = WDCC_SMART; 1271 req.databuf = (caddr_t) inbuf; 1272 req.datalen = sizeof(inbuf); 1273 req.cylinder = WDSMART_CYL; 1274 req.timeout = 1000; 1275 1276 ata_command(&req); 1277 1278 memset(&inbuf2, 0, sizeof(inbuf2)); 1279 memset(&req, 0, sizeof(req)); 1280 1281 req.flags = ATACMD_READ; 1282 req.features = WDSM_RD_THRESHOLDS; 1283 req.command = WDCC_SMART; 1284 req.databuf = (caddr_t) inbuf2; 1285 req.datalen = sizeof(inbuf2); 1286 req.cylinder = WDSMART_CYL; 1287 req.timeout = 1000; 1288 1289 ata_command(&req); 1290 1291 print_smart_status(inbuf, inbuf2); 1292 1293 } else if (strcmp(argv[0], "offline") == 0) { 1294 if (argc != 2) 1295 usage(); 1296 if (!is_smart()) { 1297 fprintf(stderr, "SMART not supported\n"); 1298 return; 1299 } 1300 1301 memset(&req, 0, sizeof(req)); 1302 1303 req.features = WDSM_EXEC_OFFL_IMM; 1304 req.command = WDCC_SMART; 1305 req.cylinder = WDSMART_CYL; 1306 req.sec_num = atol(argv[1]); 1307 req.timeout = 10000; 1308 1309 ata_command(&req); 1310 } else if (strcmp(argv[0], "error-log") == 0) { 1311 if (!is_smart()) { 1312 fprintf(stderr, "SMART not supported\n"); 1313 return; 1314 } 1315 1316 memset(&inbuf, 0, sizeof(inbuf)); 1317 memset(&req, 0, sizeof(req)); 1318 1319 req.flags = ATACMD_READ; 1320 req.features = WDSM_RD_LOG; 1321 req.sec_count = 1; 1322 req.sec_num = 1; 1323 req.command = WDCC_SMART; 1324 req.databuf = (caddr_t) inbuf; 1325 req.datalen = sizeof(inbuf); 1326 req.cylinder = WDSMART_CYL; 1327 req.timeout = 1000; 1328 1329 ata_command(&req); 1330 1331 print_error(inbuf); 1332 } else if (strcmp(argv[0], "selftest-log") == 0) { 1333 if (!is_smart()) { 1334 fprintf(stderr, "SMART not supported\n"); 1335 return; 1336 } 1337 1338 memset(&inbuf, 0, sizeof(inbuf)); 1339 memset(&req, 0, sizeof(req)); 1340 1341 req.flags = ATACMD_READ; 1342 req.features = WDSM_RD_LOG; 1343 req.sec_count = 1; 1344 req.sec_num = 6; 1345 req.command = WDCC_SMART; 1346 req.databuf = (caddr_t) inbuf; 1347 req.datalen = sizeof(inbuf); 1348 req.cylinder = WDSMART_CYL; 1349 req.timeout = 1000; 1350 1351 ata_command(&req); 1352 1353 print_selftest(inbuf); 1354 1355 } else { 1356 usage(); 1357 } 1358 return; 1359 } 1360 1361 static void 1362 device_security(int argc, char *argv[]) 1363 { 1364 struct atareq req; 1365 const struct ataparams *inqbuf; 1366 1367 /* need subcommand */ 1368 if (argc < 1) 1369 usage(); 1370 1371 if (strcmp(argv[0], "freeze") == 0) { 1372 memset(&req, 0, sizeof(req)); 1373 req.command = WDCC_SECURITY_FREEZE; 1374 req.timeout = 1000; 1375 ata_command(&req); 1376 } else if (strcmp(argv[0], "status") == 0) { 1377 inqbuf = getataparams(); 1378 print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st); 1379 } else 1380 usage(); 1381 1382 return; 1383 } 1384 1385 /* 1386 * bus_reset: 1387 * Reset an ATA bus (will reset all devices on the bus) 1388 */ 1389 static void 1390 bus_reset(int argc, char *argv[]) 1391 { 1392 int error; 1393 1394 /* no args */ 1395 if (argc != 0) 1396 usage(); 1397 1398 error = ioctl(fd, ATABUSIORESET, NULL); 1399 1400 if (error == -1) 1401 err(1, "ATABUSIORESET failed"); 1402 } 1403