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