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