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