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