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