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