atactl.c revision 1.49 1 /* $NetBSD: atactl.c,v 1.49 2007/12/15 16:03:29 perry 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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * atactl(8) - a program to control ATA devices.
41 */
42 #include <sys/cdefs.h>
43
44 #ifndef lint
45 __RCSID("$NetBSD: atactl.c,v 1.49 2007/12/15 16:03:29 perry Exp $");
46 #endif
47
48
49 #include <sys/param.h>
50 #include <sys/ioctl.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <util.h>
59
60 #include <dev/ata/atareg.h>
61 #include <sys/ataio.h>
62
63 struct ata_smart_error {
64 struct {
65 u_int8_t device_control;
66 u_int8_t features;
67 u_int8_t sector_count;
68 u_int8_t sector_number;
69 u_int8_t cylinder_low;
70 u_int8_t cylinder_high;
71 u_int8_t device_head;
72 u_int8_t command;
73 u_int8_t timestamp[4];
74 } command[5];
75 struct {
76 u_int8_t reserved;
77 u_int8_t error;
78 u_int8_t sector_count;
79 u_int8_t sector_number;
80 u_int8_t cylinder_low;
81 u_int8_t cylinder_high;
82 u_int8_t device_head;
83 u_int8_t status;
84 u_int8_t extended_error[19];
85 u_int8_t state;
86 u_int8_t lifetime[2];
87 } error_data;
88 } __packed;
89
90 struct ata_smart_errorlog {
91 u_int8_t data_structure_revision;
92 u_int8_t mostrecenterror;
93 struct ata_smart_error log_entries[5];
94 u_int16_t device_error_count;
95 u_int8_t reserved[57];
96 u_int8_t checksum;
97 } __packed;
98
99 struct command {
100 const char *cmd_name;
101 const char *arg_names;
102 void (*cmd_func)(int, char *[]);
103 };
104
105 struct bitinfo {
106 u_int bitmask;
107 const char *string;
108 };
109
110 void usage(void);
111 void ata_command(struct atareq *);
112 void print_bitinfo(const char *, const char *, u_int, struct bitinfo *);
113 void print_bitinfo2(const char *, const char *, u_int, u_int, struct bitinfo *);
114 void print_smart_status(void *, void *);
115 void print_error_entry(int, struct ata_smart_error *);
116 void print_selftest_entry(int, struct ata_smart_selftest *);
117
118 void print_error(void *);
119 void print_selftest(void *);
120
121 struct ataparams *getataparams(void);
122
123 int is_smart(void);
124
125 int fd; /* file descriptor for device */
126 const char *dvname; /* device name */
127 char dvname_store[MAXPATHLEN]; /* for opendisk(3) */
128 const char *cmdname; /* command user issued */
129 const char *argnames; /* helpstring: expected arguments */
130
131 void device_identify(int, char *[]);
132 void device_setidle(int, char *[]);
133 void device_idle(int, char *[]);
134 void device_apm(int, char *[]);
135 void device_checkpower(int, char *[]);
136 void device_smart(int, char *[]);
137 void device_security(int, char *[]);
138
139 void device_smart_temp(struct ata_smart_attr *, uint64_t);
140
141 struct command device_commands[] = {
142 { "identify", "", device_identify },
143 { "setidle", "idle-timer", device_setidle },
144 { "apm", "disable|set #", device_apm },
145 { "setstandby", "standby-timer", device_setidle },
146 { "idle", "", device_idle },
147 { "standby", "", device_idle },
148 { "sleep", "", device_idle },
149 { "checkpower", "", device_checkpower },
150 { "smart", "enable|disable|status|offline #|error-log|selftest-log",
151 device_smart },
152 { "security", "freeze|status", device_security },
153 { NULL, NULL, NULL },
154 };
155
156 void bus_reset(int, char *[]);
157
158 struct command bus_commands[] = {
159 { "reset", "", bus_reset },
160 { NULL, NULL, NULL },
161 };
162
163 /*
164 * Tables containing bitmasks used for error reporting and
165 * device identification.
166 */
167
168 struct bitinfo ata_caps[] = {
169 { WDC_CAP_DMA, "DMA" },
170 { WDC_CAP_LBA, "LBA" },
171 { ATA_CAP_STBY, "ATA standby timer values" },
172 { WDC_CAP_IORDY, "IORDY operation" },
173 { WDC_CAP_IORDY_DSBL, "IORDY disabling" },
174 { 0, NULL },
175 };
176
177 struct bitinfo ata_vers[] = {
178 { WDC_VER_ATA1, "ATA-1" },
179 { WDC_VER_ATA2, "ATA-2" },
180 { WDC_VER_ATA3, "ATA-3" },
181 { WDC_VER_ATA4, "ATA-4" },
182 { WDC_VER_ATA5, "ATA-5" },
183 { WDC_VER_ATA6, "ATA-6" },
184 { WDC_VER_ATA7, "ATA-7" },
185 { 0, NULL },
186 };
187
188 struct bitinfo ata_cmd_set1[] = {
189 { WDC_CMD1_NOP, "NOP command" },
190 { WDC_CMD1_RB, "READ BUFFER command" },
191 { WDC_CMD1_WB, "WRITE BUFFER command" },
192 { WDC_CMD1_HPA, "Host Protected Area feature set" },
193 { WDC_CMD1_DVRST, "DEVICE RESET command" },
194 { WDC_CMD1_SRV, "SERVICE interrupt" },
195 { WDC_CMD1_RLSE, "release interrupt" },
196 { WDC_CMD1_AHEAD, "look-ahead" },
197 { WDC_CMD1_CACHE, "write cache" },
198 { WDC_CMD1_PKT, "PACKET command feature set" },
199 { WDC_CMD1_PM, "Power Management feature set" },
200 { WDC_CMD1_REMOV, "Removable Media feature set" },
201 { WDC_CMD1_SEC, "Security Mode feature set" },
202 { WDC_CMD1_SMART, "SMART feature set" },
203 { 0, NULL },
204 };
205
206 struct bitinfo ata_cmd_set2[] = {
207 { ATA_CMD2_FCE, "FLUSH CACHE EXT command" },
208 { WDC_CMD2_FC, "FLUSH CACHE command" },
209 { WDC_CMD2_DCO, "Device Configuration Overlay feature set" },
210 { ATA_CMD2_LBA48, "48-bit Address feature set" },
211 { WDC_CMD2_AAM, "Automatic Acoustic Management feature set" },
212 { WDC_CMD2_SM, "SET MAX security extension" },
213 { WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" },
214 { WDC_CMD2_PUIS, "Power-Up In Standby feature set" },
215 { WDC_CMD2_RMSN, "Removable Media Status Notification feature set" },
216 { ATA_CMD2_APM, "Advanced Power Management feature set" },
217 { ATA_CMD2_CFA, "CFA feature set" },
218 { ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" },
219 { WDC_CMD2_DM, "DOWNLOAD MICROCODE command" },
220 { 0, NULL },
221 };
222
223 struct bitinfo ata_cmd_ext[] = {
224 { ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" },
225 { ATA_CMDE_TL, "Time-limited Read/Write" },
226 { ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" },
227 { ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" },
228 { ATA_CMDE_WWN, "World Wide name" },
229 { ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" },
230 { ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" },
231 { ATA_CMDE_GPL, "General Purpose Logging feature set" },
232 { ATA_CMDE_STREAM, "Streaming feature set" },
233 { ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" },
234 { ATA_CMDE_MS, "Media serial number" },
235 { ATA_CMDE_SST, "SMART self-test" },
236 { ATA_CMDE_SEL, "SMART error logging" },
237 { 0, NULL },
238 };
239
240 struct bitinfo ata_sata_caps[] = {
241 { SATA_SIGNAL_GEN1, "1.5Gb/s signaling" },
242 { SATA_SIGNAL_GEN2, "3.0Gb/s signaling" },
243 { SATA_NATIVE_CMDQ, "Native Command Queuing" },
244 { SATA_HOST_PWR_MGMT, "Host-Initiated Interface Power Management" },
245 { SATA_PHY_EVNT_CNT, "PHY Event Counters" },
246 { 0, NULL },
247 };
248
249 struct bitinfo ata_sata_feat[] = {
250 { SATA_NONZERO_OFFSETS, "Non-zero Offset DMA" },
251 { SATA_DMA_SETUP_AUTO, "DMA Setup Auto Activate" },
252 { SATA_DRIVE_PWR_MGMT, "Device-Initiated Interface Power Managment" },
253 { SATA_IN_ORDER_DATA, "In-order Data Delivery" },
254 { SATA_SW_STTNGS_PRS, "Software Settings Preservation" },
255 { 0, NULL },
256 };
257
258 static const struct {
259 const int id;
260 const char *name;
261 void (*special)(struct ata_smart_attr *, uint64_t);
262 } smart_attrs[] = {
263 { 1, "Raw read error rate", NULL },
264 { 2, "Throughput performance", NULL },
265 { 3, "Spin-up time", NULL },
266 { 4, "Start/stop count", NULL },
267 { 5, "Reallocated sector count", NULL },
268 { 6, "Read channel margin", NULL },
269 { 7, "Seek error rate", NULL },
270 { 8, "Seek time performance", NULL },
271 { 9, "Power-on hours count", NULL },
272 { 10, "Spin retry count", NULL },
273 { 11, "Calibration retry count", NULL },
274 { 12, "Device power cycle count", NULL },
275 { 191, "Gsense 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 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 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 argnames = commands->arg_names;
382
383 (*commands->cmd_func)(argc, argv);
384 exit(0);
385 }
386
387 void
388 usage(void)
389 {
390 int i;
391
392 fprintf(stderr, "usage: %s device command [arg [...]]\n",
393 getprogname());
394
395 fprintf(stderr, " Available device commands:\n");
396 for (i=0; device_commands[i].cmd_name != NULL; i++)
397 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
398 device_commands[i].arg_names);
399
400 fprintf(stderr, " Available bus commands:\n");
401 for (i=0; bus_commands[i].cmd_name != NULL; i++)
402 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
403 bus_commands[i].arg_names);
404
405 exit(1);
406 }
407
408 /*
409 * Wrapper that calls ATAIOCCOMMAND and checks for errors
410 */
411
412 void
413 ata_command(struct atareq *req)
414 {
415 int error;
416
417 error = ioctl(fd, ATAIOCCOMMAND, req);
418
419 if (error == -1)
420 err(1, "ATAIOCCOMMAND failed");
421
422 switch (req->retsts) {
423
424 case ATACMD_OK:
425 return;
426 case ATACMD_TIMEOUT:
427 fprintf(stderr, "ATA command timed out\n");
428 exit(1);
429 case ATACMD_DF:
430 fprintf(stderr, "ATA device returned a Device Fault\n");
431 exit(1);
432 case ATACMD_ERROR:
433 if (req->error & WDCE_ABRT)
434 fprintf(stderr, "ATA device returned Aborted "
435 "Command\n");
436 else
437 fprintf(stderr, "ATA device returned error register "
438 "%0x\n", req->error);
439 exit(1);
440 default:
441 fprintf(stderr, "ATAIOCCOMMAND returned unknown result code "
442 "%d\n", req->retsts);
443 exit(1);
444 }
445 }
446
447 /*
448 * Print out strings associated with particular bitmasks
449 */
450
451 void
452 print_bitinfo(const char *bf, const char *af, u_int bits, struct bitinfo *binfo)
453 {
454
455 for (; binfo->bitmask != 0; binfo++)
456 if (bits & binfo->bitmask)
457 printf("%s%s%s", bf, binfo->string, af);
458 }
459
460 void
461 print_bitinfo2(const char *bf, const char *af, u_int bits, u_int enables, 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 void
477 device_smart_temp(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 max/min %" PRIu8 "/%" PRIu8,
482 attr->raw[2], attr->raw[4]);
483 }
484
485
486 /*
487 * Print out SMART attribute thresholds and values
488 */
489
490 void
491 print_smart_status(void *vbuf, void *tbuf)
492 {
493 struct ata_smart_attributes *value_buf = vbuf;
494 struct ata_smart_thresholds *threshold_buf = tbuf;
495 struct ata_smart_attr *attr;
496 uint64_t raw_value;
497 int flags;
498 int i, j;
499 int aid;
500 u_int8_t checksum;
501
502 for (i = checksum = 0; i < 512; i++)
503 checksum += ((u_int8_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 += ((u_int8_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\t\t\traw\n");
517 for (i = 0; i < 256; i++) {
518 int thresh = 0;
519
520 attr = NULL;
521
522 for (j = 0; j < 30; j++) {
523 if (value_buf->attributes[j].id == i)
524 attr = &value_buf->attributes[j];
525 if (threshold_buf->thresholds[j].id == i)
526 thresh = threshold_buf->thresholds[j].value;
527 }
528
529 if (thresh && attr == NULL)
530 errx(1, "threshold but not attr %d", i);
531 if (attr == NULL)
532 continue;
533
534 if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF)
535 continue;
536
537 for (aid = 0;
538 smart_attrs[aid].id != i && smart_attrs[aid].id != 0;
539 aid++)
540 ;
541
542 flags = le16toh(attr->flags);
543
544 printf("%3d %3d %3d %-3s %-7s %stive %-24s\t",
545 i, attr->value, thresh,
546 flags & WDSM_ATTR_ADVISORY ? "yes" : "no",
547 flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline",
548 attr->value > thresh ? "posi" : "nega",
549 smart_attrs[aid].name);
550
551 for (j = 0, raw_value = 0; j < 6; j++)
552 raw_value += ((uint64_t)attr->raw[j]) << (8*j);
553
554 if (smart_attrs[aid].special)
555 (*smart_attrs[aid].special)(attr, raw_value);
556 else
557 printf("%" PRIu64, raw_value);
558 printf("\n");
559 }
560 }
561
562 struct {
563 int number;
564 const char *name;
565 } selftest_name[] = {
566 { 0, "Off-line" },
567 { 1, "Short off-line" },
568 { 2, "Extended off-line" },
569 { 127, "Abort off-line test" },
570 { 129, "Short captive" },
571 { 130, "Extended captive" },
572 { 256, "Unknown test" }, /* larger then u_int8_t */
573 { 0, NULL }
574 };
575
576 const char *selftest_status[] = {
577 "No error",
578 "Aborted by the host",
579 "Interrupted by the host by reset",
580 "Fatal error or unknown test error",
581 "Unknown test element failed",
582 "Electrical test element failed",
583 "The Servo (and/or seek) test element failed",
584 "Read element of test failed",
585 "Reserved",
586 "Reserved",
587 "Reserved",
588 "Reserved",
589 "Reserved",
590 "Reserved",
591 "Reserved",
592 "Self-test in progress"
593 };
594
595 void
596 print_error_entry(int num, struct ata_smart_error *le)
597 {
598 int i;
599
600 printf("Log entry: %d\n", num);
601
602 for (i = 0; i < 5; i++)
603 printf("\tCommand %d: dc=%02x sf=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x cmd=%02x time=%02x%02x%02x%02x\n", i,
604 le->command[i].device_control,
605 le->command[i].features,
606 le->command[i].sector_count,
607 le->command[i].sector_number,
608 le->command[i].cylinder_low,
609 le->command[i].cylinder_high,
610 le->command[i].device_head,
611 le->command[i].command,
612 le->command[i].timestamp[3],
613 le->command[i].timestamp[2],
614 le->command[i].timestamp[1],
615 le->command[i].timestamp[0]);
616 printf("\tError: err=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x status=%02x state=%02x lifetime=%02x%02x\n",
617 le->error_data.error,
618 le->error_data.sector_count,
619 le->error_data.sector_number,
620 le->error_data.cylinder_low,
621 le->error_data.cylinder_high,
622 le->error_data.device_head,
623 le->error_data.status,
624 le->error_data.state,
625 le->error_data.lifetime[1],
626 le->error_data.lifetime[0]);
627 printf("\tExtended: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
628 le->error_data.extended_error[0],
629 le->error_data.extended_error[1],
630 le->error_data.extended_error[2],
631 le->error_data.extended_error[3],
632 le->error_data.extended_error[4],
633 le->error_data.extended_error[5],
634 le->error_data.extended_error[6],
635 le->error_data.extended_error[7],
636 le->error_data.extended_error[8],
637 le->error_data.extended_error[9],
638 le->error_data.extended_error[10],
639 le->error_data.extended_error[11],
640 le->error_data.extended_error[12],
641 le->error_data.extended_error[13],
642 le->error_data.extended_error[14],
643 le->error_data.extended_error[15],
644 le->error_data.extended_error[15],
645 le->error_data.extended_error[17],
646 le->error_data.extended_error[18]);
647 }
648
649 void
650 print_error(void *buf)
651 {
652 struct ata_smart_errorlog *erlog = buf;
653 u_int8_t checksum;
654 int i;
655
656 for (i = checksum = 0; i < 512; i++)
657 checksum += ((u_int8_t *) buf)[i];
658 if (checksum != 0) {
659 fprintf(stderr, "SMART error log checksum error\n");
660 return;
661 }
662
663 if (erlog->data_structure_revision != 1) {
664 fprintf(stderr, "Error log revision not 1 (found 0x%04x)\n",
665 erlog->data_structure_revision);
666 return;
667 }
668
669 if (erlog->mostrecenterror == 0) {
670 printf("No errors have been logged\n");
671 return;
672 }
673
674 if (erlog->mostrecenterror > 5) {
675 fprintf(stderr, "Most recent error is too large\n");
676 return;
677 }
678
679 for (i = erlog->mostrecenterror; i < 5; i++)
680 print_error_entry(i, &erlog->log_entries[i]);
681 for (i = 0; i < erlog->mostrecenterror; i++)
682 print_error_entry(i, &erlog->log_entries[i]);
683 printf("device error count: %d\n", erlog->device_error_count);
684 }
685
686 void
687 print_selftest_entry(int num, struct ata_smart_selftest *le)
688 {
689 unsigned char *p;
690 int i;
691
692 /* check if all zero */
693 for (p = (void *)le, i = 0; i < sizeof(*le); i++)
694 if (p[i] != 0)
695 break;
696 if (i == sizeof(*le))
697 return;
698
699 printf("Log entry: %d\n", num);
700
701 /* Get test name */
702 for (i = 0; selftest_name[i].name != NULL; i++)
703 if (selftest_name[i].number == le->number)
704 break;
705
706 if (selftest_name[i].name == NULL)
707 printf("\tName: (%d)\n", le->number);
708 else
709 printf("\tName: %s\n", selftest_name[i].name);
710 printf("\tStatus: %s\n", selftest_status[le->status >> 4]);
711 /* XXX This generally should not be set when a self-test is completed,
712 and at any rate is useless. - mycroft */
713 if (le->status >> 4 == 15)
714 printf("\tPercent of test remaining: %1d0\n", le->status & 0xf);
715 else if (le->status >> 4 != 0)
716 printf("\tLBA first error: %d\n", le32toh(le->lba_first_error));
717 }
718
719 void
720 print_selftest(void *buf)
721 {
722 struct ata_smart_selftestlog *stlog = buf;
723 u_int8_t checksum;
724 int i;
725
726 for (i = checksum = 0; i < 512; i++)
727 checksum += ((u_int8_t *) buf)[i];
728 if (checksum != 0) {
729 fprintf(stderr, "SMART selftest log checksum error\n");
730 return;
731 }
732
733 if (le16toh(stlog->data_structure_revision) != 1) {
734 fprintf(stderr, "Self-test log revision not 1 (found 0x%04x)\n",
735 le16toh(stlog->data_structure_revision));
736 return;
737 }
738
739 if (stlog->mostrecenttest == 0) {
740 printf("No self-tests have been logged\n");
741 return;
742 }
743
744 if (stlog->mostrecenttest > 22) {
745 fprintf(stderr, "Most recent test is too large\n");
746 return;
747 }
748
749 for (i = stlog->mostrecenttest; i < 22; i++)
750 print_selftest_entry(i, &stlog->log_entries[i]);
751 for (i = 0; i < stlog->mostrecenttest; i++)
752 print_selftest_entry(i, &stlog->log_entries[i]);
753 }
754
755 struct ataparams *
756 getataparams()
757 {
758 struct atareq req;
759 static union {
760 unsigned char inbuf[DEV_BSIZE];
761 struct ataparams inqbuf;
762 } inbuf;
763
764 memset(&inbuf, 0, sizeof(inbuf));
765 memset(&req, 0, sizeof(req));
766
767 req.flags = ATACMD_READ;
768 req.command = WDCC_IDENTIFY;
769 req.databuf = (caddr_t)&inbuf;
770 req.datalen = sizeof(inbuf);
771 req.timeout = 1000;
772
773 ata_command(&req);
774
775 return (&inbuf.inqbuf);
776 }
777
778 /*
779 * is_smart:
780 *
781 * Detect whether device supports SMART and SMART is enabled.
782 */
783
784 int
785 is_smart(void)
786 {
787 int retval = 0;
788 struct ataparams *inqbuf;
789 const char *status;
790
791 inqbuf = getataparams();
792
793 if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
794 if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
795 fprintf(stderr, "SMART unsupported\n");
796 } else {
797 if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
798 inqbuf->atap_cmd_set2 == 0xffff ||
799 inqbuf->atap_cmd_set2 == 0x0000) {
800 status = "status unknown";
801 retval = 2;
802 } else {
803 if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) {
804 status = "enabled";
805 retval = 1;
806 } else {
807 status = "disabled";
808 retval = 3;
809 }
810 }
811 printf("SMART supported, SMART %s\n", status);
812 }
813 }
814 return retval;
815 }
816
817 /*
818 * DEVICE COMMANDS
819 */
820
821 /*
822 * device_identify:
823 *
824 * Display the identity of the device
825 */
826 void
827 device_identify(int argc, char *argv[])
828 {
829 struct ataparams *inqbuf;
830 #if BYTE_ORDER == LITTLE_ENDIAN
831 int i;
832 u_int16_t *p;
833 #endif
834
835 /* No arguments. */
836 if (argc != 0)
837 usage();
838
839 inqbuf = getataparams();
840
841 #if BYTE_ORDER == LITTLE_ENDIAN
842 /*
843 * On little endian machines, we need to shuffle the string
844 * byte order. However, we don't have to do this for NEC or
845 * Mitsumi ATAPI devices
846 */
847
848 if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI &&
849 ((inqbuf->atap_model[0] == 'N' &&
850 inqbuf->atap_model[1] == 'E') ||
851 (inqbuf->atap_model[0] == 'F' &&
852 inqbuf->atap_model[1] == 'X')))) {
853 for (i = 0 ; i < sizeof(inqbuf->atap_model); i += 2) {
854 p = (u_short *) (inqbuf->atap_model + i);
855 *p = ntohs(*p);
856 }
857 for (i = 0 ; i < sizeof(inqbuf->atap_serial); i += 2) {
858 p = (u_short *) (inqbuf->atap_serial + i);
859 *p = ntohs(*p);
860 }
861 for (i = 0 ; i < sizeof(inqbuf->atap_revision); i += 2) {
862 p = (u_short *) (inqbuf->atap_revision + i);
863 *p = ntohs(*p);
864 }
865 }
866 #endif
867
868 /*
869 * Strip blanks off of the info strings. Yuck, I wish this was
870 * cleaner.
871 */
872
873 if (inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] == ' ') {
874 inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] = '\0';
875 while (inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] == ' ')
876 inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] = '\0';
877 }
878
879 if (inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] == ' ') {
880 inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] = '\0';
881 while (inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] == ' ')
882 inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] = '\0';
883 }
884
885 if (inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] == ' ') {
886 inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] = '\0';
887 while (inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] == ' ')
888 inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] = '\0';
889 }
890
891 printf("Model: %.*s, Rev: %.*s, Serial #: %.*s\n",
892 (int) sizeof(inqbuf->atap_model), inqbuf->atap_model,
893 (int) sizeof(inqbuf->atap_revision), inqbuf->atap_revision,
894 (int) sizeof(inqbuf->atap_serial), inqbuf->atap_serial);
895
896 printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ?
897 "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" :
898 "removable");
899
900 if ((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == 0)
901 printf("Cylinders: %d, heads: %d, sec/track: %d, total "
902 "sectors: %d\n", inqbuf->atap_cylinders,
903 inqbuf->atap_heads, inqbuf->atap_sectors,
904 (inqbuf->atap_capacity[1] << 16) |
905 inqbuf->atap_capacity[0]);
906
907 if (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK)
908 printf("Device supports command queue depth of %d\n",
909 inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK);
910
911 printf("Device capabilities:\n");
912 print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
913
914 if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
915 printf("Device supports following standards:\n");
916 print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
917 printf("\n");
918 }
919
920 if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
921 inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
922 printf("Command set support:\n");
923 if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff)
924 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1,
925 inqbuf->atap_cmd1_en, ata_cmd_set1);
926 else
927 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1,
928 ata_cmd_set1);
929 if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff)
930 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2,
931 inqbuf->atap_cmd2_en, ata_cmd_set2);
932 else
933 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2,
934 ata_cmd_set2);
935 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
936 print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
937 ata_cmd_ext);
938 }
939
940 if (inqbuf->atap_sata_caps != 0 && inqbuf->atap_sata_caps != 0xffff) {
941 printf("Serial ATA capabilities:\n");
942 print_bitinfo("\t", "\n", inqbuf->atap_sata_caps, ata_sata_caps);
943 }
944
945 if (inqbuf->atap_sata_features_supp != 0 && inqbuf->atap_sata_features_supp != 0xffff) {
946 printf("Serial ATA features:\n");
947 if (inqbuf->atap_sata_features_en != 0 && inqbuf->atap_sata_features_en != 0xffff)
948 print_bitinfo2("\t", "\n", inqbuf->atap_sata_features_supp, inqbuf->atap_sata_features_en, ata_sata_feat);
949 else
950 print_bitinfo("\t", "\n", inqbuf->atap_sata_features_supp, ata_sata_feat);
951 }
952
953 return;
954 }
955
956 /*
957 * device idle:
958 *
959 * issue the IDLE IMMEDIATE command to the drive
960 */
961 void
962 device_idle(int argc, char *argv[])
963 {
964 struct atareq req;
965
966 /* No arguments. */
967 if (argc != 0)
968 usage();
969
970 memset(&req, 0, sizeof(req));
971
972 if (strcmp(cmdname, "idle") == 0)
973 req.command = WDCC_IDLE_IMMED;
974 else if (strcmp(cmdname, "standby") == 0)
975 req.command = WDCC_STANDBY_IMMED;
976 else
977 req.command = WDCC_SLEEP;
978
979 req.timeout = 1000;
980
981 ata_command(&req);
982
983 return;
984 }
985
986 /*
987 * device apm:
988 *
989 * enable/disable/control the APM feature of the drive
990 */
991 void
992 device_apm(int argc, char *argv[])
993 {
994 struct atareq req;
995 long l;
996
997 memset(&req, 0, sizeof(req));
998 if (argc >= 1) {
999 req.command = SET_FEATURES;
1000 req.timeout = 1000;
1001
1002 if (strcmp(argv[0], "disable") == 0)
1003 req.features = WDSF_APM_DS;
1004 else if (strcmp(argv[0], "set") == 0 && argc >= 2 &&
1005 (l = strtol(argv[1], NULL, 0)) >= 0 && l <= 253) {
1006
1007 req.features = WDSF_APM_EN;
1008 req.sec_count = l + 1;
1009 } else
1010 usage();
1011 } else
1012 usage();
1013
1014 ata_command(&req);
1015 }
1016
1017
1018 /*
1019 * Set the idle timer on the disk. Set it for either idle mode or
1020 * standby mode, depending on how we were invoked.
1021 */
1022
1023 void
1024 device_setidle(int argc, char *argv[])
1025 {
1026 unsigned long idle;
1027 struct atareq req;
1028 char *end;
1029
1030 /* Only one argument */
1031 if (argc != 1)
1032 usage();
1033
1034 idle = strtoul(argv[0], &end, 0);
1035
1036 if (*end != '\0') {
1037 fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
1038 exit(1);
1039 }
1040
1041 if (idle > 19800) {
1042 fprintf(stderr, "Idle time has a maximum value of 5.5 "
1043 "hours\n");
1044 exit(1);
1045 }
1046
1047 if (idle != 0 && idle < 5) {
1048 fprintf(stderr, "Idle timer must be at least 5 seconds\n");
1049 exit(1);
1050 }
1051
1052 memset(&req, 0, sizeof(req));
1053
1054 if (idle <= 240*5)
1055 req.sec_count = idle / 5;
1056 else
1057 req.sec_count = idle / (30*60) + 240;
1058
1059 req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
1060 req.timeout = 1000;
1061
1062 ata_command(&req);
1063
1064 return;
1065 }
1066
1067 /*
1068 * Query the device for the current power mode
1069 */
1070
1071 void
1072 device_checkpower(int argc, char *argv[])
1073 {
1074 struct atareq req;
1075
1076 /* No arguments. */
1077 if (argc != 0)
1078 usage();
1079
1080 memset(&req, 0, sizeof(req));
1081
1082 req.command = WDCC_CHECK_PWR;
1083 req.timeout = 1000;
1084 req.flags = ATACMD_READREG;
1085
1086 ata_command(&req);
1087
1088 printf("Current power status: ");
1089
1090 switch (req.sec_count) {
1091 case 0x00:
1092 printf("Standby mode\n");
1093 break;
1094 case 0x80:
1095 printf("Idle mode\n");
1096 break;
1097 case 0xff:
1098 printf("Active mode\n");
1099 break;
1100 default:
1101 printf("Unknown power code (%02x)\n", req.sec_count);
1102 }
1103
1104 return;
1105 }
1106
1107 /*
1108 * device_smart:
1109 *
1110 * Display SMART status
1111 */
1112 void
1113 device_smart(int argc, char *argv[])
1114 {
1115 struct atareq req;
1116 unsigned char inbuf[DEV_BSIZE];
1117 unsigned char inbuf2[DEV_BSIZE];
1118
1119 if (argc < 1)
1120 usage();
1121
1122 if (strcmp(argv[0], "enable") == 0) {
1123 memset(&req, 0, sizeof(req));
1124
1125 req.features = WDSM_ENABLE_OPS;
1126 req.command = WDCC_SMART;
1127 req.cylinder = WDSMART_CYL;
1128 req.timeout = 1000;
1129
1130 ata_command(&req);
1131
1132 is_smart();
1133 } else if (strcmp(argv[0], "disable") == 0) {
1134 memset(&req, 0, sizeof(req));
1135
1136 req.features = WDSM_DISABLE_OPS;
1137 req.command = WDCC_SMART;
1138 req.cylinder = WDSMART_CYL;
1139 req.timeout = 1000;
1140
1141 ata_command(&req);
1142
1143 is_smart();
1144 } else if (strcmp(argv[0], "status") == 0) {
1145 int rv;
1146
1147 rv = is_smart();
1148
1149 if (!rv) {
1150 fprintf(stderr, "SMART not supported\n");
1151 return;
1152 } else if (rv == 3)
1153 return;
1154
1155 memset(&inbuf, 0, sizeof(inbuf));
1156 memset(&req, 0, sizeof(req));
1157
1158 req.features = WDSM_STATUS;
1159 req.command = WDCC_SMART;
1160 req.cylinder = WDSMART_CYL;
1161 req.timeout = 1000;
1162
1163 ata_command(&req);
1164
1165 if (req.cylinder != WDSMART_CYL) {
1166 fprintf(stderr, "Threshold exceeds condition\n");
1167 }
1168
1169 /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
1170 * features, the following ata_command()'s may error
1171 * and exit().
1172 */
1173
1174 memset(&inbuf, 0, sizeof(inbuf));
1175 memset(&req, 0, sizeof(req));
1176
1177 req.flags = ATACMD_READ;
1178 req.features = WDSM_RD_DATA;
1179 req.command = WDCC_SMART;
1180 req.databuf = (caddr_t) inbuf;
1181 req.datalen = sizeof(inbuf);
1182 req.cylinder = WDSMART_CYL;
1183 req.timeout = 1000;
1184
1185 ata_command(&req);
1186
1187 memset(&inbuf2, 0, sizeof(inbuf2));
1188 memset(&req, 0, sizeof(req));
1189
1190 req.flags = ATACMD_READ;
1191 req.features = WDSM_RD_THRESHOLDS;
1192 req.command = WDCC_SMART;
1193 req.databuf = (caddr_t) inbuf2;
1194 req.datalen = sizeof(inbuf2);
1195 req.cylinder = WDSMART_CYL;
1196 req.timeout = 1000;
1197
1198 ata_command(&req);
1199
1200 print_smart_status(inbuf, inbuf2);
1201
1202 } else if (strcmp(argv[0], "offline") == 0) {
1203 if (argc != 2)
1204 usage();
1205 if (!is_smart()) {
1206 fprintf(stderr, "SMART not supported\n");
1207 return;
1208 }
1209
1210 memset(&req, 0, sizeof(req));
1211
1212 req.features = WDSM_EXEC_OFFL_IMM;
1213 req.command = WDCC_SMART;
1214 req.cylinder = WDSMART_CYL;
1215 req.sec_num = atol(argv[1]);
1216 req.timeout = 10000;
1217
1218 ata_command(&req);
1219 } else if (strcmp(argv[0], "error-log") == 0) {
1220 if (!is_smart()) {
1221 fprintf(stderr, "SMART not supported\n");
1222 return;
1223 }
1224
1225 memset(&inbuf, 0, sizeof(inbuf));
1226 memset(&req, 0, sizeof(req));
1227
1228 req.flags = ATACMD_READ;
1229 req.features = WDSM_RD_LOG;
1230 req.sec_count = 1;
1231 req.sec_num = 1;
1232 req.command = WDCC_SMART;
1233 req.databuf = (caddr_t) inbuf;
1234 req.datalen = sizeof(inbuf);
1235 req.cylinder = WDSMART_CYL;
1236 req.timeout = 1000;
1237
1238 ata_command(&req);
1239
1240 print_error(inbuf);
1241 } else if (strcmp(argv[0], "selftest-log") == 0) {
1242 if (!is_smart()) {
1243 fprintf(stderr, "SMART not supported\n");
1244 return;
1245 }
1246
1247 memset(&inbuf, 0, sizeof(inbuf));
1248 memset(&req, 0, sizeof(req));
1249
1250 req.flags = ATACMD_READ;
1251 req.features = WDSM_RD_LOG;
1252 req.sec_count = 1;
1253 req.sec_num = 6;
1254 req.command = WDCC_SMART;
1255 req.databuf = (caddr_t) inbuf;
1256 req.datalen = sizeof(inbuf);
1257 req.cylinder = WDSMART_CYL;
1258 req.timeout = 1000;
1259
1260 ata_command(&req);
1261
1262 print_selftest(inbuf);
1263
1264 } else {
1265 usage();
1266 }
1267 return;
1268 }
1269
1270 void
1271 device_security(int argc, char *argv[])
1272 {
1273 struct atareq req;
1274 struct ataparams *inqbuf;
1275
1276 /* need subcommand */
1277 if (argc < 1)
1278 usage();
1279
1280 if (strcmp(argv[0], "freeze") == 0) {
1281 memset(&req, 0, sizeof(req));
1282 req.command = WDCC_SECURITY_FREEZE;
1283 req.timeout = 1000;
1284 ata_command(&req);
1285 } else if (strcmp(argv[0], "status") == 0) {
1286 inqbuf = getataparams();
1287 print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
1288 } else
1289 usage();
1290
1291 return;
1292 }
1293
1294 /*
1295 * bus_reset:
1296 * Reset an ATA bus (will reset all devices on the bus)
1297 */
1298 void
1299 bus_reset(int argc, char *argv[])
1300 {
1301 int error;
1302
1303 /* no args */
1304 if (argc != 0)
1305 usage();
1306
1307 error = ioctl(fd, ATABUSIORESET, NULL);
1308
1309 if (error == -1)
1310 err(1, "ATABUSIORESET failed");
1311 }
1312