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