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