xref: /netbsd-src/sbin/atactl/atactl.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: atactl.c,v 1.41 2005/11/29 08:47:22 dbj 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.41 2005/11/29 08:47:22 dbj 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 	"Interruped 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 				}
789 			}
790 			printf("SMART supported, SMART %s\n", status);
791 		}
792 	}
793 	return retval;
794 }
795 
796 /*
797  * DEVICE COMMANDS
798  */
799 
800 /*
801  * device_identify:
802  *
803  *	Display the identity of the device
804  */
805 void
806 device_identify(int argc, char *argv[])
807 {
808 	struct ataparams *inqbuf;
809 #if BYTE_ORDER == LITTLE_ENDIAN
810 	int i;
811 	u_int16_t *p;
812 #endif
813 
814 	/* No arguments. */
815 	if (argc != 0)
816 		usage();
817 
818 	inqbuf = getataparams();
819 
820 #if BYTE_ORDER == LITTLE_ENDIAN
821 	/*
822 	 * On little endian machines, we need to shuffle the string
823 	 * byte order.  However, we don't have to do this for NEC or
824 	 * Mitsumi ATAPI devices
825 	 */
826 
827 	if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI &&
828 	      ((inqbuf->atap_model[0] == 'N' &&
829 		  inqbuf->atap_model[1] == 'E') ||
830 	       (inqbuf->atap_model[0] == 'F' &&
831 		  inqbuf->atap_model[1] == 'X')))) {
832 		for (i = 0 ; i < sizeof(inqbuf->atap_model); i += 2) {
833 			p = (u_short *) (inqbuf->atap_model + i);
834 			*p = ntohs(*p);
835 		}
836 		for (i = 0 ; i < sizeof(inqbuf->atap_serial); i += 2) {
837 			p = (u_short *) (inqbuf->atap_serial + i);
838 			*p = ntohs(*p);
839 		}
840 		for (i = 0 ; i < sizeof(inqbuf->atap_revision); i += 2) {
841 			p = (u_short *) (inqbuf->atap_revision + i);
842 			*p = ntohs(*p);
843 		}
844 	}
845 #endif
846 
847 	/*
848 	 * Strip blanks off of the info strings.  Yuck, I wish this was
849 	 * cleaner.
850 	 */
851 
852 	if (inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] == ' ') {
853 		inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] = '\0';
854 		while (inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] == ' ')
855 			inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] = '\0';
856 	}
857 
858 	if (inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] == ' ') {
859 		inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] = '\0';
860 		while (inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] == ' ')
861 			inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] = '\0';
862 	}
863 
864 	if (inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] == ' ') {
865 		inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] = '\0';
866 		while (inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] == ' ')
867 			inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] = '\0';
868 	}
869 
870 	printf("Model: %.*s, Rev: %.*s, Serial #: %.*s\n",
871 	       (int) sizeof(inqbuf->atap_model), inqbuf->atap_model,
872 	       (int) sizeof(inqbuf->atap_revision), inqbuf->atap_revision,
873 	       (int) sizeof(inqbuf->atap_serial), inqbuf->atap_serial);
874 
875 	printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ?
876 	       "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" :
877 	       "removable");
878 
879 	if ((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == 0)
880 		printf("Cylinders: %d, heads: %d, sec/track: %d, total "
881 		       "sectors: %d\n", inqbuf->atap_cylinders,
882 		       inqbuf->atap_heads, inqbuf->atap_sectors,
883 		       (inqbuf->atap_capacity[1] << 16) |
884 		       inqbuf->atap_capacity[0]);
885 
886 	if (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK)
887 		printf("Device supports command queue depth of %d\n",
888 		       inqbuf->atap_queuedepth & 0xf);
889 
890 	printf("Device capabilities:\n");
891 	print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
892 
893 	if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
894 		printf("Device supports following standards:\n");
895 		print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
896 		printf("\n");
897 	}
898 
899 	if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
900 	    inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
901 		printf("Command set support:\n");
902 		if (inqbuf->atap_cmd1_en != 0 && inqbuf->atap_cmd1_en != 0xffff)
903 			print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set1,
904 			    inqbuf->atap_cmd1_en, ata_cmd_set1);
905 		else
906 			print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1,
907 			    ata_cmd_set1);
908 		if (inqbuf->atap_cmd2_en != 0 && inqbuf->atap_cmd2_en != 0xffff)
909 			print_bitinfo2("\t", "\n", inqbuf->atap_cmd_set2,
910 			    inqbuf->atap_cmd2_en, ata_cmd_set2);
911 		else
912 			print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2,
913 			    ata_cmd_set2);
914 		if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
915 			print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
916 			    ata_cmd_ext);
917 	}
918 
919 	return;
920 }
921 
922 /*
923  * device idle:
924  *
925  * issue the IDLE IMMEDIATE command to the drive
926  */
927 
928 void
929 device_idle(int argc, char *argv[])
930 {
931 	struct atareq req;
932 
933 	/* No arguments. */
934 	if (argc != 0)
935 		usage();
936 
937 	memset(&req, 0, sizeof(req));
938 
939 	if (strcmp(cmdname, "idle") == 0)
940 		req.command = WDCC_IDLE_IMMED;
941 	else if (strcmp(cmdname, "standby") == 0)
942 		req.command = WDCC_STANDBY_IMMED;
943 	else
944 		req.command = WDCC_SLEEP;
945 
946 	req.timeout = 1000;
947 
948 	ata_command(&req);
949 
950 	return;
951 }
952 
953 /*
954  * Set the idle timer on the disk.  Set it for either idle mode or
955  * standby mode, depending on how we were invoked.
956  */
957 
958 void
959 device_setidle(int argc, char *argv[])
960 {
961 	unsigned long idle;
962 	struct atareq req;
963 	char *end;
964 
965 	/* Only one argument */
966 	if (argc != 1)
967 		usage();
968 
969 	idle = strtoul(argv[0], &end, 0);
970 
971 	if (*end != '\0') {
972 		fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
973 		exit(1);
974 	}
975 
976 	if (idle > 19800) {
977 		fprintf(stderr, "Idle time has a maximum value of 5.5 "
978 			"hours\n");
979 		exit(1);
980 	}
981 
982 	if (idle != 0 && idle < 5) {
983 		fprintf(stderr, "Idle timer must be at least 5 seconds\n");
984 		exit(1);
985 	}
986 
987 	memset(&req, 0, sizeof(req));
988 
989 	if (idle <= 240*5)
990 		req.sec_count = idle / 5;
991 	else
992 		req.sec_count = idle / (30*60) + 240;
993 
994 	req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
995 	req.timeout = 1000;
996 
997 	ata_command(&req);
998 
999 	return;
1000 }
1001 
1002 /*
1003  * Query the device for the current power mode
1004  */
1005 
1006 void
1007 device_checkpower(int argc, char *argv[])
1008 {
1009 	struct atareq req;
1010 
1011 	/* No arguments. */
1012 	if (argc != 0)
1013 		usage();
1014 
1015 	memset(&req, 0, sizeof(req));
1016 
1017 	req.command = WDCC_CHECK_PWR;
1018 	req.timeout = 1000;
1019 	req.flags = ATACMD_READREG;
1020 
1021 	ata_command(&req);
1022 
1023 	printf("Current power status: ");
1024 
1025 	switch (req.sec_count) {
1026 	case 0x00:
1027 		printf("Standby mode\n");
1028 		break;
1029 	case 0x80:
1030 		printf("Idle mode\n");
1031 		break;
1032 	case 0xff:
1033 		printf("Active mode\n");
1034 		break;
1035 	default:
1036 		printf("Unknown power code (%02x)\n", req.sec_count);
1037 	}
1038 
1039 	return;
1040 }
1041 
1042 /*
1043  * device_smart:
1044  *
1045  *	Display SMART status
1046  */
1047 void
1048 device_smart(int argc, char *argv[])
1049 {
1050 	struct atareq req;
1051 	unsigned char inbuf[DEV_BSIZE];
1052 	unsigned char inbuf2[DEV_BSIZE];
1053 
1054 	if (argc < 1)
1055 		usage();
1056 
1057 	if (strcmp(argv[0], "enable") == 0) {
1058 		memset(&req, 0, sizeof(req));
1059 
1060 		req.features = WDSM_ENABLE_OPS;
1061 		req.command = WDCC_SMART;
1062 		req.cylinder = WDSMART_CYL;
1063 		req.timeout = 1000;
1064 
1065 		ata_command(&req);
1066 
1067 		is_smart();
1068 	} else if (strcmp(argv[0], "disable") == 0) {
1069 		memset(&req, 0, sizeof(req));
1070 
1071 		req.features = WDSM_DISABLE_OPS;
1072 		req.command = WDCC_SMART;
1073 		req.cylinder = WDSMART_CYL;
1074 		req.timeout = 1000;
1075 
1076 		ata_command(&req);
1077 
1078 		is_smart();
1079 	} else if (strcmp(argv[0], "status") == 0) {
1080 		if (!is_smart()) {
1081 			fprintf(stderr, "SMART not supported\n");
1082 			return;
1083 		}
1084 
1085 			memset(&inbuf, 0, sizeof(inbuf));
1086 			memset(&req, 0, sizeof(req));
1087 
1088 			req.features = WDSM_STATUS;
1089 			req.command = WDCC_SMART;
1090 			req.cylinder = WDSMART_CYL;
1091 			req.timeout = 1000;
1092 
1093 			ata_command(&req);
1094 
1095 			if (req.cylinder != WDSMART_CYL) {
1096 				fprintf(stderr, "Threshold exceeds condition\n");
1097 			}
1098 
1099 			/* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
1100 			 * features, the following ata_command()'s may error
1101 			 * and exit().
1102 			 */
1103 
1104 			memset(&inbuf, 0, sizeof(inbuf));
1105 			memset(&req, 0, sizeof(req));
1106 
1107 			req.flags = ATACMD_READ;
1108 			req.features = WDSM_RD_DATA;
1109 			req.command = WDCC_SMART;
1110 			req.databuf = (caddr_t) inbuf;
1111 			req.datalen = sizeof(inbuf);
1112 			req.cylinder = WDSMART_CYL;
1113 			req.timeout = 1000;
1114 
1115 			ata_command(&req);
1116 
1117 			memset(&inbuf2, 0, sizeof(inbuf2));
1118 			memset(&req, 0, sizeof(req));
1119 
1120 			req.flags = ATACMD_READ;
1121 			req.features = WDSM_RD_THRESHOLDS;
1122 			req.command = WDCC_SMART;
1123 			req.databuf = (caddr_t) inbuf2;
1124 			req.datalen = sizeof(inbuf2);
1125 			req.cylinder = WDSMART_CYL;
1126 			req.timeout = 1000;
1127 
1128 			ata_command(&req);
1129 
1130 			print_smart_status(inbuf, inbuf2);
1131 
1132 	} else if (strcmp(argv[0], "offline") == 0) {
1133 		if (argc != 2)
1134 			usage();
1135 		if (!is_smart()) {
1136 			fprintf(stderr, "SMART not supported\n");
1137 			return;
1138 		}
1139 
1140 		memset(&req, 0, sizeof(req));
1141 
1142 		req.features = WDSM_EXEC_OFFL_IMM;
1143 		req.command = WDCC_SMART;
1144 		req.cylinder = WDSMART_CYL;
1145 		req.sec_num = atol(argv[1]);
1146 		req.timeout = 10000;
1147 
1148 		ata_command(&req);
1149 	} else if (strcmp(argv[0], "error-log") == 0) {
1150 		if (!is_smart()) {
1151 			fprintf(stderr, "SMART not supported\n");
1152 			return;
1153 		}
1154 
1155 		memset(&inbuf, 0, sizeof(inbuf));
1156 		memset(&req, 0, sizeof(req));
1157 
1158 		req.flags = ATACMD_READ;
1159 		req.features = WDSM_RD_LOG;
1160 		req.sec_count = 1;
1161 		req.sec_num = 1;
1162 		req.command = WDCC_SMART;
1163 		req.databuf = (caddr_t) inbuf;
1164 		req.datalen = sizeof(inbuf);
1165 		req.cylinder = WDSMART_CYL;
1166 		req.timeout = 1000;
1167 
1168 		ata_command(&req);
1169 
1170 		print_error(inbuf);
1171 	} else if (strcmp(argv[0], "selftest-log") == 0) {
1172 		if (!is_smart()) {
1173 			fprintf(stderr, "SMART not supported\n");
1174 			return;
1175 		}
1176 
1177 		memset(&inbuf, 0, sizeof(inbuf));
1178 		memset(&req, 0, sizeof(req));
1179 
1180 		req.flags = ATACMD_READ;
1181 		req.features = WDSM_RD_LOG;
1182 		req.sec_count = 1;
1183 		req.sec_num = 6;
1184 		req.command = WDCC_SMART;
1185 		req.databuf = (caddr_t) inbuf;
1186 		req.datalen = sizeof(inbuf);
1187 		req.cylinder = WDSMART_CYL;
1188 		req.timeout = 1000;
1189 
1190 		ata_command(&req);
1191 
1192 		print_selftest(inbuf);
1193 
1194 	} else {
1195 		usage();
1196 	}
1197 	return;
1198 }
1199 
1200 void
1201 device_security(int argc, char *argv[])
1202 {
1203 	struct atareq req;
1204 	struct ataparams *inqbuf;
1205 
1206 	/* need subcommand */
1207 	if (argc < 1)
1208 		usage();
1209 
1210 	if (strcmp(argv[0], "freeze") == 0) {
1211 		memset(&req, 0, sizeof(req));
1212 		req.command = WCDD_SECURITY_FREEZE;
1213 		req.timeout = 1000;
1214 		ata_command(&req);
1215 	} else if (strcmp(argv[0], "status") == 0) {
1216 		inqbuf = getataparams();
1217 		print_bitinfo("\t", "\n", inqbuf->atap_sec_st, ata_sec_st);
1218 	} else
1219 		usage();
1220 
1221 	return;
1222 }
1223 
1224 /*
1225  * bus_reset:
1226  *	Reset an ATA bus (will reset all devices on the bus)
1227  */
1228 void
1229 bus_reset(int argc, char *argv[])
1230 {
1231 	int error;
1232 
1233 	/* no args */
1234 	if (argc != 0)
1235 		usage();
1236 
1237 	error = ioctl(fd, ATABUSIORESET, NULL);
1238 
1239 	if (error == -1)
1240 		err(1, "ATABUSIORESET failed");
1241 }
1242