atactl.c revision 1.67 1 /* $NetBSD: atactl.c,v 1.67 2012/10/19 17:09:07 drochner 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.67 2012/10/19 17:09:07 drochner 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 { WDC_VER_ATA8, "ATA-8" },
181 { 0, NULL },
182 };
183
184 static const struct bitinfo ata_cmd_set1[] = {
185 { WDC_CMD1_NOP, "NOP command" },
186 { WDC_CMD1_RB, "READ BUFFER command" },
187 { WDC_CMD1_WB, "WRITE BUFFER command" },
188 { WDC_CMD1_HPA, "Host Protected Area feature set" },
189 { WDC_CMD1_DVRST, "DEVICE RESET command" },
190 { WDC_CMD1_SRV, "SERVICE interrupt" },
191 { WDC_CMD1_RLSE, "release interrupt" },
192 { WDC_CMD1_AHEAD, "look-ahead" },
193 { WDC_CMD1_CACHE, "write cache" },
194 { WDC_CMD1_PKT, "PACKET command feature set" },
195 { WDC_CMD1_PM, "Power Management feature set" },
196 { WDC_CMD1_REMOV, "Removable Media feature set" },
197 { WDC_CMD1_SEC, "Security Mode feature set" },
198 { WDC_CMD1_SMART, "SMART feature set" },
199 { 0, NULL },
200 };
201
202 static const struct bitinfo ata_cmd_set2[] = {
203 { ATA_CMD2_FCE, "FLUSH CACHE EXT command" },
204 { WDC_CMD2_FC, "FLUSH CACHE command" },
205 { WDC_CMD2_DCO, "Device Configuration Overlay feature set" },
206 { ATA_CMD2_LBA48, "48-bit Address feature set" },
207 { WDC_CMD2_AAM, "Automatic Acoustic Management feature set" },
208 { WDC_CMD2_SM, "SET MAX security extension" },
209 { WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" },
210 { WDC_CMD2_PUIS, "Power-Up In Standby feature set" },
211 { WDC_CMD2_RMSN, "Removable Media Status Notification feature set" },
212 { ATA_CMD2_APM, "Advanced Power Management feature set" },
213 { ATA_CMD2_CFA, "CFA feature set" },
214 { ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" },
215 { WDC_CMD2_DM, "DOWNLOAD MICROCODE command" },
216 { 0, NULL },
217 };
218
219 static const struct bitinfo ata_cmd_ext[] = {
220 { ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" },
221 { ATA_CMDE_TL, "Time-limited Read/Write" },
222 { ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" },
223 { ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" },
224 { ATA_CMDE_WWN, "World Wide Name" },
225 { ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" },
226 { ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" },
227 { ATA_CMDE_GPL, "General Purpose Logging feature set" },
228 { ATA_CMDE_STREAM, "Streaming feature set" },
229 { ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" },
230 { ATA_CMDE_MS, "Media serial number" },
231 { ATA_CMDE_SST, "SMART self-test" },
232 { ATA_CMDE_SEL, "SMART error logging" },
233 { 0, NULL },
234 };
235
236 static const struct bitinfo ata_sata_caps[] = {
237 { SATA_SIGNAL_GEN1, "1.5Gb/s signaling" },
238 { SATA_SIGNAL_GEN2, "3.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
245 static 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
254 static 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
310 static 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
321 int
322 main(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
385 static void
386 usage(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
410 static void
411 ata_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
449 static void
450 print_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
459 static void
460 print_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
476 static void
477 device_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
490 static void
491 print_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
563 static 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
577 static 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
596 static void
597 print_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
653 static void
654 print_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
690 static void
691 print_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
723 static void
724 print_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
759 static const struct ataparams *
760 getataparams(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
788 static int
789 is_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 */
826 static void
827 extract_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 */
863 static void
864 device_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 if ((inqbuf->atap_ata_major & WDC_VER_ATA8) &&
1046 (inqbuf->support_dsm & ATA_SUPPORT_DSM_TRIM))
1047 printf("TRIM supported\n");
1048
1049 return;
1050 }
1051
1052 /*
1053 * device idle:
1054 *
1055 * issue the IDLE IMMEDIATE command to the drive
1056 */
1057 static void
1058 device_idle(int argc, char *argv[])
1059 {
1060 struct atareq req;
1061
1062 /* No arguments. */
1063 if (argc != 0)
1064 usage();
1065
1066 memset(&req, 0, sizeof(req));
1067
1068 if (strcmp(cmdname, "idle") == 0)
1069 req.command = WDCC_IDLE_IMMED;
1070 else if (strcmp(cmdname, "standby") == 0)
1071 req.command = WDCC_STANDBY_IMMED;
1072 else
1073 req.command = WDCC_SLEEP;
1074
1075 req.timeout = 1000;
1076
1077 ata_command(&req);
1078
1079 return;
1080 }
1081
1082 /*
1083 * device apm:
1084 *
1085 * enable/disable/control the APM feature of the drive
1086 */
1087 static void
1088 device_apm(int argc, char *argv[])
1089 {
1090 struct atareq req;
1091 long l;
1092
1093 memset(&req, 0, sizeof(req));
1094 if (argc >= 1) {
1095 req.command = SET_FEATURES;
1096 req.timeout = 1000;
1097
1098 if (strcmp(argv[0], "disable") == 0)
1099 req.features = WDSF_APM_DS;
1100 else if (strcmp(argv[0], "set") == 0 && argc >= 2 &&
1101 (l = strtol(argv[1], NULL, 0)) >= 0 && l <= 253) {
1102
1103 req.features = WDSF_APM_EN;
1104 req.sec_count = l + 1;
1105 } else
1106 usage();
1107 } else
1108 usage();
1109
1110 ata_command(&req);
1111 }
1112
1113
1114 /*
1115 * Set the idle timer on the disk. Set it for either idle mode or
1116 * standby mode, depending on how we were invoked.
1117 */
1118
1119 static void
1120 device_setidle(int argc, char *argv[])
1121 {
1122 unsigned long idle;
1123 struct atareq req;
1124 char *end;
1125
1126 /* Only one argument */
1127 if (argc != 1)
1128 usage();
1129
1130 idle = strtoul(argv[0], &end, 0);
1131
1132 if (*end != '\0') {
1133 fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
1134 exit(1);
1135 }
1136
1137 if (idle > 19800) {
1138 fprintf(stderr, "Idle time has a maximum value of 5.5 "
1139 "hours\n");
1140 exit(1);
1141 }
1142
1143 if (idle != 0 && idle < 5) {
1144 fprintf(stderr, "Idle timer must be at least 5 seconds\n");
1145 exit(1);
1146 }
1147
1148 memset(&req, 0, sizeof(req));
1149
1150 if (idle <= 240*5)
1151 req.sec_count = idle / 5;
1152 else
1153 req.sec_count = idle / (30*60) + 240;
1154
1155 req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
1156 req.timeout = 1000;
1157
1158 ata_command(&req);
1159
1160 return;
1161 }
1162
1163 /*
1164 * Query the device for the current power mode
1165 */
1166
1167 static void
1168 device_checkpower(int argc, char *argv[])
1169 {
1170 struct atareq req;
1171
1172 /* No arguments. */
1173 if (argc != 0)
1174 usage();
1175
1176 memset(&req, 0, sizeof(req));
1177
1178 req.command = WDCC_CHECK_PWR;
1179 req.timeout = 1000;
1180 req.flags = ATACMD_READREG;
1181
1182 ata_command(&req);
1183
1184 printf("Current power status: ");
1185
1186 switch (req.sec_count) {
1187 case 0x00:
1188 printf("Standby mode\n");
1189 break;
1190 case 0x80:
1191 printf("Idle mode\n");
1192 break;
1193 case 0xff:
1194 printf("Active mode\n");
1195 break;
1196 default:
1197 printf("Unknown power code (%02x)\n", req.sec_count);
1198 }
1199
1200 return;
1201 }
1202
1203 /*
1204 * device_smart:
1205 *
1206 * Display SMART status
1207 */
1208 static void
1209 device_smart(int argc, char *argv[])
1210 {
1211 struct atareq req;
1212 unsigned char inbuf[DEV_BSIZE];
1213 unsigned char inbuf2[DEV_BSIZE];
1214
1215 if (argc < 1)
1216 usage();
1217
1218 if (strcmp(argv[0], "enable") == 0) {
1219 memset(&req, 0, sizeof(req));
1220
1221 req.features = WDSM_ENABLE_OPS;
1222 req.command = WDCC_SMART;
1223 req.cylinder = WDSMART_CYL;
1224 req.timeout = 1000;
1225
1226 ata_command(&req);
1227
1228 is_smart();
1229 } else if (strcmp(argv[0], "disable") == 0) {
1230 memset(&req, 0, sizeof(req));
1231
1232 req.features = WDSM_DISABLE_OPS;
1233 req.command = WDCC_SMART;
1234 req.cylinder = WDSMART_CYL;
1235 req.timeout = 1000;
1236
1237 ata_command(&req);
1238
1239 is_smart();
1240 } else if (strcmp(argv[0], "status") == 0) {
1241 int rv;
1242
1243 rv = is_smart();
1244
1245 if (!rv) {
1246 fprintf(stderr, "SMART not supported\n");
1247 return;
1248 } else if (rv == 3)
1249 return;
1250
1251 memset(&inbuf, 0, sizeof(inbuf));
1252 memset(&req, 0, sizeof(req));
1253
1254 req.features = WDSM_STATUS;
1255 req.command = WDCC_SMART;
1256 req.cylinder = WDSMART_CYL;
1257 req.timeout = 1000;
1258
1259 ata_command(&req);
1260
1261 if (req.cylinder != WDSMART_CYL) {
1262 fprintf(stderr, "Threshold exceeds condition\n");
1263 }
1264
1265 /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
1266 * features, the following ata_command()'s may error
1267 * and exit().
1268 */
1269
1270 memset(&inbuf, 0, sizeof(inbuf));
1271 memset(&req, 0, sizeof(req));
1272
1273 req.flags = ATACMD_READ;
1274 req.features = WDSM_RD_DATA;
1275 req.command = WDCC_SMART;
1276 req.databuf = (caddr_t) inbuf;
1277 req.datalen = sizeof(inbuf);
1278 req.cylinder = WDSMART_CYL;
1279 req.timeout = 1000;
1280
1281 ata_command(&req);
1282
1283 memset(&inbuf2, 0, sizeof(inbuf2));
1284 memset(&req, 0, sizeof(req));
1285
1286 req.flags = ATACMD_READ;
1287 req.features = WDSM_RD_THRESHOLDS;
1288 req.command = WDCC_SMART;
1289 req.databuf = (caddr_t) inbuf2;
1290 req.datalen = sizeof(inbuf2);
1291 req.cylinder = WDSMART_CYL;
1292 req.timeout = 1000;
1293
1294 ata_command(&req);
1295
1296 print_smart_status(inbuf, inbuf2);
1297
1298 } else if (strcmp(argv[0], "offline") == 0) {
1299 if (argc != 2)
1300 usage();
1301 if (!is_smart()) {
1302 fprintf(stderr, "SMART not supported\n");
1303 return;
1304 }
1305
1306 memset(&req, 0, sizeof(req));
1307
1308 req.features = WDSM_EXEC_OFFL_IMM;
1309 req.command = WDCC_SMART;
1310 req.cylinder = WDSMART_CYL;
1311 req.sec_num = atol(argv[1]);
1312 req.timeout = 10000;
1313
1314 ata_command(&req);
1315 } else if (strcmp(argv[0], "error-log") == 0) {
1316 if (!is_smart()) {
1317 fprintf(stderr, "SMART not supported\n");
1318 return;
1319 }
1320
1321 memset(&inbuf, 0, sizeof(inbuf));
1322 memset(&req, 0, sizeof(req));
1323
1324 req.flags = ATACMD_READ;
1325 req.features = WDSM_RD_LOG;
1326 req.sec_count = 1;
1327 req.sec_num = 1;
1328 req.command = WDCC_SMART;
1329 req.databuf = (caddr_t) inbuf;
1330 req.datalen = sizeof(inbuf);
1331 req.cylinder = WDSMART_CYL;
1332 req.timeout = 1000;
1333
1334 ata_command(&req);
1335
1336 print_error(inbuf);
1337 } else if (strcmp(argv[0], "selftest-log") == 0) {
1338 if (!is_smart()) {
1339 fprintf(stderr, "SMART not supported\n");
1340 return;
1341 }
1342
1343 memset(&inbuf, 0, sizeof(inbuf));
1344 memset(&req, 0, sizeof(req));
1345
1346 req.flags = ATACMD_READ;
1347 req.features = WDSM_RD_LOG;
1348 req.sec_count = 1;
1349 req.sec_num = 6;
1350 req.command = WDCC_SMART;
1351 req.databuf = (caddr_t) inbuf;
1352 req.datalen = sizeof(inbuf);
1353 req.cylinder = WDSMART_CYL;
1354 req.timeout = 1000;
1355
1356 ata_command(&req);
1357
1358 print_selftest(inbuf);
1359
1360 } else {
1361 usage();
1362 }
1363 return;
1364 }
1365
1366 static void
1367 device_security(int argc, char *argv[])
1368 {
1369 struct atareq req;
1370 const struct ataparams *inqbuf;
1371
1372 /* need subcommand */
1373 if (argc < 1)
1374 usage();
1375
1376 if (strcmp(argv[0], "freeze") == 0) {
1377 memset(&req, 0, sizeof(req));
1378 req.command = WDCC_SECURITY_FREEZE;
1379 req.timeout = 1000;
1380 ata_command(&req);
1381 } else if (strcmp(argv[0], "status") == 0) {
1382 inqbuf = getataparams();
1383 print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
1384 } else
1385 usage();
1386
1387 return;
1388 }
1389
1390 /*
1391 * bus_reset:
1392 * Reset an ATA bus (will reset all devices on the bus)
1393 */
1394 static void
1395 bus_reset(int argc, char *argv[])
1396 {
1397 int error;
1398
1399 /* no args */
1400 if (argc != 0)
1401 usage();
1402
1403 error = ioctl(fd, ATABUSIORESET, NULL);
1404
1405 if (error == -1)
1406 err(1, "ATABUSIORESET failed");
1407 }
1408