atactl.c revision 1.66 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