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