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