1 /* $NetBSD: atactl.c,v 1.54 2009/06/06 09:18:55 mlelstv Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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>
38 __RCSID("$NetBSD: atactl.c,v 1.54 2009/06/06 09:18:55 mlelstv Exp $");
42 #include <sys/param.h>
43 #include <sys/ioctl.h>
53 #include <dev/ata/atareg.h>
54 #include <sys/ataio.h>
56 struct ata_smart_error
{
58 u_int8_t device_control
;
60 u_int8_t sector_count
;
61 u_int8_t sector_number
;
62 u_int8_t cylinder_low
;
63 u_int8_t cylinder_high
;
66 u_int8_t timestamp
[4];
71 u_int8_t sector_count
;
72 u_int8_t sector_number
;
73 u_int8_t cylinder_low
;
74 u_int8_t cylinder_high
;
77 u_int8_t extended_error
[19];
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];
94 const char *arg_names
;
95 void (*cmd_func
)(int, char *[]);
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);
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",
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" },
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" },
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" },
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" },
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" },
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" },
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" },
251 static const struct {
254 void (*special
)(struct ata_smart_attr
*, uint64_t);
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" },
318 main(int argc
, char *argv
[])
321 struct command
*commands
= NULL
;
323 /* Must have at least: device command */
327 /* Skip program name, get and skip device name and command. */
336 fd
= opendisk(dvname
, O_RDWR
, dvname_store
, sizeof(dvname_store
), 0);
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
346 fd
= opendisk(dvname
, O_RDWR
, dvname_store
,
347 sizeof(dvname_store
), 1);
349 err(1, "%s", dvname
);
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
];
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
];
374 if (commands
== NULL
)
375 errx(1, "unknown command: %s", cmdname
);
377 argnames
= commands
->arg_names
;
379 (*commands
->cmd_func
)(argc
, argv
);
388 fprintf(stderr
, "usage: %s device command [arg [...]]\n",
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
);
405 * Wrapper that calls ATAIOCCOMMAND and checks for errors
409 ata_command(struct atareq
*req
)
413 error
= ioctl(fd
, ATAIOCCOMMAND
, req
);
416 err(1, "ATAIOCCOMMAND failed");
418 switch (req
->retsts
) {
423 fprintf(stderr
, "ATA command timed out\n");
426 fprintf(stderr
, "ATA device returned a Device Fault\n");
429 if (req
->error
& WDCE_ABRT
)
430 fprintf(stderr
, "ATA device returned Aborted "
433 fprintf(stderr
, "ATA device returned error register "
434 "%0x\n", req
->error
);
437 fprintf(stderr
, "ATAIOCCOMMAND returned unknown result code "
438 "%d\n", req
->retsts
);
444 * Print out strings associated with particular bitmasks
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
);
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",
469 * Try to print SMART temperature field
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
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
;
498 for (i
= checksum
= 0; i
< 512; i
++)
499 checksum
+= ((u_int8_t
*) value_buf
)[i
];
501 fprintf(stderr
, "SMART attribute values checksum error\n");
505 for (i
= checksum
= 0; i
< 512; i
++)
506 checksum
+= ((u_int8_t
*) threshold_buf
)[i
];
508 fprintf(stderr
, "SMART attribute thresholds checksum error\n");
512 printf("id value thresh crit collect reliability description\t\t\traw\n");
513 for (i
= 0; i
< 256; i
++) {
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
);
530 if (attr
->value
== 0||attr
->value
== 0xFE||attr
->value
== 0xFF)
534 smart_attrs
[aid
].id
!= i
&& smart_attrs
[aid
].id
!= 0;
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
);
553 printf("%" PRIu64
, raw_value
);
561 } selftest_name
[] = {
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 */
572 const char *selftest_status
[] = {
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",
588 "Self-test in progress"
592 print_error_entry(int num
, struct ata_smart_error
*le
)
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]);
646 print_error(void *buf
)
648 struct ata_smart_errorlog
*erlog
= buf
;
652 for (i
= checksum
= 0; i
< 512; i
++)
653 checksum
+= ((u_int8_t
*) buf
)[i
];
655 fprintf(stderr
, "SMART error log checksum error\n");
659 if (erlog
->data_structure_revision
!= 1) {
660 fprintf(stderr
, "Error log revision not 1 (found 0x%04x)\n",
661 erlog
->data_structure_revision
);
665 if (erlog
->mostrecenterror
== 0) {
666 printf("No errors have been logged\n");
670 if (erlog
->mostrecenterror
> 5) {
671 fprintf(stderr
, "Most recent error is too large\n");
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
);
683 print_selftest_entry(int num
, struct ata_smart_selftest
*le
)
688 /* check if all zero */
689 for (p
= (void *)le
, i
= 0; i
< sizeof(*le
); i
++)
692 if (i
== sizeof(*le
))
695 printf("Log entry: %d\n", num
);
698 for (i
= 0; selftest_name
[i
].name
!= NULL
; i
++)
699 if (selftest_name
[i
].number
== le
->number
)
702 if (selftest_name
[i
].name
== NULL
)
703 printf("\tName: (%d)\n", le
->number
);
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
));
716 print_selftest(void *buf
)
718 struct ata_smart_selftestlog
*stlog
= buf
;
722 for (i
= checksum
= 0; i
< 512; i
++)
723 checksum
+= ((u_int8_t
*) buf
)[i
];
725 fprintf(stderr
, "SMART selftest log checksum error\n");
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
));
735 if (stlog
->mostrecenttest
== 0) {
736 printf("No self-tests have been logged\n");
740 if (stlog
->mostrecenttest
> 22) {
741 fprintf(stderr
, "Most recent test is too large\n");
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
]);
756 unsigned char inbuf
[DEV_BSIZE
];
757 struct ataparams inqbuf
;
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
);
771 return (&inbuf
.inqbuf
);
777 * Detect whether device supports SMART and SMART is enabled.
784 struct ataparams
*inqbuf
;
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");
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";
799 if (inqbuf
->atap_cmd1_en
& WDC_CMD1_SMART
) {
807 printf("SMART supported, SMART %s\n", status
);
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.
819 extract_string(char *buf
, size_t bufmax
,
820 uint8_t *bytes
, unsigned numbytes
,
825 unsigned char ch1
, ch2
;
827 for (i
= 0, j
= 0; i
< numbytes
; i
+= 2) {
830 if (needswap
&& j
< bufmax
-1) {
836 if (!needswap
&& j
< bufmax
-1) {
840 while (j
> 0 && buf
[j
-1] == ' ') {
853 * Display the identity of the device
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];
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')))) {
888 * Copy the info strings out, stripping off blanks.
890 extract_string(model
, sizeof(model
),
891 inqbuf
->atap_model
, sizeof(inqbuf
->atap_model
),
893 extract_string(revision
, sizeof(revision
),
894 inqbuf
->atap_revision
, sizeof(inqbuf
->atap_revision
),
896 extract_string(serial
, sizeof(serial
),
897 inqbuf
->atap_serial
, sizeof(inqbuf
->atap_serial
),
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" :
917 if (inqbuf
->atap_cmd2_en
!= 0 && inqbuf
->atap_cmd2_en
!= 0xffff &&
918 inqbuf
->atap_cmd2_en
& ATA_CMD2_LBA48
) {
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
) {
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
);
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
);
959 print_bitinfo("\t", "\n", inqbuf
->atap_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
);
965 print_bitinfo("\t", "\n", inqbuf
->atap_cmd_set2
,
967 if (inqbuf
->atap_cmd_ext
!= 0 && inqbuf
->atap_cmd_ext
!= 0xffff)
968 print_bitinfo("\t", "\n", inqbuf
->atap_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
);
988 print_bitinfo("\t", "\n",
989 inqbuf
->atap_sata_features_supp
, ata_sata_feat
);
998 * issue the IDLE IMMEDIATE command to the drive
1001 device_idle(int argc
, char *argv
[])
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
;
1016 req
.command
= WDCC_SLEEP
;
1028 * enable/disable/control the APM feature of the drive
1031 device_apm(int argc
, char *argv
[])
1036 memset(&req
, 0, sizeof(req
));
1038 req
.command
= SET_FEATURES
;
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;
1058 * Set the idle timer on the disk. Set it for either idle mode or
1059 * standby mode, depending on how we were invoked.
1063 device_setidle(int argc
, char *argv
[])
1069 /* Only one argument */
1073 idle
= strtoul(argv
[0], &end
, 0);
1076 fprintf(stderr
, "Invalid idle time: \"%s\"\n", argv
[0]);
1081 fprintf(stderr
, "Idle time has a maximum value of 5.5 "
1086 if (idle
!= 0 && idle
< 5) {
1087 fprintf(stderr
, "Idle timer must be at least 5 seconds\n");
1091 memset(&req
, 0, sizeof(req
));
1094 req
.sec_count
= idle
/ 5;
1096 req
.sec_count
= idle
/ (30*60) + 240;
1098 req
.command
= cmdname
[3] == 's' ? WDCC_STANDBY
: WDCC_IDLE
;
1107 * Query the device for the current power mode
1111 device_checkpower(int argc
, char *argv
[])
1119 memset(&req
, 0, sizeof(req
));
1121 req
.command
= WDCC_CHECK_PWR
;
1123 req
.flags
= ATACMD_READREG
;
1127 printf("Current power status: ");
1129 switch (req
.sec_count
) {
1131 printf("Standby mode\n");
1134 printf("Idle mode\n");
1137 printf("Active mode\n");
1140 printf("Unknown power code (%02x)\n", req
.sec_count
);
1149 * Display SMART status
1152 device_smart(int argc
, char *argv
[])
1155 unsigned char inbuf
[DEV_BSIZE
];
1156 unsigned char inbuf2
[DEV_BSIZE
];
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
;
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
;
1183 } else if (strcmp(argv
[0], "status") == 0) {
1189 fprintf(stderr
, "SMART not supported\n");
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
;
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
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
;
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
;
1239 print_smart_status(inbuf
, inbuf2
);
1241 } else if (strcmp(argv
[0], "offline") == 0) {
1245 fprintf(stderr
, "SMART not supported\n");
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;
1258 } else if (strcmp(argv
[0], "error-log") == 0) {
1260 fprintf(stderr
, "SMART not supported\n");
1264 memset(&inbuf
, 0, sizeof(inbuf
));
1265 memset(&req
, 0, sizeof(req
));
1267 req
.flags
= ATACMD_READ
;
1268 req
.features
= WDSM_RD_LOG
;
1271 req
.command
= WDCC_SMART
;
1272 req
.databuf
= (caddr_t
) inbuf
;
1273 req
.datalen
= sizeof(inbuf
);
1274 req
.cylinder
= WDSMART_CYL
;
1280 } else if (strcmp(argv
[0], "selftest-log") == 0) {
1282 fprintf(stderr
, "SMART not supported\n");
1286 memset(&inbuf
, 0, sizeof(inbuf
));
1287 memset(&req
, 0, sizeof(req
));
1289 req
.flags
= ATACMD_READ
;
1290 req
.features
= WDSM_RD_LOG
;
1293 req
.command
= WDCC_SMART
;
1294 req
.databuf
= (caddr_t
) inbuf
;
1295 req
.datalen
= sizeof(inbuf
);
1296 req
.cylinder
= WDSMART_CYL
;
1301 print_selftest(inbuf
);
1310 device_security(int argc
, char *argv
[])
1313 struct ataparams
*inqbuf
;
1315 /* need subcommand */
1319 if (strcmp(argv
[0], "freeze") == 0) {
1320 memset(&req
, 0, sizeof(req
));
1321 req
.command
= WDCC_SECURITY_FREEZE
;
1324 } else if (strcmp(argv
[0], "status") == 0) {
1325 inqbuf
= getataparams();
1326 print_bitinfo("\t", "\n", inqbuf
->atap_sec_st
, ata_sec_st
);
1335 * Reset an ATA bus (will reset all devices on the bus)
1338 bus_reset(int argc
, char *argv
[])
1346 error
= ioctl(fd
, ATABUSIORESET
, NULL
);
1349 err(1, "ATABUSIORESET failed");