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