No empty .Rs/.Re
[netbsd-mini2440.git] / sbin / atactl / atactl.c
blob6da8692674cb5295aafcff69b74b7fba74865cbe
1 /* $NetBSD: atactl.c,v 1.54 2009/06/06 09:18:55 mlelstv Exp $ */
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ken Hornstein.
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.
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.
33 * atactl(8) - a program to control ATA devices.
35 #include <sys/cdefs.h>
37 #ifndef lint
38 __RCSID("$NetBSD: atactl.c,v 1.54 2009/06/06 09:18:55 mlelstv Exp $");
39 #endif
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>
53 #include <dev/ata/atareg.h>
54 #include <sys/ataio.h>
56 struct ata_smart_error {
57 struct {
58 u_int8_t device_control;
59 u_int8_t features;
60 u_int8_t sector_count;
61 u_int8_t sector_number;
62 u_int8_t cylinder_low;
63 u_int8_t cylinder_high;
64 u_int8_t device_head;
65 u_int8_t command;
66 u_int8_t timestamp[4];
67 } command[5];
68 struct {
69 u_int8_t reserved;
70 u_int8_t error;
71 u_int8_t sector_count;
72 u_int8_t sector_number;
73 u_int8_t cylinder_low;
74 u_int8_t cylinder_high;
75 u_int8_t device_head;
76 u_int8_t status;
77 u_int8_t extended_error[19];
78 u_int8_t state;
79 u_int8_t lifetime[2];
80 } error_data;
81 } __packed;
83 struct ata_smart_errorlog {
84 u_int8_t data_structure_revision;
85 u_int8_t mostrecenterror;
86 struct ata_smart_error log_entries[5];
87 u_int16_t device_error_count;
88 u_int8_t reserved[57];
89 u_int8_t checksum;
90 } __packed;
92 struct command {
93 const char *cmd_name;
94 const char *arg_names;
95 void (*cmd_func)(int, char *[]);
98 struct bitinfo {
99 u_int bitmask;
100 const char *string;
103 void usage(void);
104 void ata_command(struct atareq *);
105 void print_bitinfo(const char *, const char *, u_int, struct bitinfo *);
106 void print_bitinfo2(const char *, const char *, u_int, u_int, struct bitinfo *);
107 void print_smart_status(void *, void *);
108 void print_error_entry(int, struct ata_smart_error *);
109 void print_selftest_entry(int, struct ata_smart_selftest *);
111 void print_error(void *);
112 void print_selftest(void *);
114 struct ataparams *getataparams(void);
116 int is_smart(void);
118 int fd; /* file descriptor for device */
119 const char *dvname; /* device name */
120 char dvname_store[MAXPATHLEN]; /* for opendisk(3) */
121 const char *cmdname; /* command user issued */
122 const char *argnames; /* helpstring: expected arguments */
124 void device_identify(int, char *[]);
125 void device_setidle(int, char *[]);
126 void device_idle(int, char *[]);
127 void device_apm(int, char *[]);
128 void device_checkpower(int, char *[]);
129 void device_smart(int, char *[]);
130 void device_security(int, char *[]);
132 void device_smart_temp(struct ata_smart_attr *, uint64_t);
134 struct command device_commands[] = {
135 { "identify", "", device_identify },
136 { "setidle", "idle-timer", device_setidle },
137 { "apm", "disable|set #", device_apm },
138 { "setstandby", "standby-timer", device_setidle },
139 { "idle", "", device_idle },
140 { "standby", "", device_idle },
141 { "sleep", "", device_idle },
142 { "checkpower", "", device_checkpower },
143 { "smart", "enable|disable|status|offline #|error-log|selftest-log",
144 device_smart },
145 { "security", "freeze|status", device_security },
146 { NULL, NULL, NULL },
149 void bus_reset(int, char *[]);
151 struct command bus_commands[] = {
152 { "reset", "", bus_reset },
153 { NULL, NULL, NULL },
157 * Tables containing bitmasks used for error reporting and
158 * device identification.
161 struct bitinfo ata_caps[] = {
162 { WDC_CAP_DMA, "DMA" },
163 { WDC_CAP_LBA, "LBA" },
164 { ATA_CAP_STBY, "ATA standby timer values" },
165 { WDC_CAP_IORDY, "IORDY operation" },
166 { WDC_CAP_IORDY_DSBL, "IORDY disabling" },
167 { 0, NULL },
170 struct bitinfo ata_vers[] = {
171 { WDC_VER_ATA1, "ATA-1" },
172 { WDC_VER_ATA2, "ATA-2" },
173 { WDC_VER_ATA3, "ATA-3" },
174 { WDC_VER_ATA4, "ATA-4" },
175 { WDC_VER_ATA5, "ATA-5" },
176 { WDC_VER_ATA6, "ATA-6" },
177 { WDC_VER_ATA7, "ATA-7" },
178 { 0, NULL },
181 struct bitinfo ata_cmd_set1[] = {
182 { WDC_CMD1_NOP, "NOP command" },
183 { WDC_CMD1_RB, "READ BUFFER command" },
184 { WDC_CMD1_WB, "WRITE BUFFER command" },
185 { WDC_CMD1_HPA, "Host Protected Area feature set" },
186 { WDC_CMD1_DVRST, "DEVICE RESET command" },
187 { WDC_CMD1_SRV, "SERVICE interrupt" },
188 { WDC_CMD1_RLSE, "release interrupt" },
189 { WDC_CMD1_AHEAD, "look-ahead" },
190 { WDC_CMD1_CACHE, "write cache" },
191 { WDC_CMD1_PKT, "PACKET command feature set" },
192 { WDC_CMD1_PM, "Power Management feature set" },
193 { WDC_CMD1_REMOV, "Removable Media feature set" },
194 { WDC_CMD1_SEC, "Security Mode feature set" },
195 { WDC_CMD1_SMART, "SMART feature set" },
196 { 0, NULL },
199 struct bitinfo ata_cmd_set2[] = {
200 { ATA_CMD2_FCE, "FLUSH CACHE EXT command" },
201 { WDC_CMD2_FC, "FLUSH CACHE command" },
202 { WDC_CMD2_DCO, "Device Configuration Overlay feature set" },
203 { ATA_CMD2_LBA48, "48-bit Address feature set" },
204 { WDC_CMD2_AAM, "Automatic Acoustic Management feature set" },
205 { WDC_CMD2_SM, "SET MAX security extension" },
206 { WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" },
207 { WDC_CMD2_PUIS, "Power-Up In Standby feature set" },
208 { WDC_CMD2_RMSN, "Removable Media Status Notification feature set" },
209 { ATA_CMD2_APM, "Advanced Power Management feature set" },
210 { ATA_CMD2_CFA, "CFA feature set" },
211 { ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" },
212 { WDC_CMD2_DM, "DOWNLOAD MICROCODE command" },
213 { 0, NULL },
216 struct bitinfo ata_cmd_ext[] = {
217 { ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" },
218 { ATA_CMDE_TL, "Time-limited Read/Write" },
219 { ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" },
220 { ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" },
221 { ATA_CMDE_WWN, "World Wide Name" },
222 { ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" },
223 { ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" },
224 { ATA_CMDE_GPL, "General Purpose Logging feature set" },
225 { ATA_CMDE_STREAM, "Streaming feature set" },
226 { ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" },
227 { ATA_CMDE_MS, "Media serial number" },
228 { ATA_CMDE_SST, "SMART self-test" },
229 { ATA_CMDE_SEL, "SMART error logging" },
230 { 0, NULL },
233 struct bitinfo ata_sata_caps[] = {
234 { SATA_SIGNAL_GEN1, "1.5Gb/s signaling" },
235 { SATA_SIGNAL_GEN2, "3.0Gb/s signaling" },
236 { SATA_NATIVE_CMDQ, "Native Command Queuing" },
237 { SATA_HOST_PWR_MGMT, "Host-Initiated Interface Power Management" },
238 { SATA_PHY_EVNT_CNT, "PHY Event Counters" },
239 { 0, NULL },
242 struct bitinfo ata_sata_feat[] = {
243 { SATA_NONZERO_OFFSETS, "Non-zero Offset DMA" },
244 { SATA_DMA_SETUP_AUTO, "DMA Setup Auto Activate" },
245 { SATA_DRIVE_PWR_MGMT, "Device-Initiated Interface Power Managment" },
246 { SATA_IN_ORDER_DATA, "In-order Data Delivery" },
247 { SATA_SW_STTNGS_PRS, "Software Settings Preservation" },
248 { 0, NULL },
251 static const struct {
252 const int id;
253 const char *name;
254 void (*special)(struct ata_smart_attr *, uint64_t);
255 } smart_attrs[] = {
256 { 1, "Raw read error rate", NULL },
257 { 2, "Throughput performance", NULL },
258 { 3, "Spin-up time", NULL },
259 { 4, "Start/stop count", NULL },
260 { 5, "Reallocated sector count", NULL },
261 { 6, "Read channel margin", NULL },
262 { 7, "Seek error rate", NULL },
263 { 8, "Seek time performance", NULL },
264 { 9, "Power-on hours count", NULL },
265 { 10, "Spin retry count", NULL },
266 { 11, "Calibration retry count", NULL },
267 { 12, "Device power cycle count", NULL },
268 { 13, "Soft read error rate", NULL },
269 { 189, "High Fly Writes", NULL },
270 { 190, "Airflow Temperature", device_smart_temp },
271 { 191, "G-sense error rate", NULL },
272 { 192, "Power-off retract count", NULL },
273 { 193, "Load cycle count", NULL },
274 { 194, "Temperature", device_smart_temp},
275 { 195, "Hardware ECC Recovered", NULL },
276 { 196, "Reallocated event count", NULL },
277 { 197, "Current pending sector", NULL },
278 { 198, "Offline uncorrectable", NULL },
279 { 199, "Ultra DMA CRC error count", NULL },
280 { 200, "Write error rate", NULL },
281 { 201, "Soft read error rate", NULL },
282 { 202, "Data address mark errors", NULL },
283 { 203, "Run out cancel", NULL },
284 { 204, "Soft ECC correction", NULL },
285 { 205, "Thermal asperity check", NULL },
286 { 206, "Flying height", NULL },
287 { 207, "Spin high current", NULL },
288 { 208, "Spin buzz", NULL },
289 { 209, "Offline seek performance", NULL },
290 { 220, "Disk shift", NULL },
291 { 221, "G-Sense error rate", NULL },
292 { 222, "Loaded hours", NULL },
293 { 223, "Load/unload retry count", NULL },
294 { 224, "Load friction", NULL },
295 { 225, "Load/unload cycle count", NULL },
296 { 226, "Load-in time", NULL },
297 { 227, "Torque amplification count", NULL },
298 { 228, "Power-off retract count", NULL },
299 { 230, "GMR head amplitude", NULL },
300 { 231, "Temperature", device_smart_temp },
301 { 240, "Head flying hours", NULL },
302 { 250, "Read error retry rate", NULL },
303 { 0, "Unknown", NULL },
306 struct bitinfo ata_sec_st[] = {
307 { WDC_SEC_SUPP, "supported" },
308 { WDC_SEC_EN, "enabled" },
309 { WDC_SEC_LOCKED, "locked" },
310 { WDC_SEC_FROZEN, "frozen" },
311 { WDC_SEC_EXP, "expired" },
312 { WDC_SEC_ESE_SUPP, "enhanced erase support" },
313 { WDC_SEC_LEV_MAX, "maximum level" },
314 { 0, NULL },
318 main(int argc, char *argv[])
320 int i;
321 struct command *commands = NULL;
323 /* Must have at least: device command */
324 if (argc < 3)
325 usage();
327 /* Skip program name, get and skip device name and command. */
328 dvname = argv[1];
329 cmdname = argv[2];
330 argv += 3;
331 argc -= 3;
334 * Open the device
336 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
337 if (fd == -1) {
338 if (errno == ENOENT) {
340 * Device doesn't exist. Probably trying to open
341 * a device which doesn't use disk semantics for
342 * device name. Try again, specifying "cooked",
343 * which leaves off the "r" in front of the device's
344 * name.
346 fd = opendisk(dvname, O_RDWR, dvname_store,
347 sizeof(dvname_store), 1);
348 if (fd == -1)
349 err(1, "%s", dvname);
350 } else
351 err(1, "%s", dvname);
355 * Point the dvname at the actual device name that opendisk() opened.
357 dvname = dvname_store;
359 /* Look up and call the command. */
360 for (i = 0; device_commands[i].cmd_name != NULL; i++) {
361 if (strcmp(cmdname, device_commands[i].cmd_name) == 0) {
362 commands = &device_commands[i];
363 break;
366 if (commands == NULL) {
367 for (i = 0; bus_commands[i].cmd_name != NULL; i++) {
368 if (strcmp(cmdname, bus_commands[i].cmd_name) == 0) {
369 commands = &bus_commands[i];
370 break;
374 if (commands == NULL)
375 errx(1, "unknown command: %s", cmdname);
377 argnames = commands->arg_names;
379 (*commands->cmd_func)(argc, argv);
380 exit(0);
383 void
384 usage(void)
386 int i;
388 fprintf(stderr, "usage: %s device command [arg [...]]\n",
389 getprogname());
391 fprintf(stderr, " Available device commands:\n");
392 for (i=0; device_commands[i].cmd_name != NULL; i++)
393 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
394 device_commands[i].arg_names);
396 fprintf(stderr, " Available bus commands:\n");
397 for (i=0; bus_commands[i].cmd_name != NULL; i++)
398 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
399 bus_commands[i].arg_names);
401 exit(1);
405 * Wrapper that calls ATAIOCCOMMAND and checks for errors
408 void
409 ata_command(struct atareq *req)
411 int error;
413 error = ioctl(fd, ATAIOCCOMMAND, req);
415 if (error == -1)
416 err(1, "ATAIOCCOMMAND failed");
418 switch (req->retsts) {
420 case ATACMD_OK:
421 return;
422 case ATACMD_TIMEOUT:
423 fprintf(stderr, "ATA command timed out\n");
424 exit(1);
425 case ATACMD_DF:
426 fprintf(stderr, "ATA device returned a Device Fault\n");
427 exit(1);
428 case ATACMD_ERROR:
429 if (req->error & WDCE_ABRT)
430 fprintf(stderr, "ATA device returned Aborted "
431 "Command\n");
432 else
433 fprintf(stderr, "ATA device returned error register "
434 "%0x\n", req->error);
435 exit(1);
436 default:
437 fprintf(stderr, "ATAIOCCOMMAND returned unknown result code "
438 "%d\n", req->retsts);
439 exit(1);
444 * Print out strings associated with particular bitmasks
447 void
448 print_bitinfo(const char *bf, const char *af, u_int bits, struct bitinfo *binfo)
451 for (; binfo->bitmask != 0; binfo++)
452 if (bits & binfo->bitmask)
453 printf("%s%s%s", bf, binfo->string, af);
456 void
457 print_bitinfo2(const char *bf, const char *af, u_int bits, u_int enables, struct bitinfo *binfo)
460 for (; binfo->bitmask != 0; binfo++)
461 if (bits & binfo->bitmask)
462 printf("%s%s (%s)%s", bf, binfo->string,
463 (enables & binfo->bitmask) ? "enabled" : "disabled",
464 af);
469 * Try to print SMART temperature field
472 void
473 device_smart_temp(struct ata_smart_attr *attr, uint64_t raw_value)
475 printf("%" PRIu8, attr->raw[0]);
476 if (attr->raw[0] != raw_value)
477 printf(" Lifetime max/min %" PRIu8 "/%" PRIu8,
478 attr->raw[2], attr->raw[4]);
483 * Print out SMART attribute thresholds and values
486 void
487 print_smart_status(void *vbuf, void *tbuf)
489 struct ata_smart_attributes *value_buf = vbuf;
490 struct ata_smart_thresholds *threshold_buf = tbuf;
491 struct ata_smart_attr *attr;
492 uint64_t raw_value;
493 int flags;
494 int i, j;
495 int aid;
496 u_int8_t checksum;
498 for (i = checksum = 0; i < 512; i++)
499 checksum += ((u_int8_t *) value_buf)[i];
500 if (checksum != 0) {
501 fprintf(stderr, "SMART attribute values checksum error\n");
502 return;
505 for (i = checksum = 0; i < 512; i++)
506 checksum += ((u_int8_t *) threshold_buf)[i];
507 if (checksum != 0) {
508 fprintf(stderr, "SMART attribute thresholds checksum error\n");
509 return;
512 printf("id value thresh crit collect reliability description\t\t\traw\n");
513 for (i = 0; i < 256; i++) {
514 int thresh = 0;
516 attr = NULL;
518 for (j = 0; j < 30; j++) {
519 if (value_buf->attributes[j].id == i)
520 attr = &value_buf->attributes[j];
521 if (threshold_buf->thresholds[j].id == i)
522 thresh = threshold_buf->thresholds[j].value;
525 if (thresh && attr == NULL)
526 errx(1, "threshold but not attr %d", i);
527 if (attr == NULL)
528 continue;
530 if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF)
531 continue;
533 for (aid = 0;
534 smart_attrs[aid].id != i && smart_attrs[aid].id != 0;
535 aid++)
538 flags = le16toh(attr->flags);
540 printf("%3d %3d %3d %-3s %-7s %stive %-24s\t",
541 i, attr->value, thresh,
542 flags & WDSM_ATTR_ADVISORY ? "yes" : "no",
543 flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline",
544 attr->value > thresh ? "posi" : "nega",
545 smart_attrs[aid].name);
547 for (j = 0, raw_value = 0; j < 6; j++)
548 raw_value += ((uint64_t)attr->raw[j]) << (8*j);
550 if (smart_attrs[aid].special)
551 (*smart_attrs[aid].special)(attr, raw_value);
552 else
553 printf("%" PRIu64, raw_value);
554 printf("\n");
558 struct {
559 int number;
560 const char *name;
561 } selftest_name[] = {
562 { 0, "Off-line" },
563 { 1, "Short off-line" },
564 { 2, "Extended off-line" },
565 { 127, "Abort off-line test" },
566 { 129, "Short captive" },
567 { 130, "Extended captive" },
568 { 256, "Unknown test" }, /* larger then u_int8_t */
569 { 0, NULL }
572 const char *selftest_status[] = {
573 "No error",
574 "Aborted by the host",
575 "Interrupted by the host by reset",
576 "Fatal error or unknown test error",
577 "Unknown test element failed",
578 "Electrical test element failed",
579 "The Servo (and/or seek) test element failed",
580 "Read element of test failed",
581 "Reserved",
582 "Reserved",
583 "Reserved",
584 "Reserved",
585 "Reserved",
586 "Reserved",
587 "Reserved",
588 "Self-test in progress"
591 void
592 print_error_entry(int num, struct ata_smart_error *le)
594 int i;
596 printf("Log entry: %d\n", num);
598 for (i = 0; i < 5; i++)
599 printf("\tCommand %d: dc=%02x sf=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x cmd=%02x time=%02x%02x%02x%02x\n", i,
600 le->command[i].device_control,
601 le->command[i].features,
602 le->command[i].sector_count,
603 le->command[i].sector_number,
604 le->command[i].cylinder_low,
605 le->command[i].cylinder_high,
606 le->command[i].device_head,
607 le->command[i].command,
608 le->command[i].timestamp[3],
609 le->command[i].timestamp[2],
610 le->command[i].timestamp[1],
611 le->command[i].timestamp[0]);
612 printf("\tError: err=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x status=%02x state=%02x lifetime=%02x%02x\n",
613 le->error_data.error,
614 le->error_data.sector_count,
615 le->error_data.sector_number,
616 le->error_data.cylinder_low,
617 le->error_data.cylinder_high,
618 le->error_data.device_head,
619 le->error_data.status,
620 le->error_data.state,
621 le->error_data.lifetime[1],
622 le->error_data.lifetime[0]);
623 printf("\tExtended: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
624 le->error_data.extended_error[0],
625 le->error_data.extended_error[1],
626 le->error_data.extended_error[2],
627 le->error_data.extended_error[3],
628 le->error_data.extended_error[4],
629 le->error_data.extended_error[5],
630 le->error_data.extended_error[6],
631 le->error_data.extended_error[7],
632 le->error_data.extended_error[8],
633 le->error_data.extended_error[9],
634 le->error_data.extended_error[10],
635 le->error_data.extended_error[11],
636 le->error_data.extended_error[12],
637 le->error_data.extended_error[13],
638 le->error_data.extended_error[14],
639 le->error_data.extended_error[15],
640 le->error_data.extended_error[15],
641 le->error_data.extended_error[17],
642 le->error_data.extended_error[18]);
645 void
646 print_error(void *buf)
648 struct ata_smart_errorlog *erlog = buf;
649 u_int8_t checksum;
650 int i;
652 for (i = checksum = 0; i < 512; i++)
653 checksum += ((u_int8_t *) buf)[i];
654 if (checksum != 0) {
655 fprintf(stderr, "SMART error log checksum error\n");
656 return;
659 if (erlog->data_structure_revision != 1) {
660 fprintf(stderr, "Error log revision not 1 (found 0x%04x)\n",
661 erlog->data_structure_revision);
662 return;
665 if (erlog->mostrecenterror == 0) {
666 printf("No errors have been logged\n");
667 return;
670 if (erlog->mostrecenterror > 5) {
671 fprintf(stderr, "Most recent error is too large\n");
672 return;
675 for (i = erlog->mostrecenterror; i < 5; i++)
676 print_error_entry(i, &erlog->log_entries[i]);
677 for (i = 0; i < erlog->mostrecenterror; i++)
678 print_error_entry(i, &erlog->log_entries[i]);
679 printf("device error count: %d\n", erlog->device_error_count);
682 void
683 print_selftest_entry(int num, struct ata_smart_selftest *le)
685 unsigned char *p;
686 size_t i;
688 /* check if all zero */
689 for (p = (void *)le, i = 0; i < sizeof(*le); i++)
690 if (p[i] != 0)
691 break;
692 if (i == sizeof(*le))
693 return;
695 printf("Log entry: %d\n", num);
697 /* Get test name */
698 for (i = 0; selftest_name[i].name != NULL; i++)
699 if (selftest_name[i].number == le->number)
700 break;
702 if (selftest_name[i].name == NULL)
703 printf("\tName: (%d)\n", le->number);
704 else
705 printf("\tName: %s\n", selftest_name[i].name);
706 printf("\tStatus: %s\n", selftest_status[le->status >> 4]);
707 /* XXX This generally should not be set when a self-test is completed,
708 and at any rate is useless. - mycroft */
709 if (le->status >> 4 == 15)
710 printf("\tPercent of test remaining: %1d0\n", le->status & 0xf);
711 else if (le->status >> 4 != 0)
712 printf("\tLBA first error: %d\n", le32toh(le->lba_first_error));
715 void
716 print_selftest(void *buf)
718 struct ata_smart_selftestlog *stlog = buf;
719 u_int8_t checksum;
720 int i;
722 for (i = checksum = 0; i < 512; i++)
723 checksum += ((u_int8_t *) buf)[i];
724 if (checksum != 0) {
725 fprintf(stderr, "SMART selftest log checksum error\n");
726 return;
729 if (le16toh(stlog->data_structure_revision) != 1) {
730 fprintf(stderr, "Self-test log revision not 1 (found 0x%04x)\n",
731 le16toh(stlog->data_structure_revision));
732 return;
735 if (stlog->mostrecenttest == 0) {
736 printf("No self-tests have been logged\n");
737 return;
740 if (stlog->mostrecenttest > 22) {
741 fprintf(stderr, "Most recent test is too large\n");
742 return;
745 for (i = stlog->mostrecenttest; i < 22; i++)
746 print_selftest_entry(i, &stlog->log_entries[i]);
747 for (i = 0; i < stlog->mostrecenttest; i++)
748 print_selftest_entry(i, &stlog->log_entries[i]);
751 struct ataparams *
752 getataparams()
754 struct atareq req;
755 static union {
756 unsigned char inbuf[DEV_BSIZE];
757 struct ataparams inqbuf;
758 } inbuf;
760 memset(&inbuf, 0, sizeof(inbuf));
761 memset(&req, 0, sizeof(req));
763 req.flags = ATACMD_READ;
764 req.command = WDCC_IDENTIFY;
765 req.databuf = (caddr_t)&inbuf;
766 req.datalen = sizeof(inbuf);
767 req.timeout = 1000;
769 ata_command(&req);
771 return (&inbuf.inqbuf);
775 * is_smart:
777 * Detect whether device supports SMART and SMART is enabled.
781 is_smart(void)
783 int retval = 0;
784 struct ataparams *inqbuf;
785 const char *status;
787 inqbuf = getataparams();
789 if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
790 if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
791 fprintf(stderr, "SMART unsupported\n");
792 } else {
793 if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
794 inqbuf->atap_cmd_set2 == 0xffff ||
795 inqbuf->atap_cmd_set2 == 0x0000) {
796 status = "status unknown";
797 retval = 2;
798 } else {
799 if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) {
800 status = "enabled";
801 retval = 1;
802 } else {
803 status = "disabled";
804 retval = 3;
807 printf("SMART supported, SMART %s\n", status);
810 return retval;
814 * extract_string: copy a block of bytes out of ataparams and make
815 * a proper string out of it, truncating trailing spaces and preserving
816 * strict typing. And also, not doing unaligned accesses.
818 static void
819 extract_string(char *buf, size_t bufmax,
820 uint8_t *bytes, unsigned numbytes,
821 int needswap)
823 unsigned i;
824 size_t j;
825 unsigned char ch1, ch2;
827 for (i = 0, j = 0; i < numbytes; i += 2) {
828 ch1 = bytes[i];
829 ch2 = bytes[i+1];
830 if (needswap && j < bufmax-1) {
831 buf[j++] = ch2;
833 if (j < bufmax-1) {
834 buf[j++] = ch1;
836 if (!needswap && j < bufmax-1) {
837 buf[j++] = ch2;
840 while (j > 0 && buf[j-1] == ' ') {
841 j--;
843 buf[j] = '\0';
847 * DEVICE COMMANDS
851 * device_identify:
853 * Display the identity of the device
855 void
856 device_identify(int argc, char *argv[])
858 struct ataparams *inqbuf;
859 char model[sizeof(inqbuf->atap_model)+1];
860 char revision[sizeof(inqbuf->atap_revision)+1];
861 char serial[sizeof(inqbuf->atap_serial)+1];
862 uint64_t capacity;
863 int needswap = 0;
865 /* No arguments. */
866 if (argc != 0)
867 usage();
869 inqbuf = getataparams();
871 #if BYTE_ORDER == LITTLE_ENDIAN
873 * On little endian machines, we need to shuffle the string
874 * byte order. However, we don't have to do this for NEC or
875 * Mitsumi ATAPI devices
878 if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI &&
879 ((inqbuf->atap_model[0] == 'N' &&
880 inqbuf->atap_model[1] == 'E') ||
881 (inqbuf->atap_model[0] == 'F' &&
882 inqbuf->atap_model[1] == 'X')))) {
883 needswap = 1;
885 #endif
888 * Copy the info strings out, stripping off blanks.
890 extract_string(model, sizeof(model),
891 inqbuf->atap_model, sizeof(inqbuf->atap_model),
892 needswap);
893 extract_string(revision, sizeof(revision),
894 inqbuf->atap_revision, sizeof(inqbuf->atap_revision),
895 needswap);
896 extract_string(serial, sizeof(serial),
897 inqbuf->atap_serial, sizeof(inqbuf->atap_serial),
898 needswap);
900 printf("Model: %s, Rev: %s, Serial #: %s\n",
901 model, revision, serial);
903 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff &&
904 inqbuf->atap_cmd_ext & ATA_CMDE_WWN)
905 printf("World Wide Name: %016" PRIX64 "\n",
906 ((uint64_t)inqbuf->atap_wwn[0] << 48) |
907 ((uint64_t)inqbuf->atap_wwn[1] << 32) |
908 ((uint64_t)inqbuf->atap_wwn[2] << 16) |
909 ((uint64_t)inqbuf->atap_wwn[3] << 0));
911 printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ?
912 "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" :
913 "removable");
915 capacity = 0;
917 if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff &&
918 inqbuf->atap_cmd2_en & ATA_CMD2_LBA48) {
919 capacity =
920 ((uint64_t)inqbuf->atap_max_lba[3] << 48) |
921 ((uint64_t)inqbuf->atap_max_lba[2] << 32) |
922 ((uint64_t)inqbuf->atap_max_lba[1] << 16) |
923 ((uint64_t)inqbuf->atap_max_lba[0] << 0);
924 } else if (inqbuf->atap_capabilities1 & WDC_CAP_LBA) {
925 capacity = (inqbuf->atap_capacity[1] << 16) |
926 inqbuf->atap_capacity[0];
928 if ((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) != WDC_CFG_ATAPI) {
929 if (capacity == 0)
930 capacity = inqbuf->atap_cylinders *
931 inqbuf->atap_heads * inqbuf->atap_sectors;
932 printf("Cylinders: %d, heads: %d, sec/track: %d, total "
933 "sectors: %" PRIu64 "\n", inqbuf->atap_cylinders,
934 inqbuf->atap_heads, inqbuf->atap_sectors, capacity);
937 if (((inqbuf->atap_sata_caps & SATA_NATIVE_CMDQ) ||
938 (inqbuf->atap_cmd_set2 & ATA_CMD2_RWQ)) &&
939 (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK))
940 printf("Device supports command queue depth of %d\n",
941 (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK) + 1);
943 printf("Device capabilities:\n");
944 print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
946 if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
947 printf("Device supports following standards:\n");
948 print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
949 printf("\n");
952 if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
953 inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
954 printf("Command set support:\n");
955 if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff)
956 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1,
957 inqbuf->atap_cmd1_en, ata_cmd_set1);
958 else
959 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1,
960 ata_cmd_set1);
961 if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff)
962 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2,
963 inqbuf->atap_cmd2_en, ata_cmd_set2);
964 else
965 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2,
966 ata_cmd_set2);
967 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
968 print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
969 ata_cmd_ext);
972 if (inqbuf->atap_sata_caps != 0 && inqbuf->atap_sata_caps != 0xffff) {
973 printf("Serial ATA capabilities:\n");
974 print_bitinfo("\t", "\n",
975 inqbuf->atap_sata_caps, ata_sata_caps);
979 if (inqbuf->atap_sata_features_supp != 0 &&
980 inqbuf->atap_sata_features_supp != 0xffff) {
981 printf("Serial ATA features:\n");
982 if (inqbuf->atap_sata_features_en != 0 &&
983 inqbuf->atap_sata_features_en != 0xffff)
984 print_bitinfo2("\t", "\n",
985 inqbuf->atap_sata_features_supp,
986 inqbuf->atap_sata_features_en, ata_sata_feat);
987 else
988 print_bitinfo("\t", "\n",
989 inqbuf->atap_sata_features_supp, ata_sata_feat);
992 return;
996 * device idle:
998 * issue the IDLE IMMEDIATE command to the drive
1000 void
1001 device_idle(int argc, char *argv[])
1003 struct atareq req;
1005 /* No arguments. */
1006 if (argc != 0)
1007 usage();
1009 memset(&req, 0, sizeof(req));
1011 if (strcmp(cmdname, "idle") == 0)
1012 req.command = WDCC_IDLE_IMMED;
1013 else if (strcmp(cmdname, "standby") == 0)
1014 req.command = WDCC_STANDBY_IMMED;
1015 else
1016 req.command = WDCC_SLEEP;
1018 req.timeout = 1000;
1020 ata_command(&req);
1022 return;
1026 * device apm:
1028 * enable/disable/control the APM feature of the drive
1030 void
1031 device_apm(int argc, char *argv[])
1033 struct atareq req;
1034 long l;
1036 memset(&req, 0, sizeof(req));
1037 if (argc >= 1) {
1038 req.command = SET_FEATURES;
1039 req.timeout = 1000;
1041 if (strcmp(argv[0], "disable") == 0)
1042 req.features = WDSF_APM_DS;
1043 else if (strcmp(argv[0], "set") == 0 && argc >= 2 &&
1044 (l = strtol(argv[1], NULL, 0)) >= 0 && l <= 253) {
1046 req.features = WDSF_APM_EN;
1047 req.sec_count = l + 1;
1048 } else
1049 usage();
1050 } else
1051 usage();
1053 ata_command(&req);
1058 * Set the idle timer on the disk. Set it for either idle mode or
1059 * standby mode, depending on how we were invoked.
1062 void
1063 device_setidle(int argc, char *argv[])
1065 unsigned long idle;
1066 struct atareq req;
1067 char *end;
1069 /* Only one argument */
1070 if (argc != 1)
1071 usage();
1073 idle = strtoul(argv[0], &end, 0);
1075 if (*end != '\0') {
1076 fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
1077 exit(1);
1080 if (idle > 19800) {
1081 fprintf(stderr, "Idle time has a maximum value of 5.5 "
1082 "hours\n");
1083 exit(1);
1086 if (idle != 0 && idle < 5) {
1087 fprintf(stderr, "Idle timer must be at least 5 seconds\n");
1088 exit(1);
1091 memset(&req, 0, sizeof(req));
1093 if (idle <= 240*5)
1094 req.sec_count = idle / 5;
1095 else
1096 req.sec_count = idle / (30*60) + 240;
1098 req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
1099 req.timeout = 1000;
1101 ata_command(&req);
1103 return;
1107 * Query the device for the current power mode
1110 void
1111 device_checkpower(int argc, char *argv[])
1113 struct atareq req;
1115 /* No arguments. */
1116 if (argc != 0)
1117 usage();
1119 memset(&req, 0, sizeof(req));
1121 req.command = WDCC_CHECK_PWR;
1122 req.timeout = 1000;
1123 req.flags = ATACMD_READREG;
1125 ata_command(&req);
1127 printf("Current power status: ");
1129 switch (req.sec_count) {
1130 case 0x00:
1131 printf("Standby mode\n");
1132 break;
1133 case 0x80:
1134 printf("Idle mode\n");
1135 break;
1136 case 0xff:
1137 printf("Active mode\n");
1138 break;
1139 default:
1140 printf("Unknown power code (%02x)\n", req.sec_count);
1143 return;
1147 * device_smart:
1149 * Display SMART status
1151 void
1152 device_smart(int argc, char *argv[])
1154 struct atareq req;
1155 unsigned char inbuf[DEV_BSIZE];
1156 unsigned char inbuf2[DEV_BSIZE];
1158 if (argc < 1)
1159 usage();
1161 if (strcmp(argv[0], "enable") == 0) {
1162 memset(&req, 0, sizeof(req));
1164 req.features = WDSM_ENABLE_OPS;
1165 req.command = WDCC_SMART;
1166 req.cylinder = WDSMART_CYL;
1167 req.timeout = 1000;
1169 ata_command(&req);
1171 is_smart();
1172 } else if (strcmp(argv[0], "disable") == 0) {
1173 memset(&req, 0, sizeof(req));
1175 req.features = WDSM_DISABLE_OPS;
1176 req.command = WDCC_SMART;
1177 req.cylinder = WDSMART_CYL;
1178 req.timeout = 1000;
1180 ata_command(&req);
1182 is_smart();
1183 } else if (strcmp(argv[0], "status") == 0) {
1184 int rv;
1186 rv = is_smart();
1188 if (!rv) {
1189 fprintf(stderr, "SMART not supported\n");
1190 return;
1191 } else if (rv == 3)
1192 return;
1194 memset(&inbuf, 0, sizeof(inbuf));
1195 memset(&req, 0, sizeof(req));
1197 req.features = WDSM_STATUS;
1198 req.command = WDCC_SMART;
1199 req.cylinder = WDSMART_CYL;
1200 req.timeout = 1000;
1202 ata_command(&req);
1204 if (req.cylinder != WDSMART_CYL) {
1205 fprintf(stderr, "Threshold exceeds condition\n");
1208 /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
1209 * features, the following ata_command()'s may error
1210 * and exit().
1213 memset(&inbuf, 0, sizeof(inbuf));
1214 memset(&req, 0, sizeof(req));
1216 req.flags = ATACMD_READ;
1217 req.features = WDSM_RD_DATA;
1218 req.command = WDCC_SMART;
1219 req.databuf = (caddr_t) inbuf;
1220 req.datalen = sizeof(inbuf);
1221 req.cylinder = WDSMART_CYL;
1222 req.timeout = 1000;
1224 ata_command(&req);
1226 memset(&inbuf2, 0, sizeof(inbuf2));
1227 memset(&req, 0, sizeof(req));
1229 req.flags = ATACMD_READ;
1230 req.features = WDSM_RD_THRESHOLDS;
1231 req.command = WDCC_SMART;
1232 req.databuf = (caddr_t) inbuf2;
1233 req.datalen = sizeof(inbuf2);
1234 req.cylinder = WDSMART_CYL;
1235 req.timeout = 1000;
1237 ata_command(&req);
1239 print_smart_status(inbuf, inbuf2);
1241 } else if (strcmp(argv[0], "offline") == 0) {
1242 if (argc != 2)
1243 usage();
1244 if (!is_smart()) {
1245 fprintf(stderr, "SMART not supported\n");
1246 return;
1249 memset(&req, 0, sizeof(req));
1251 req.features = WDSM_EXEC_OFFL_IMM;
1252 req.command = WDCC_SMART;
1253 req.cylinder = WDSMART_CYL;
1254 req.sec_num = atol(argv[1]);
1255 req.timeout = 10000;
1257 ata_command(&req);
1258 } else if (strcmp(argv[0], "error-log") == 0) {
1259 if (!is_smart()) {
1260 fprintf(stderr, "SMART not supported\n");
1261 return;
1264 memset(&inbuf, 0, sizeof(inbuf));
1265 memset(&req, 0, sizeof(req));
1267 req.flags = ATACMD_READ;
1268 req.features = WDSM_RD_LOG;
1269 req.sec_count = 1;
1270 req.sec_num = 1;
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;
1277 ata_command(&req);
1279 print_error(inbuf);
1280 } else if (strcmp(argv[0], "selftest-log") == 0) {
1281 if (!is_smart()) {
1282 fprintf(stderr, "SMART not supported\n");
1283 return;
1286 memset(&inbuf, 0, sizeof(inbuf));
1287 memset(&req, 0, sizeof(req));
1289 req.flags = ATACMD_READ;
1290 req.features = WDSM_RD_LOG;
1291 req.sec_count = 1;
1292 req.sec_num = 6;
1293 req.command = WDCC_SMART;
1294 req.databuf = (caddr_t) inbuf;
1295 req.datalen = sizeof(inbuf);
1296 req.cylinder = WDSMART_CYL;
1297 req.timeout = 1000;
1299 ata_command(&req);
1301 print_selftest(inbuf);
1303 } else {
1304 usage();
1306 return;
1309 void
1310 device_security(int argc, char *argv[])
1312 struct atareq req;
1313 struct ataparams *inqbuf;
1315 /* need subcommand */
1316 if (argc < 1)
1317 usage();
1319 if (strcmp(argv[0], "freeze") == 0) {
1320 memset(&req, 0, sizeof(req));
1321 req.command = WDCC_SECURITY_FREEZE;
1322 req.timeout = 1000;
1323 ata_command(&req);
1324 } else if (strcmp(argv[0], "status") == 0) {
1325 inqbuf = getataparams();
1326 print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
1327 } else
1328 usage();
1330 return;
1334 * bus_reset:
1335 * Reset an ATA bus (will reset all devices on the bus)
1337 void
1338 bus_reset(int argc, char *argv[])
1340 int error;
1342 /* no args */
1343 if (argc != 0)
1344 usage();
1346 error = ioctl(fd, ATABUSIORESET, NULL);
1348 if (error == -1)
1349 err(1, "ATABUSIORESET failed");