atactl.c revision 1.28 1 /* $NetBSD: atactl.c,v 1.28 2004/03/14 20:11:24 wiz 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.28 2004/03/14 20:11:24 wiz 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 command {
64 const char *cmd_name;
65 const char *arg_names;
66 void (*cmd_func)(int, char *[]);
67 };
68
69 struct bitinfo {
70 u_int bitmask;
71 const char *string;
72 };
73
74 int main(int, char *[]);
75 void usage(void);
76 void ata_command(struct atareq *);
77 void print_bitinfo(const char *, const char *, u_int, struct bitinfo *);
78 void print_smart_status(void *, void *);
79 void print_selftest_entry(int, struct ata_smart_selftest *);
80
81 void print_selftest(void *);
82
83 int is_smart(void);
84
85 int fd; /* file descriptor for device */
86 const char *dvname; /* device name */
87 char dvname_store[MAXPATHLEN]; /* for opendisk(3) */
88 const char *cmdname; /* command user issued */
89 const char *argnames; /* helpstring: expected arguments */
90
91 void device_identify(int, char *[]);
92 void device_setidle(int, char *[]);
93 void device_idle(int, char *[]);
94 void device_checkpower(int, char *[]);
95 void device_smart(int, char *[]);
96
97 void smart_temp(struct ata_smart_attr *, int64_t);
98
99 struct command commands[] = {
100 { "identify", "", device_identify },
101 { "setidle", "idle-timer", device_setidle },
102 { "setstandby", "standby-timer", device_setidle },
103 { "idle", "", device_idle },
104 { "standby", "", device_idle },
105 { "sleep", "", device_idle },
106 { "checkpower", "", device_checkpower },
107 { "smart", "enable|disable|status|selftest-log", device_smart },
108 { NULL, NULL, NULL },
109 };
110
111 /*
112 * Tables containing bitmasks used for error reporting and
113 * device identification.
114 */
115
116 struct bitinfo ata_caps[] = {
117 { WDC_CAP_DMA, "DMA" },
118 { WDC_CAP_LBA, "LBA" },
119 { ATA_CAP_STBY, "ATA standby timer values" },
120 { WDC_CAP_IORDY, "IORDY operation" },
121 { WDC_CAP_IORDY_DSBL, "IORDY disabling" },
122 { 0, NULL },
123 };
124
125 struct bitinfo ata_vers[] = {
126 { WDC_VER_ATA1, "ATA-1" },
127 { WDC_VER_ATA2, "ATA-2" },
128 { WDC_VER_ATA3, "ATA-3" },
129 { WDC_VER_ATA4, "ATA-4" },
130 { WDC_VER_ATA5, "ATA-5" },
131 { WDC_VER_ATA6, "ATA-6" },
132 { WDC_VER_ATA7, "ATA-7" },
133 { 0, NULL },
134 };
135
136 struct bitinfo ata_cmd_set1[] = {
137 { WDC_CMD1_NOP, "NOP command" },
138 { WDC_CMD1_RB, "READ BUFFER command" },
139 { WDC_CMD1_WB, "WRITE BUFFER command" },
140 { WDC_CMD1_HPA, "Host Protected Area feature set" },
141 { WDC_CMD1_DVRST, "DEVICE RESET command" },
142 { WDC_CMD1_SRV, "SERVICE interrupt" },
143 { WDC_CMD1_RLSE, "release interrupt" },
144 { WDC_CMD1_AHEAD, "look-ahead" },
145 { WDC_CMD1_CACHE, "write cache" },
146 { WDC_CMD1_PKT, "PACKET command feature set" },
147 { WDC_CMD1_PM, "Power Management feature set" },
148 { WDC_CMD1_REMOV, "Removable Media feature set" },
149 { WDC_CMD1_SEC, "Security Mode feature set" },
150 { WDC_CMD1_SMART, "SMART feature set" },
151 { 0, NULL },
152 };
153
154 struct bitinfo ata_cmd_set2[] = {
155 { ATA_CMD2_FCE, "FLUSH CACHE EXT command" },
156 { WDC_CMD2_FC, "FLUSH CACHE command" },
157 { WDC_CMD2_DCO, "Device Configuration Overlay feature set" },
158 { ATA_CMD2_LBA48, "48-bit Address feature set" },
159 { WDC_CMD2_AAM, "Automatic Acoustic Management feature set" },
160 { WDC_CMD2_SM, "SET MAX security extension" },
161 { WDC_CMD2_SFREQ, "SET FEATURES required to spin-up after power-up" },
162 { WDC_CMD2_PUIS, "Power-Up In Standby feature set" },
163 { WDC_CMD2_RMSN, "Removable Media Status Notification feature set" },
164 { ATA_CMD2_APM, "Advanced Power Management feature set" },
165 { ATA_CMD2_CFA, "CFA feature set" },
166 { ATA_CMD2_RWQ, "READ/WRITE DMA QUEUED commands" },
167 { WDC_CMD2_DM, "DOWNLOAD MICROCODE command" },
168 { 0, NULL },
169 };
170
171 struct bitinfo ata_cmd_ext[] = {
172 { ATA_CMDE_TLCONT, "Time-limited R/W feature set R/W Continuous mode" },
173 { ATA_CMDE_TL, "Time-limited Read/Write" },
174 { ATA_CMDE_URGW, "URG bit for WRITE STREAM DMA/PIO" },
175 { ATA_CMDE_URGR, "URG bit for READ STREAM DMA/PIO" },
176 { ATA_CMDE_WWN, "World Wide name" },
177 { ATA_CMDE_WQFE, "WRITE DMA QUEUED FUA EXT command" },
178 { ATA_CMDE_WFE, "WRITE DMA/MULTIPLE FUA EXT commands" },
179 { ATA_CMDE_GPL, "General Purpose Logging feature set" },
180 { ATA_CMDE_STREAM, "Streaming feature set" },
181 { ATA_CMDE_MCPTC, "Media Card Pass Through Command feature set" },
182 { ATA_CMDE_MS, "Media serial number" },
183 { ATA_CMDE_SST, "SMART self-test" },
184 { ATA_CMDE_SEL, "SMART error logging" },
185 { 0, NULL },
186 };
187
188 static const struct {
189 const int id;
190 const char *name;
191 void (*special)(struct ata_smart_attr *, int64_t);
192 } smart_attrs[] = {
193 { 1, "Raw read error rate" },
194 { 2, "Throughput performance" },
195 { 3, "Spin-up time" },
196 { 4, "Start/stop count" },
197 { 5, "Reallocated sector count" },
198 { 7, "Seek error rate" },
199 { 8, "Seek time performance" },
200 { 9, "Power-on hours count" },
201 { 10, "Spin retry count" },
202 { 11, "Calibration retry count" },
203 { 12, "Device power cycle count" },
204 { 191, "Gsense error rate" },
205 { 192, "Power-off retract count" },
206 { 193, "Load cycle count" },
207 { 194, "Temperature", smart_temp},
208 { 195, "Hardware ECC Recovered" },
209 { 196, "Reallocated event count" },
210 { 197, "Current pending sector" },
211 { 198, "Offline uncorrectable" },
212 { 199, "Ultra DMA CRC error count" },
213 { 0, "Unknown" },
214 };
215
216 int
217 main(int argc, char *argv[])
218 {
219 int i;
220
221 /* Must have at least: device command */
222 if (argc < 3)
223 usage();
224
225 /* Skip program name, get and skip device name and command. */
226 dvname = argv[1];
227 cmdname = argv[2];
228 argv += 3;
229 argc -= 3;
230
231 /*
232 * Open the device
233 */
234 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
235 if (fd == -1) {
236 if (errno == ENOENT) {
237 /*
238 * Device doesn't exist. Probably trying to open
239 * a device which doesn't use disk semantics for
240 * device name. Try again, specifying "cooked",
241 * which leaves off the "r" in front of the device's
242 * name.
243 */
244 fd = opendisk(dvname, O_RDWR, dvname_store,
245 sizeof(dvname_store), 1);
246 if (fd == -1)
247 err(1, "%s", dvname);
248 } else
249 err(1, "%s", dvname);
250 }
251
252 /*
253 * Point the dvname at the actual device name that opendisk() opened.
254 */
255 dvname = dvname_store;
256
257 /* Look up and call the command. */
258 for (i = 0; commands[i].cmd_name != NULL; i++)
259 if (strcmp(cmdname, commands[i].cmd_name) == 0)
260 break;
261 if (commands[i].cmd_name == NULL)
262 errx(1, "unknown command: %s", cmdname);
263
264 argnames = commands[i].arg_names;
265
266 (*commands[i].cmd_func)(argc, argv);
267 exit(0);
268 }
269
270 void
271 usage(void)
272 {
273 int i;
274
275 fprintf(stderr, "usage: %s device command [arg [...]]\n",
276 getprogname());
277
278 fprintf(stderr, " Available device commands:\n");
279 for (i=0; commands[i].cmd_name != NULL; i++)
280 fprintf(stderr, "\t%s %s\n", commands[i].cmd_name,
281 commands[i].arg_names);
282
283 exit(1);
284 }
285
286 /*
287 * Wrapper that calls ATAIOCCOMMAND and checks for errors
288 */
289
290 void
291 ata_command(struct atareq *req)
292 {
293 int error;
294
295 error = ioctl(fd, ATAIOCCOMMAND, req);
296
297 if (error == -1)
298 err(1, "ATAIOCCOMMAND failed");
299
300 switch (req->retsts) {
301
302 case ATACMD_OK:
303 return;
304 case ATACMD_TIMEOUT:
305 fprintf(stderr, "ATA command timed out\n");
306 exit(1);
307 case ATACMD_DF:
308 fprintf(stderr, "ATA device returned a Device Fault\n");
309 exit(1);
310 case ATACMD_ERROR:
311 if (req->error & WDCE_ABRT)
312 fprintf(stderr, "ATA device returned Aborted "
313 "Command\n");
314 else
315 fprintf(stderr, "ATA device returned error register "
316 "%0x\n", req->error);
317 exit(1);
318 default:
319 fprintf(stderr, "ATAIOCCOMMAND returned unknown result code "
320 "%d\n", req->retsts);
321 exit(1);
322 }
323 }
324
325 /*
326 * Print out strings associated with particular bitmasks
327 */
328
329 void
330 print_bitinfo(const char *bf, const char *af, u_int bits, struct bitinfo *binfo)
331 {
332
333 for (; binfo->bitmask != 0; binfo++)
334 if (bits & binfo->bitmask)
335 printf("%s%s%s", bf, binfo->string, af);
336 }
337
338
339 /*
340 * Try to print SMART temperature field
341 */
342
343 void
344 smart_temp(struct ata_smart_attr *attr, int64_t raw_value)
345 {
346 printf("\t%d", (int)attr->raw[0]);
347 if (attr->raw[0] != raw_value)
348 printf(" Lifetime max/min %d/%d",
349 (int)attr->raw[2],
350 (int)attr->raw[4]);
351 }
352
353
354 /*
355 * Print out SMART attribute thresholds and values
356 */
357
358 void
359 print_smart_status(void *vbuf, void *tbuf)
360 {
361 struct ata_smart_attributes *value_buf = vbuf;
362 struct ata_smart_thresholds *threshold_buf = tbuf;
363 struct ata_smart_attr *attr;
364 int64_t raw_value;
365 int flags;
366 int i, j;
367 int aid;
368 int8_t checksum;
369
370 for (i = checksum = 0; i < 511; i++)
371 checksum += ((int8_t *) value_buf)[i];
372 checksum *= -1;
373 if (checksum != value_buf->checksum) {
374 fprintf(stderr, "SMART attribute values checksum error\n");
375 return;
376 }
377
378 for (i = checksum = 0; i < 511; i++)
379 checksum += ((int8_t *) threshold_buf)[i];
380 checksum *= -1;
381 if (checksum != threshold_buf->checksum) {
382 fprintf(stderr, "SMART attribute thresholds checksum error\n");
383 return;
384 }
385
386 printf("id value thresh crit collect reliability description\t\t\traw\n");
387 for (i = 0; i < 256; i++) {
388 int thresh = 0;
389
390 attr = NULL;
391
392 for (j = 0; j < 30; j++) {
393 if (value_buf->attributes[j].id == i)
394 attr = &value_buf->attributes[j];
395 if (threshold_buf->thresholds[j].id == i)
396 thresh = threshold_buf->thresholds[j].value;
397 }
398
399 if (thresh && attr == NULL)
400 errx(1, "threshold but not attr %d", i);
401 if (attr == NULL)
402 continue;
403
404 if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF)
405 continue;
406
407 for (aid = 0;
408 smart_attrs[aid].id != i && smart_attrs[aid].id != 0;
409 aid++)
410 ;
411
412 flags = attr->flags;
413
414 printf("%3d %3d %3d %-3s %-7s %stive %-24s",
415 i, attr->value, thresh,
416 flags & WDSM_ATTR_ADVISORY ? "yes" : "no",
417 flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline",
418 attr->value > thresh ? "posi" : "nega",
419 smart_attrs[aid].name);
420
421 for (j = 0, raw_value = 0; j < 6; j++)
422 raw_value += ((int64_t)attr->raw[j]) << (8*j);
423
424 if (smart_attrs[aid].special)
425 (*smart_attrs[aid].special)(attr, raw_value);
426 printf("\n");
427 }
428 }
429
430 struct {
431 int number;
432 const char *name;
433 } selftest_name[] = {
434 { 0, "Off-line" },
435 { 1, "Short off-line" },
436 { 2, "Extended off-line" },
437 { 127, "Abort off-line test" },
438 { 129, "Short captive" },
439 { 130, "Extended captive" },
440 { 256, "Unknown test" }, /* larger then u_int8_t */
441 { 0, NULL }
442 };
443
444 const char *selftest_status[] = {
445 "No error",
446 "Aborted by the host",
447 "Interruped by the host by reset",
448 "Fatal error or unknown test error",
449 "Unknown test element failed",
450 "Electrical test element failed",
451 "The Servo (and/or seek) test element failed",
452 "Read element of test failed",
453 "Reserved",
454 "Reserved",
455 "Reserved",
456 "Reserved",
457 "Reserved",
458 "Reserved",
459 "Reserved",
460 "Self-test in progress"
461 };
462
463 void
464 print_selftest_entry(int num, struct ata_smart_selftest *le)
465 {
466 unsigned char *p;
467 int i;
468
469 /* check if all zero */
470 for (p = (void *)le, i = 0; i < sizeof(*le); i++)
471 if (p[i] != 0)
472 break;
473 if (i == sizeof(*le))
474 return;
475
476 printf("Log entry: %d\n", num);
477
478 /* Get test name */
479 for (i = 0; selftest_name[i].name != NULL; i++)
480 if (selftest_name[i].number == le->number)
481 break;
482 if (selftest_name[i].number == 0)
483 i = 255; /* unknown test */
484
485 printf("\tName: %s\n", selftest_name[i].name);
486 printf("\tStatus: %s\n", selftest_status[le->status >> 4]);
487 if (le->status >> 4 == 15)
488 printf("\tPrecent of test remaning: %1d0\n", le->status & 0xf);
489 if (le->status)
490 printf("LBA first error: %d\n", le->lba_first_error);
491 }
492
493 void
494 print_selftest(void *buf)
495 {
496 struct ata_smart_selftestlog *stlog = buf;
497 int8_t checksum;
498 int i;
499
500 for (i = checksum = 0; i < 511; i++)
501 checksum += ((int8_t *) buf)[i];
502 checksum *= -1;
503 if ((u_int8_t)checksum != stlog->checksum) {
504 fprintf(stderr, "SMART selftest log checksum error\n");
505 return;
506 }
507
508 if (stlog->data_structure_revision != 1) {
509 fprintf(stderr, "Log revision not 1");
510 return;
511 }
512
513 if (stlog->mostrecenttest == 0) {
514 printf("No self-tests have been logged\n");
515 return;
516 }
517
518 if (stlog->mostrecenttest > 22) {
519 fprintf(stderr, "Most recent test is too large\n");
520 return;
521 }
522
523 for (i = stlog->mostrecenttest; i < 22; i++)
524 print_selftest_entry(i, &stlog->log_entries[i]);
525 for (i = 0; i < stlog->mostrecenttest; i++)
526 print_selftest_entry(i, &stlog->log_entries[i]);
527 }
528
529 /*
530 * is_smart:
531 *
532 * Detect whether device supports SMART and SMART is enabled.
533 */
534
535 int
536 is_smart(void)
537 {
538 int retval = 0;
539 struct atareq req;
540 unsigned char inbuf[DEV_BSIZE];
541 struct ataparams *inqbuf;
542 char *status;
543
544 memset(&inbuf, 0, sizeof(inbuf));
545 memset(&req, 0, sizeof(req));
546
547 inqbuf = (struct ataparams *) inbuf;
548
549 req.flags = ATACMD_READ;
550 req.command = WDCC_IDENTIFY;
551 req.databuf = (caddr_t) inbuf;
552 req.datalen = sizeof(inbuf);
553 req.timeout = 1000;
554
555 ata_command(&req);
556
557 if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
558 if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
559 fprintf(stderr, "SMART unsupported\n");
560 } else {
561 if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
562 inqbuf->atap_cmd_set2 == 0xffff ||
563 inqbuf->atap_cmd_set2 == 0x0000) {
564 status = "status unknown";
565 retval = 2;
566 } else {
567 if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) {
568 status = "enabled";
569 retval = 1;
570 } else {
571 status = "disabled";
572 }
573 }
574 printf("SMART supported, SMART %s\n", status);
575 }
576 }
577 return retval;
578 }
579
580 /*
581 * DEVICE COMMANDS
582 */
583
584 /*
585 * device_identify:
586 *
587 * Display the identity of the device
588 */
589 void
590 device_identify(int argc, char *argv[])
591 {
592 struct ataparams *inqbuf;
593 struct atareq req;
594 unsigned char inbuf[DEV_BSIZE];
595 #if BYTE_ORDER == LITTLE_ENDIAN
596 int i;
597 u_int16_t *p;
598 #endif
599
600 /* No arguments. */
601 if (argc != 0)
602 usage();
603
604 memset(&inbuf, 0, sizeof(inbuf));
605 memset(&req, 0, sizeof(req));
606
607 inqbuf = (struct ataparams *) inbuf;
608
609 req.flags = ATACMD_READ;
610 req.command = WDCC_IDENTIFY;
611 req.databuf = (caddr_t) inbuf;
612 req.datalen = sizeof(inbuf);
613 req.timeout = 1000;
614
615 ata_command(&req);
616
617 #if BYTE_ORDER == LITTLE_ENDIAN
618 /*
619 * On little endian machines, we need to shuffle the string
620 * byte order. However, we don't have to do this for NEC or
621 * Mitsumi ATAPI devices
622 */
623
624 if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI &&
625 ((inqbuf->atap_model[0] == 'N' &&
626 inqbuf->atap_model[1] == 'E') ||
627 (inqbuf->atap_model[0] == 'F' &&
628 inqbuf->atap_model[1] == 'X')))) {
629 for (i = 0 ; i < sizeof(inqbuf->atap_model); i += 2) {
630 p = (u_short *) (inqbuf->atap_model + i);
631 *p = ntohs(*p);
632 }
633 for (i = 0 ; i < sizeof(inqbuf->atap_serial); i += 2) {
634 p = (u_short *) (inqbuf->atap_serial + i);
635 *p = ntohs(*p);
636 }
637 for (i = 0 ; i < sizeof(inqbuf->atap_revision); i += 2) {
638 p = (u_short *) (inqbuf->atap_revision + i);
639 *p = ntohs(*p);
640 }
641 }
642 #endif
643
644 /*
645 * Strip blanks off of the info strings. Yuck, I wish this was
646 * cleaner.
647 */
648
649 if (inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] == ' ') {
650 inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] = '\0';
651 while (inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] == ' ')
652 inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] = '\0';
653 }
654
655 if (inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] == ' ') {
656 inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] = '\0';
657 while (inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] == ' ')
658 inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] = '\0';
659 }
660
661 if (inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] == ' ') {
662 inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] = '\0';
663 while (inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] == ' ')
664 inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] = '\0';
665 }
666
667 printf("Model: %.*s, Rev: %.*s, Serial #: %.*s\n",
668 (int) sizeof(inqbuf->atap_model), inqbuf->atap_model,
669 (int) sizeof(inqbuf->atap_revision), inqbuf->atap_revision,
670 (int) sizeof(inqbuf->atap_serial), inqbuf->atap_serial);
671
672 printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ?
673 "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" :
674 "removable");
675
676 if ((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == 0)
677 printf("Cylinders: %d, heads: %d, sec/track: %d, total "
678 "sectors: %d\n", inqbuf->atap_cylinders,
679 inqbuf->atap_heads, inqbuf->atap_sectors,
680 (inqbuf->atap_capacity[1] << 16) |
681 inqbuf->atap_capacity[0]);
682
683 if (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK)
684 printf("Device supports command queue depth of %d\n",
685 inqbuf->atap_queuedepth & 0xf);
686
687 printf("Device capabilities:\n");
688 print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
689
690 if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
691 printf("Device supports following standards:\n");
692 print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
693 printf("\n");
694 }
695
696 if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
697 inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
698 printf("Command set support:\n");
699 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1, ata_cmd_set1);
700 print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2, ata_cmd_set2);
701 if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
702 print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
703 ata_cmd_ext);
704 }
705
706 if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
707 printf("Command sets/features enabled:\n");
708 print_bitinfo("\t", "\n", inqbuf->atap_cmd1_en &
709 (WDC_CMD1_SRV | WDC_CMD1_RLSE | WDC_CMD1_AHEAD |
710 WDC_CMD1_CACHE | WDC_CMD1_SEC | WDC_CMD1_SMART),
711 ata_cmd_set1);
712 print_bitinfo("\t", "\n", inqbuf->atap_cmd2_en &
713 (WDC_CMD2_RMSN | ATA_CMD2_APM), ata_cmd_set2);
714 }
715
716 return;
717 }
718
719 /*
720 * device idle:
721 *
722 * issue the IDLE IMMEDIATE command to the drive
723 */
724
725 void
726 device_idle(int argc, char *argv[])
727 {
728 struct atareq req;
729
730 /* No arguments. */
731 if (argc != 0)
732 usage();
733
734 memset(&req, 0, sizeof(req));
735
736 if (strcmp(cmdname, "idle") == 0)
737 req.command = WDCC_IDLE_IMMED;
738 else if (strcmp(cmdname, "standby") == 0)
739 req.command = WDCC_STANDBY_IMMED;
740 else
741 req.command = WDCC_SLEEP;
742
743 req.timeout = 1000;
744
745 ata_command(&req);
746
747 return;
748 }
749
750 /*
751 * Set the idle timer on the disk. Set it for either idle mode or
752 * standby mode, depending on how we were invoked.
753 */
754
755 void
756 device_setidle(int argc, char *argv[])
757 {
758 unsigned long idle;
759 struct atareq req;
760 char *end;
761
762 /* Only one argument */
763 if (argc != 1)
764 usage();
765
766 idle = strtoul(argv[0], &end, 0);
767
768 if (*end != '\0') {
769 fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
770 exit(1);
771 }
772
773 if (idle > 19800) {
774 fprintf(stderr, "Idle time has a maximum value of 5.5 "
775 "hours\n");
776 exit(1);
777 }
778
779 if (idle != 0 && idle < 5) {
780 fprintf(stderr, "Idle timer must be at least 5 seconds\n");
781 exit(1);
782 }
783
784 memset(&req, 0, sizeof(req));
785
786 if (idle <= 240*5)
787 req.sec_count = idle / 5;
788 else
789 req.sec_count = idle / (30*60) + 240;
790
791 req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
792 req.timeout = 1000;
793
794 ata_command(&req);
795
796 return;
797 }
798
799 /*
800 * Query the device for the current power mode
801 */
802
803 void
804 device_checkpower(int argc, char *argv[])
805 {
806 struct atareq req;
807
808 /* No arguments. */
809 if (argc != 0)
810 usage();
811
812 memset(&req, 0, sizeof(req));
813
814 req.command = WDCC_CHECK_PWR;
815 req.timeout = 1000;
816 req.flags = ATACMD_READREG;
817
818 ata_command(&req);
819
820 printf("Current power status: ");
821
822 switch (req.sec_count) {
823 case 0x00:
824 printf("Standby mode\n");
825 break;
826 case 0x80:
827 printf("Idle mode\n");
828 break;
829 case 0xff:
830 printf("Active mode\n");
831 break;
832 default:
833 printf("Unknown power code (%02x)\n", req.sec_count);
834 }
835
836 return;
837 }
838
839 /*
840 * device_smart:
841 *
842 * Display SMART status
843 */
844 void
845 device_smart(int argc, char *argv[])
846 {
847 struct atareq req;
848 unsigned char inbuf[DEV_BSIZE];
849 unsigned char inbuf2[DEV_BSIZE];
850
851 /* Only one argument */
852 if (argc != 1)
853 usage();
854
855 if (strcmp(argv[0], "enable") == 0) {
856 memset(&req, 0, sizeof(req));
857
858 req.features = WDSM_ENABLE_OPS;
859 req.command = WDCC_SMART;
860 req.cylinder = htole16(WDSMART_CYL);
861 req.timeout = 1000;
862
863 ata_command(&req);
864
865 is_smart();
866 } else if (strcmp(argv[0], "disable") == 0) {
867 memset(&req, 0, sizeof(req));
868
869 req.features = WDSM_DISABLE_OPS;
870 req.command = WDCC_SMART;
871 req.cylinder = htole16(WDSMART_CYL);
872 req.timeout = 1000;
873
874 ata_command(&req);
875
876 is_smart();
877 } else if (strcmp(argv[0], "status") == 0) {
878 if (!is_smart()) {
879 fprintf(stderr, "SMART not supported\n");
880 return;
881 }
882
883 memset(&inbuf, 0, sizeof(inbuf));
884 memset(&req, 0, sizeof(req));
885
886 req.features = WDSM_STATUS;
887 req.command = WDCC_SMART;
888 req.cylinder = htole16(WDSMART_CYL);
889 req.timeout = 1000;
890
891 ata_command(&req);
892
893 if (req.cylinder != htole16(WDSMART_CYL)) {
894 fprintf(stderr, "Threshold exceeds condition\n");
895 }
896
897 /* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
898 * features, the following ata_command()'s may error
899 * and exit().
900 */
901
902 memset(&inbuf, 0, sizeof(inbuf));
903 memset(&req, 0, sizeof(req));
904
905 req.flags = ATACMD_READ;
906 req.features = WDSM_RD_DATA;
907 req.command = WDCC_SMART;
908 req.databuf = (caddr_t) inbuf;
909 req.datalen = sizeof(inbuf);
910 req.cylinder = htole16(WDSMART_CYL);
911 req.timeout = 1000;
912
913 ata_command(&req);
914
915 memset(&inbuf2, 0, sizeof(inbuf2));
916 memset(&req, 0, sizeof(req));
917
918 req.flags = ATACMD_READ;
919 req.features = WDSM_RD_THRESHOLDS;
920 req.command = WDCC_SMART;
921 req.databuf = (caddr_t) inbuf2;
922 req.datalen = sizeof(inbuf2);
923 req.cylinder = htole16(WDSMART_CYL);
924 req.timeout = 1000;
925
926 ata_command(&req);
927
928 print_smart_status(inbuf, inbuf2);
929
930 } else if (strcmp(argv[0], "selftest-log") == 0) {
931 if (!is_smart()) {
932 fprintf(stderr, "SMART not supported\n");
933 return;
934 }
935
936 memset(&inbuf, 0, sizeof(inbuf));
937 memset(&req, 0, sizeof(req));
938
939 req.flags = ATACMD_READ;
940 req.features = WDSM_RD_LOG;
941 req.sec_count = 1;
942 req.sec_num = 6;
943 req.command = WDCC_SMART;
944 req.databuf = (caddr_t) inbuf;
945 req.datalen = sizeof(inbuf);
946 req.cylinder = htole16(WDSMART_CYL);
947 req.timeout = 1000;
948
949 ata_command(&req);
950
951 print_selftest(inbuf);
952
953 } else {
954 usage();
955 }
956 return;
957 }
958