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