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