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