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