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