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