atactl.c revision 1.37 1 /* $NetBSD: atactl.c,v 1.37 2005/01/20 15:36:02 xtraeme 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.37 2005/01/20 15:36:02 xtraeme 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 } __attribute__((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 } __attribute__((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 int is_smart(void);
122
123 int fd; /* file descriptor for device */
124 const char *dvname; /* device name */
125 char dvname_store[MAXPATHLEN]; /* for opendisk(3) */
126 const char *cmdname; /* command user issued */
127 const char *argnames; /* helpstring: expected arguments */
128
129 void device_identify(int, char *[]);
130 void device_setidle(int, char *[]);
131 void device_idle(int, char *[]);
132 void device_checkpower(int, char *[]);
133 void device_smart(int, char *[]);
134
135 void device_smart_temp(struct ata_smart_attr *, uint64_t);
136
137 struct command device_commands[] = {
138 { "identify", "", device_identify },
139 { "setidle", "idle-timer", device_setidle },
140 { "setstandby", "standby-timer", device_setidle },
141 { "idle", "", device_idle },
142 { "standby", "", device_idle },
143 { "sleep", "", device_idle },
144 { "checkpower", "", device_checkpower },
145 { "smart", "enable|disable|status|offline #|error-log|selftest-log",
146 device_smart },
147 { NULL, NULL, NULL },
148 };
149
150 void bus_reset(int, char *[]);
151
152 struct command bus_commands[] = {
153 { "reset", "", bus_reset },
154 { NULL, NULL, NULL },
155 };
156
157 /*
158 * Tables containing bitmasks used for error reporting and
159 * device identification.
160 */
161
162 struct bitinfo ata_caps[] = {
163 { WDC_CAP_DMA, "DMA" },
164 { WDC_CAP_LBA, "LBA" },
165 { ATA_CAP_STBY, "ATA standby timer values" },
166 { WDC_CAP_IORDY, "IORDY operation" },
167 { WDC_CAP_IORDY_DSBL, "IORDY disabling" },
168 { 0, NULL },
169 };
170
171 struct bitinfo ata_vers[] = {
172 { WDC_VER_ATA1, "ATA-1" },
173 { WDC_VER_ATA2, "ATA-2" },
174 { WDC_VER_ATA3, "ATA-3" },
175 { WDC_VER_ATA4, "ATA-4" },
176 { WDC_VER_ATA5, "ATA-5" },
177 { WDC_VER_ATA6, "ATA-6" },
178 { WDC_VER_ATA7, "ATA-7" },
179 { 0, NULL },
180 };
181
182 struct bitinfo ata_cmd_set1[] = {
183 { WDC_CMD1_NOP, "NOP command" },
184 { WDC_CMD1_RB, "READ BUFFER command" },
185 { WDC_CMD1_WB, "WRITE BUFFER command" },
186 { WDC_CMD1_HPA, "Host Protected Area feature set" },
187 { WDC_CMD1_DVRST, "DEVICE RESET command" },
188 { WDC_CMD1_SRV, "SERVICE interrupt" },
189 { WDC_CMD1_RLSE, "release interrupt" },
190 { WDC_CMD1_AHEAD, "look-ahead" },
191 { WDC_CMD1_CACHE, "write cache" },
192 { WDC_CMD1_PKT, "PACKET command feature set" },
193 { WDC_CMD1_PM, "Power Management feature set" },
194 { WDC_CMD1_REMOV, "Removable Media feature set" },
195 { WDC_CMD1_SEC, "Security Mode feature set" },
196 { WDC_CMD1_SMART, "SMART feature set" },
197 { 0, NULL },
198 };
199
200 struct bitinfo ata_cmd_set2[] = {
201 { ATA_CMD2_FCE, "FLUSH CACHE EXT command" },
202 { WDC_CMD2_FC, "FLUSH CACHE command" },
203 { WDC_CMD2_DCO, "Device Configuration Overlay feature set" },
204 { ATA_CMD2_LBA48, "48-bit Address feature set" },
205 { WDC_CMD2_AAM, "Automatic Acoustic Management feature set" },
206 { WDC_CMD2_SM, "SET MAX security extension" },
207 { WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" },
208 { WDC_CMD2_PUIS, "Power-Up In Standby feature set" },
209 { WDC_CMD2_RMSN, "Removable Media Status Notification feature set" },
210 { ATA_CMD2_APM, "Advanced Power Management feature set" },
211 { ATA_CMD2_CFA, "CFA feature set" },
212 { ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" },
213 { WDC_CMD2_DM, "DOWNLOAD MICROCODE command" },
214 { 0, NULL },
215 };
216
217 struct bitinfo ata_cmd_ext[] = {
218 { ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" },
219 { ATA_CMDE_TL, "Time-limited Read/Write" },
220 { ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" },
221 { ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" },
222 { ATA_CMDE_WWN, "World Wide name" },
223 { ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" },
224 { ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" },
225 { ATA_CMDE_GPL, "General Purpose Logging feature set" },
226 { ATA_CMDE_STREAM, "Streaming feature set" },
227 { ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" },
228 { ATA_CMDE_MS, "Media serial number" },
229 { ATA_CMDE_SST, "SMART self-test" },
230 { ATA_CMDE_SEL, "SMART error logging" },
231 { 0, NULL },
232 };
233
234 static const struct {
235 const int id;
236 const char *name;
237 void (*special)(struct ata_smart_attr *, uint64_t);
238 } smart_attrs[] = {
239 { 1, "Raw read error rate" },
240 { 2, "Throughput performance" },
241 { 3, "Spin-up time" },
242 { 4, "Start/stop count" },
243 { 5, "Reallocated sector count" },
244 { 6, "Read channel margin" },
245 { 7, "Seek error rate" },
246 { 8, "Seek time performance" },
247 { 9, "Power-on hours count" },
248 { 10, "Spin retry count" },
249 { 11, "Calibration retry count" },
250 { 12, "Device power cycle count" },
251 { 191, "Gsense error rate" },
252 { 192, "Power-off retract count" },
253 { 193, "Load cycle count" },
254 { 194, "Temperature", device_smart_temp},
255 { 195, "Hardware ECC Recovered" },
256 { 196, "Reallocated event count" },
257 { 197, "Current pending sector" },
258 { 198, "Offline uncorrectable" },
259 { 199, "Ultra DMA CRC error count" },
260 { 200, "Write error rate" },
261 { 201, "Soft read error rate" },
262 { 202, "Data address mark errors" },
263 { 203, "Run out cancel" },
264 { 204, "Soft ECC correction" },
265 { 205, "Thermal asperity check" },
266 { 206, "Flying height" },
267 { 207, "Spin high current" },
268 { 208, "Spin buzz" },
269 { 209, "Offline seek performance" },
270 { 220, "Disk shift" },
271 { 221, "G-Sense error rate" },
272 { 222, "Loaded hours" },
273 { 223, "Load/unload retry count" },
274 { 224, "Load friction" },
275 { 225, "Load/unload cycle count" },
276 { 226, "Load-in time" },
277 { 227, "Torque amplification count" },
278 { 228, "Power-off retract count" },
279 { 230, "GMR head amplitude" },
280 { 231, "Temperature", device_smart_temp },
281 { 240, "Head flying hours" },
282 { 250, "Read error retry rate" },
283 { 0, "Unknown" },
284 };
285
286 int
287 main(int argc, char *argv[])
288 {
289 int i;
290 struct command *commands = NULL;
291
292 /* Must have at least: device command */
293 if (argc < 3)
294 usage();
295
296 /* Skip program name, get and skip device name and command. */
297 dvname = argv[1];
298 cmdname = argv[2];
299 argv += 3;
300 argc -= 3;
301
302 /*
303 * Open the device
304 */
305 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
306 if (fd == -1) {
307 if (errno == ENOENT) {
308 /*
309 * Device doesn't exist. Probably trying to open
310 * a device which doesn't use disk semantics for
311 * device name. Try again, specifying "cooked",
312 * which leaves off the "r" in front of the device's
313 * name.
314 */
315 fd = opendisk(dvname, O_RDWR, dvname_store,
316 sizeof(dvname_store), 1);
317 if (fd == -1)
318 err(1, "%s", dvname);
319 } else
320 err(1, "%s", dvname);
321 }
322
323 /*
324 * Point the dvname at the actual device name that opendisk() opened.
325 */
326 dvname = dvname_store;
327
328 /* Look up and call the command. */
329 for (i = 0; device_commands[i].cmd_name != NULL; i++) {
330 if (strcmp(cmdname, device_commands[i].cmd_name) == 0) {
331 commands = &device_commands[i];
332 break;
333 }
334 }
335 if (commands == NULL) {
336 for (i = 0; bus_commands[i].cmd_name != NULL; i++) {
337 if (strcmp(cmdname, bus_commands[i].cmd_name) == 0) {
338 commands = &bus_commands[i];
339 break;
340 }
341 }
342 }
343 if (commands == NULL)
344 errx(1, "unknown command: %s", cmdname);
345
346 argnames = commands->arg_names;
347
348 (*commands->cmd_func)(argc, argv);
349 exit(0);
350 }
351
352 void
353 usage(void)
354 {
355 int i;
356
357 fprintf(stderr, "usage: %s device command [arg [...]]\n",
358 getprogname());
359
360 fprintf(stderr, " Available device commands:\n");
361 for (i=0; device_commands[i].cmd_name != NULL; i++)
362 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
363 device_commands[i].arg_names);
364
365 fprintf(stderr, " Available bus commands:\n");
366 for (i=0; bus_commands[i].cmd_name != NULL; i++)
367 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
368 bus_commands[i].arg_names);
369
370 exit(1);
371 }
372
373 /*
374 * Wrapper that calls ATAIOCCOMMAND and checks for errors
375 */
376
377 void
378 ata_command(struct atareq *req)
379 {
380 int error;
381
382 error = ioctl(fd, ATAIOCCOMMAND, req);
383
384 if (error == -1)
385 err(1, "ATAIOCCOMMAND failed");
386
387 switch (req->retsts) {
388
389 case ATACMD_OK:
390 return;
391 case ATACMD_TIMEOUT:
392 fprintf(stderr, "ATA command timed out\n");
393 exit(1);
394 case ATACMD_DF:
395 fprintf(stderr, "ATA device returned a Device Fault\n");
396 exit(1);
397 case ATACMD_ERROR:
398 if (req->error & WDCE_ABRT)
399 fprintf(stderr, "ATA device returned Aborted "
400 "Command\n");
401 else
402 fprintf(stderr, "ATA device returned error register "
403 "%0x\n", req->error);
404 exit(1);
405 default:
406 fprintf(stderr, "ATAIOCCOMMAND returned unknown result code "
407 "%d\n", req->retsts);
408 exit(1);
409 }
410 }
411
412 /*
413 * Print out strings associated with particular bitmasks
414 */
415
416 void
417 print_bitinfo(const char *bf, const char *af, u_int bits, struct bitinfo *binfo)
418 {
419
420 for (; binfo->bitmask != 0; binfo++)
421 if (bits & binfo->bitmask)
422 printf("%s%s%s", bf, binfo->string, af);
423 }
424
425 void
426 print_bitinfo2(const char *bf, const char *af, u_int bits, u_int enables, struct bitinfo *binfo)
427 {
428
429 for (; binfo->bitmask != 0; binfo++)
430 if (bits & binfo->bitmask)
431 printf("%s%s (%s)%s", bf, binfo->string,
432 (enables & binfo->bitmask) ? "enabled" : "disabled",
433 af);
434 }
435
436
437 /*
438 * Try to print SMART temperature field
439 */
440
441 void
442 device_smart_temp(struct ata_smart_attr *attr, uint64_t raw_value)
443 {
444 printf("%" PRIu8, attr->raw[0]);
445 if (attr->raw[0] != raw_value)
446 printf(" Lifetime max/min %" PRIu8 "/%" PRIu8,
447 attr->raw[2], attr->raw[4]);
448 }
449
450
451 /*
452 * Print out SMART attribute thresholds and values
453 */
454
455 void
456 print_smart_status(void *vbuf, void *tbuf)
457 {
458 struct ata_smart_attributes *value_buf = vbuf;
459 struct ata_smart_thresholds *threshold_buf = tbuf;
460 struct ata_smart_attr *attr;
461 uint64_t raw_value;
462 int flags;
463 int i, j;
464 int aid;
465 u_int8_t checksum;
466
467 for (i = checksum = 0; i < 512; i++)
468 checksum += ((u_int8_t *) value_buf)[i];
469 if (checksum != 0) {
470 fprintf(stderr, "SMART attribute values checksum error\n");
471 return;
472 }
473
474 for (i = checksum = 0; i < 512; i++)
475 checksum += ((u_int8_t *) threshold_buf)[i];
476 if (checksum != 0) {
477 fprintf(stderr, "SMART attribute thresholds checksum error\n");
478 return;
479 }
480
481 printf("id value thresh crit collect reliability description\t\t\traw\n");
482 for (i = 0; i < 256; i++) {
483 int thresh = 0;
484
485 attr = NULL;
486
487 for (j = 0; j < 30; j++) {
488 if (value_buf->attributes[j].id == i)
489 attr = &value_buf->attributes[j];
490 if (threshold_buf->thresholds[j].id == i)
491 thresh = threshold_buf->thresholds[j].value;
492 }
493
494 if (thresh && attr == NULL)
495 errx(1, "threshold but not attr %d", i);
496 if (attr == NULL)
497 continue;
498
499 if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF)
500 continue;
501
502 for (aid = 0;
503 smart_attrs[aid].id != i && smart_attrs[aid].id != 0;
504 aid++)
505 ;
506
507 flags = le16toh(attr->flags);
508
509 printf("%3d %3d %3d %-3s %-7s %stive %-24s\t",
510 i, attr->value, thresh,
511 flags & WDSM_ATTR_ADVISORY ? "yes" : "no",
512 flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline",
513 attr->value > thresh ? "posi" : "nega",
514 smart_attrs[aid].name);
515
516 for (j = 0, raw_value = 0; j < 6; j++)
517 raw_value += ((uint64_t)attr->raw[j]) << (8*j);
518
519 if (smart_attrs[aid].special)
520 (*smart_attrs[aid].special)(attr, raw_value);
521 else
522 printf("%" PRIu64, raw_value);
523 printf("\n");
524 }
525 }
526
527 struct {
528 int number;
529 const char *name;
530 } selftest_name[] = {
531 { 0, "Off-line" },
532 { 1, "Short off-line" },
533 { 2, "Extended off-line" },
534 { 127, "Abort off-line test" },
535 { 129, "Short captive" },
536 { 130, "Extended captive" },
537 { 256, "Unknown test" }, /* larger then u_int8_t */
538 { 0, NULL }
539 };
540
541 const char *selftest_status[] = {
542 "No error",
543 "Aborted by the host",
544 "Interruped by the host by reset",
545 "Fatal error or unknown test error",
546 "Unknown test element failed",
547 "Electrical test element failed",
548 "The Servo (and/or seek) test element failed",
549 "Read element of test failed",
550 "Reserved",
551 "Reserved",
552 "Reserved",
553 "Reserved",
554 "Reserved",
555 "Reserved",
556 "Reserved",
557 "Self-test in progress"
558 };
559
560 void
561 print_error_entry(int num, struct ata_smart_error *le)
562 {
563 int i;
564
565 printf("Log entry: %d\n", num);
566
567 for (i = 0; i < 5; i++)
568 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,
569 le->command[i].device_control,
570 le->command[i].features,
571 le->command[i].sector_count,
572 le->command[i].sector_number,
573 le->command[i].cylinder_low,
574 le->command[i].cylinder_high,
575 le->command[i].device_head,
576 le->command[i].command,
577 le->command[i].timestamp[3],
578 le->command[i].timestamp[2],
579 le->command[i].timestamp[1],
580 le->command[i].timestamp[0]);
581 printf("\tError: err=%02x sc=%02x sn=%02x cl=%02x ch=%02x dh=%02x status=%02x state=%02x lifetime=%02x%02x\n",
582 le->error_data.error,
583 le->error_data.sector_count,
584 le->error_data.sector_number,
585 le->error_data.cylinder_low,
586 le->error_data.cylinder_high,
587 le->error_data.device_head,
588 le->error_data.status,
589 le->error_data.state,
590 le->error_data.lifetime[1],
591 le->error_data.lifetime[0]);
592 printf("\tExtended: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
593 le->error_data.extended_error[0],
594 le->error_data.extended_error[1],
595 le->error_data.extended_error[2],
596 le->error_data.extended_error[3],
597 le->error_data.extended_error[4],
598 le->error_data.extended_error[5],
599 le->error_data.extended_error[6],
600 le->error_data.extended_error[7],
601 le->error_data.extended_error[8],
602 le->error_data.extended_error[9],
603 le->error_data.extended_error[10],
604 le->error_data.extended_error[11],
605 le->error_data.extended_error[12],
606 le->error_data.extended_error[13],
607 le->error_data.extended_error[14],
608 le->error_data.extended_error[15],
609 le->error_data.extended_error[15],
610 le->error_data.extended_error[17],
611 le->error_data.extended_error[18]);
612 }
613
614 void
615 print_error(void *buf)
616 {
617 struct ata_smart_errorlog *erlog = buf;
618 u_int8_t checksum;
619 int i;
620
621 for (i = checksum = 0; i < 512; i++)
622 checksum += ((u_int8_t *) buf)[i];
623 if (checksum != 0) {
624 fprintf(stderr, "SMART error log checksum error\n");
625 return;
626 }
627
628 if (erlog->data_structure_revision != 1) {
629 fprintf(stderr, "Log revision not 1");
630 return;
631 }
632
633 if (erlog->mostrecenterror == 0) {
634 printf("No errors have been logged\n");
635 return;
636 }
637
638 if (erlog->mostrecenterror > 5) {
639 fprintf(stderr, "Most recent error is too large\n");
640 return;
641 }
642
643 for (i = erlog->mostrecenterror; i < 5; i++)
644 print_error_entry(i, &erlog->log_entries[i]);
645 for (i = 0; i < erlog->mostrecenterror; i++)
646 print_error_entry(i, &erlog->log_entries[i]);
647 printf("device error count: %d\n", erlog->device_error_count);
648 }
649
650 void
651 print_selftest_entry(int num, struct ata_smart_selftest *le)
652 {
653 unsigned char *p;
654 int i;
655
656 /* check if all zero */
657 for (p = (void *)le, i = 0; i < sizeof(*le); i++)
658 if (p[i] != 0)
659 break;
660 if (i == sizeof(*le))
661 return;
662
663 printf("Log entry: %d\n", num);
664
665 /* Get test name */
666 for (i = 0; selftest_name[i].name != NULL; i++)
667 if (selftest_name[i].number == le->number)
668 break;
669
670 if (selftest_name[i].name == NULL)
671 printf("\tName: (%d)\n", le->number);
672 else
673 printf("\tName: %s\n", selftest_name[i].name);
674 printf("\tStatus: %s\n", selftest_status[le->status >> 4]);
675 /* XXX This generally should not be set when a self-test is completed,
676 and at any rate is useless. - mycroft */
677 if (le->status >> 4 == 15)
678 printf("\tPercent of test remaining: %1d0\n", le->status & 0xf);
679 else if (le->status >> 4 != 0)
680 printf("\tLBA first error: %d\n", le32toh(le->lba_first_error));
681 }
682
683 void
684 print_selftest(void *buf)
685 {
686 struct ata_smart_selftestlog *stlog = buf;
687 u_int8_t checksum;
688 int i;
689
690 for (i = checksum = 0; i < 512; i++)
691 checksum += ((u_int8_t *) buf)[i];
692 if (checksum != 0) {
693 fprintf(stderr, "SMART selftest log checksum error\n");
694 return;
695 }
696
697 if (le16toh(stlog->data_structure_revision != 1)) {
698 fprintf(stderr, "Log revision not 1");
699 return;
700 }
701
702 if (stlog->mostrecenttest == 0) {
703 printf("No self-tests have been logged\n");
704 return;
705 }
706
707 if (stlog->mostrecenttest > 22) {
708 fprintf(stderr, "Most recent test is too large\n");
709 return;
710 }
711
712 for (i = stlog->mostrecenttest; i < 22; i++)
713 print_selftest_entry(i, &stlog->log_entries[i]);
714 for (i = 0; i < stlog->mostrecenttest; i++)
715 print_selftest_entry(i, &stlog->log_entries[i]);
716 }
717
718 /*
719 * is_smart:
720 *
721 * Detect whether device supports SMART and SMART is enabled.
722 */
723
724 int
725 is_smart(void)
726 {
727 int retval = 0;
728 struct atareq req;
729 unsigned char inbuf[DEV_BSIZE];
730 struct ataparams *inqbuf;
731 char *status;
732
733 memset(&inbuf, 0, sizeof(inbuf));
734 memset(&req, 0, sizeof(req));
735
736 inqbuf = (struct ataparams *) inbuf;
737
738 req.flags = ATACMD_READ;
739 req.command = WDCC_IDENTIFY;
740 req.databuf = (caddr_t) inbuf;
741 req.datalen = sizeof(inbuf);
742 req.timeout = 1000;
743
744 ata_command(&req);
745
746 if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
747 if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
748 fprintf(stderr, "SMART unsupported\n");
749 } else {
750 if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
751 inqbuf->atap_cmd_set2 == 0xffff ||
752 inqbuf->atap_cmd_set2 == 0x0000) {
753 status = "status unknown";
754 retval = 2;
755 } else {
756 if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) {
757 status = "enabled";
758 retval = 1;
759 } else {
760 status = "disabled";
761 }
762 }
763 printf("SMART supported, SMART %s\n", status);
764 }
765 }
766 return retval;
767 }
768
769 /*
770 * DEVICE COMMANDS
771 */
772
773 /*
774 * device_identify:
775 *
776 * Display the identity of the device
777 */
778 void
779 device_identify(int argc, char *argv[])
780 {
781 struct ataparams *inqbuf;
782 struct atareq req;
783 unsigned char inbuf[DEV_BSIZE];
784 #if BYTE_ORDER == LITTLE_ENDIAN
785 int i;
786 u_int16_t *p;
787 #endif
788
789 /* No arguments. */
790 if (argc != 0)
791 usage();
792
793 memset(&inbuf, 0, sizeof(inbuf));
794 memset(&req, 0, sizeof(req));
795
796 inqbuf = (struct ataparams *) inbuf;
797
798 req.flags = ATACMD_READ;
799 req.command = WDCC_IDENTIFY;
800 req.databuf = (caddr_t) inbuf;
801 req.datalen = sizeof(inbuf);
802 req.timeout = 1000;
803
804 ata_command(&req);
805
806 #if BYTE_ORDER == LITTLE_ENDIAN
807 /*
808 * On little endian machines, we need to shuffle the string
809 * byte order. However, we don't have to do this for NEC or
810 * Mitsumi ATAPI devices
811 */
812
813 if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI &&
814 ((inqbuf->atap_model[0] == 'N' &&
815 inqbuf->atap_model[1] == 'E') ||
816 (inqbuf->atap_model[0] == 'F' &&
817 inqbuf->atap_model[1] == 'X')))) {
818 for (i = 0 ; i < sizeof(inqbuf->atap_model); i += 2) {
819 p = (u_short *) (inqbuf->atap_model + i);
820 *p = ntohs(*p);
821 }
822 for (i = 0 ; i < sizeof(inqbuf->atap_serial); i += 2) {
823 p = (u_short *) (inqbuf->atap_serial + i);
824 *p = ntohs(*p);
825 }
826 for (i = 0 ; i < sizeof(inqbuf->atap_revision); i += 2) {
827 p = (u_short *) (inqbuf->atap_revision + i);
828 *p = ntohs(*p);
829 }
830 }
831 #endif
832
833 /*
834 * Strip blanks off of the info strings. Yuck, I wish this was
835 * cleaner.
836 */
837
838 if (inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] == ' ') {
839 inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] = '\0';
840 while (inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] == ' ')
841 inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] = '\0';
842 }
843
844 if (inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] == ' ') {
845 inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] = '\0';
846 while (inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] == ' ')
847 inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] = '\0';
848 }
849
850 if (inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] == ' ') {
851 inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] = '\0';
852 while (inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] == ' ')
853 inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] = '\0';
854 }
855
856 printf("Model: %.*s, Rev: %.*s, Serial #: %.*s\n",
857 (int) sizeof(inqbuf->atap_model), inqbuf->atap_model,
858 (int) sizeof(inqbuf->atap_revision), inqbuf->atap_revision,
859 (int) sizeof(inqbuf->atap_serial), inqbuf->atap_serial);
860
861 printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ?
862 "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" :
863 "removable");
864
865 if ((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == 0)
866 printf("Cylinders: %d, heads: %d, sec/track: %d, total "
867 "sectors: %d\n", inqbuf->atap_cylinders,
868 inqbuf->atap_heads, inqbuf->atap_sectors,
869 (inqbuf->atap_capacity[1] << 16) |
870 inqbuf->atap_capacity[0]);
871
872 if (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK)
873 printf("Device supports command queue depth of %d\n",
874 inqbuf->atap_queuedepth & 0xf);
875
876 printf("Device capabilities:\n");
877 print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
878
879 if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
880 printf("Device supports following standards:\n");
881 print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
882 printf("\n");
883 }
884
885 if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
886 inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
887 printf("Command set support:\n");
888 if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff)
889 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1,
890 inqbuf->atap_cmd1_en, ata_cmd_set1);
891 else
892 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1,
893 ata_cmd_set1);
894 if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff)
895 print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2,
896 inqbuf->atap_cmd2_en, ata_cmd_set2);
897 else
898 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2,
899 ata_cmd_set2);
900 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
901 print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
902 ata_cmd_ext);
903 }
904
905 return;
906 }
907
908 /*
909 * device idle:
910 *
911 * issue the IDLE IMMEDIATE command to the drive
912 */
913
914 void
915 device_idle(int argc, char *argv[])
916 {
917 struct atareq req;
918
919 /* No arguments. */
920 if (argc != 0)
921 usage();
922
923 memset(&req, 0, sizeof(req));
924
925 if (strcmp(cmdname, "idle") == 0)
926 req.command = WDCC_IDLE_IMMED;
927 else if (strcmp(cmdname, "standby") == 0)
928 req.command = WDCC_STANDBY_IMMED;
929 else
930 req.command = WDCC_SLEEP;
931
932 req.timeout = 1000;
933
934 ata_command(&req);
935
936 return;
937 }
938
939 /*
940 * Set the idle timer on the disk. Set it for either idle mode or
941 * standby mode, depending on how we were invoked.
942 */
943
944 void
945 device_setidle(int argc, char *argv[])
946 {
947 unsigned long idle;
948 struct atareq req;
949 char *end;
950
951 /* Only one argument */
952 if (argc != 1)
953 usage();
954
955 idle = strtoul(argv[0], &end, 0);
956
957 if (*end != '\0') {
958 fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
959 exit(1);
960 }
961
962 if (idle > 19800) {
963 fprintf(stderr, "Idle time has a maximum value of 5.5 "
964 "hours\n");
965 exit(1);
966 }
967
968 if (idle != 0 && idle < 5) {
969 fprintf(stderr, "Idle timer must be at least 5 seconds\n");
970 exit(1);
971 }
972
973 memset(&req, 0, sizeof(req));
974
975 if (idle <= 240*5)
976 req.sec_count = idle / 5;
977 else
978 req.sec_count = idle / (30*60) + 240;
979
980 req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
981 req.timeout = 1000;
982
983 ata_command(&req);
984
985 return;
986 }
987
988 /*
989 * Query the device for the current power mode
990 */
991
992 void
993 device_checkpower(int argc, char *argv[])
994 {
995 struct atareq req;
996
997 /* No arguments. */
998 if (argc != 0)
999 usage();
1000
1001 memset(&req, 0, sizeof(req));
1002
1003 req.command = WDCC_CHECK_PWR;
1004 req.timeout = 1000;
1005 req.flags = ATACMD_READREG;
1006
1007 ata_command(&req);
1008
1009 printf("Current power status: ");
1010
1011 switch (req.sec_count) {
1012 case 0x00:
1013 printf("Standby mode\n");
1014 break;
1015 case 0x80:
1016 printf("Idle mode\n");
1017 break;
1018 case 0xff:
1019 printf("Active mode\n");
1020 break;
1021 default:
1022 printf("Unknown power code (%02x)\n", req.sec_count);
1023 }
1024
1025 return;
1026 }
1027
1028 /*
1029 * device_smart:
1030 *
1031 * Display SMART status
1032 */
1033 void
1034 device_smart(int argc, char *argv[])
1035 {
1036 struct atareq req;
1037 unsigned char inbuf[DEV_BSIZE];
1038 unsigned char inbuf2[DEV_BSIZE];
1039
1040 if (argc < 1)
1041 usage();
1042
1043 if (strcmp(argv[0], "enable") == 0) {
1044 memset(&req, 0, sizeof(req));
1045
1046 req.features = WDSM_ENABLE_OPS;
1047 req.command = WDCC_SMART;
1048 req.cylinder = WDSMART_CYL;
1049 req.timeout = 1000;
1050
1051 ata_command(&req);
1052
1053 is_smart();
1054 } else if (strcmp(argv[0], "disable") == 0) {
1055 memset(&req, 0, sizeof(req));
1056
1057 req.features = WDSM_DISABLE_OPS;
1058 req.command = WDCC_SMART;
1059 req.cylinder = WDSMART_CYL;
1060 req.timeout = 1000;
1061
1062 ata_command(&req);
1063
1064 is_smart();
1065 } else if (strcmp(argv[0], "status") == 0) {
1066 if (!is_smart()) {
1067 fprintf(stderr, "SMART not supported\n");
1068 return;
1069 }
1070
1071 memset(&inbuf, 0, sizeof(inbuf));
1072 memset(&req, 0, sizeof(req));
1073
1074 req.features = WDSM_STATUS;
1075 req.command = WDCC_SMART;
1076 req.cylinder = WDSMART_CYL;
1077 req.timeout = 1000;
1078
1079 ata_command(&req);
1080
1081 if (req.cylinder != WDSMART_CYL) {
1082 fprintf(stderr, "Threshold exceeds condition\n");
1083 }
1084
1085 /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
1086 * features, the following ata_command()'s may error
1087 * and exit().
1088 */
1089
1090 memset(&inbuf, 0, sizeof(inbuf));
1091 memset(&req, 0, sizeof(req));
1092
1093 req.flags = ATACMD_READ;
1094 req.features = WDSM_RD_DATA;
1095 req.command = WDCC_SMART;
1096 req.databuf = (caddr_t) inbuf;
1097 req.datalen = sizeof(inbuf);
1098 req.cylinder = WDSMART_CYL;
1099 req.timeout = 1000;
1100
1101 ata_command(&req);
1102
1103 memset(&inbuf2, 0, sizeof(inbuf2));
1104 memset(&req, 0, sizeof(req));
1105
1106 req.flags = ATACMD_READ;
1107 req.features = WDSM_RD_THRESHOLDS;
1108 req.command = WDCC_SMART;
1109 req.databuf = (caddr_t) inbuf2;
1110 req.datalen = sizeof(inbuf2);
1111 req.cylinder = WDSMART_CYL;
1112 req.timeout = 1000;
1113
1114 ata_command(&req);
1115
1116 print_smart_status(inbuf, inbuf2);
1117
1118 } else if (strcmp(argv[0], "offline") == 0) {
1119 if (argc != 2)
1120 usage();
1121 if (!is_smart()) {
1122 fprintf(stderr, "SMART not supported\n");
1123 return;
1124 }
1125
1126 memset(&req, 0, sizeof(req));
1127
1128 req.features = WDSM_EXEC_OFFL_IMM;
1129 req.command = WDCC_SMART;
1130 req.cylinder = WDSMART_CYL;
1131 req.sec_num = atol(argv[1]);
1132 req.timeout = 10000;
1133
1134 ata_command(&req);
1135 } else if (strcmp(argv[0], "error-log") == 0) {
1136 if (!is_smart()) {
1137 fprintf(stderr, "SMART not supported\n");
1138 return;
1139 }
1140
1141 memset(&inbuf, 0, sizeof(inbuf));
1142 memset(&req, 0, sizeof(req));
1143
1144 req.flags = ATACMD_READ;
1145 req.features = WDSM_RD_LOG;
1146 req.sec_count = 1;
1147 req.sec_num = 1;
1148 req.command = WDCC_SMART;
1149 req.databuf = (caddr_t) inbuf;
1150 req.datalen = sizeof(inbuf);
1151 req.cylinder = WDSMART_CYL;
1152 req.timeout = 1000;
1153
1154 ata_command(&req);
1155
1156 print_error(inbuf);
1157 } else if (strcmp(argv[0], "selftest-log") == 0) {
1158 if (!is_smart()) {
1159 fprintf(stderr, "SMART not supported\n");
1160 return;
1161 }
1162
1163 memset(&inbuf, 0, sizeof(inbuf));
1164 memset(&req, 0, sizeof(req));
1165
1166 req.flags = ATACMD_READ;
1167 req.features = WDSM_RD_LOG;
1168 req.sec_count = 1;
1169 req.sec_num = 6;
1170 req.command = WDCC_SMART;
1171 req.databuf = (caddr_t) inbuf;
1172 req.datalen = sizeof(inbuf);
1173 req.cylinder = WDSMART_CYL;
1174 req.timeout = 1000;
1175
1176 ata_command(&req);
1177
1178 print_selftest(inbuf);
1179
1180 } else {
1181 usage();
1182 }
1183 return;
1184 }
1185
1186 /*
1187 * bus_reset:
1188 * Reset an ATA bus (will reset all devices on the bus)
1189 */
1190 void
1191 bus_reset(int argc, char *argv[])
1192 {
1193 int error;
1194
1195 /* no args */
1196 if (argc != 0)
1197 usage();
1198
1199 error = ioctl(fd, ATABUSIORESET, NULL);
1200
1201 if (error == -1)
1202 err(1, "ATABUSIORESET failed");
1203 }
1204