Home | History | Annotate | Line # | Download | only in atactl
atactl.c revision 1.31
      1 /*	$NetBSD: atactl.c,v 1.31 2004/09/10 03:43:52 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.31 2004/09/10 03:43:52 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 	{ 0,		"Unknown" },
    221 };
    222 
    223 int
    224 main(int argc, char *argv[])
    225 {
    226 	int i;
    227 	struct command *commands = NULL;
    228 
    229 	/* Must have at least: device command */
    230 	if (argc < 3)
    231 		usage();
    232 
    233 	/* Skip program name, get and skip device name and command. */
    234 	dvname = argv[1];
    235 	cmdname = argv[2];
    236 	argv += 3;
    237 	argc -= 3;
    238 
    239 	/*
    240 	 * Open the device
    241 	 */
    242 	fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
    243 	if (fd == -1) {
    244 		if (errno == ENOENT) {
    245 			/*
    246 			 * Device doesn't exist.  Probably trying to open
    247 			 * a device which doesn't use disk semantics for
    248 			 * device name.  Try again, specifying "cooked",
    249 			 * which leaves off the "r" in front of the device's
    250 			 * name.
    251 			 */
    252 			fd = opendisk(dvname, O_RDWR, dvname_store,
    253 			    sizeof(dvname_store), 1);
    254 			if (fd == -1)
    255 				err(1, "%s", dvname);
    256 		} else
    257 			err(1, "%s", dvname);
    258 	}
    259 
    260 	/*
    261 	 * Point the dvname at the actual device name that opendisk() opened.
    262 	 */
    263 	dvname = dvname_store;
    264 
    265 	/* Look up and call the command. */
    266 	for (i = 0; device_commands[i].cmd_name != NULL; i++) {
    267 		if (strcmp(cmdname, device_commands[i].cmd_name) == 0) {
    268 			commands = &device_commands[i];
    269 			break;
    270 		}
    271 	}
    272 	if (commands == NULL) {
    273 		for (i = 0; bus_commands[i].cmd_name != NULL; i++) {
    274 			if (strcmp(cmdname, bus_commands[i].cmd_name) == 0) {
    275 				commands = &bus_commands[i];
    276 				break;
    277 			}
    278 		}
    279 	}
    280 	if (commands == NULL)
    281 		errx(1, "unknown command: %s", cmdname);
    282 
    283 	argnames = commands->arg_names;
    284 
    285 	(*commands->cmd_func)(argc, argv);
    286 	exit(0);
    287 }
    288 
    289 void
    290 usage(void)
    291 {
    292 	int i;
    293 
    294 	fprintf(stderr, "usage: %s device command [arg [...]]\n",
    295 	    getprogname());
    296 
    297 	fprintf(stderr, "   Available device commands:\n");
    298 	for (i=0; device_commands[i].cmd_name != NULL; i++)
    299 		fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
    300 					    device_commands[i].arg_names);
    301 
    302 	fprintf(stderr, "   Available bus commands:\n");
    303 	for (i=0; bus_commands[i].cmd_name != NULL; i++)
    304 		fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
    305 					    bus_commands[i].arg_names);
    306 
    307 	exit(1);
    308 }
    309 
    310 /*
    311  * Wrapper that calls ATAIOCCOMMAND and checks for errors
    312  */
    313 
    314 void
    315 ata_command(struct atareq *req)
    316 {
    317 	int error;
    318 
    319 	error = ioctl(fd, ATAIOCCOMMAND, req);
    320 
    321 	if (error == -1)
    322 		err(1, "ATAIOCCOMMAND failed");
    323 
    324 	switch (req->retsts) {
    325 
    326 	case ATACMD_OK:
    327 		return;
    328 	case ATACMD_TIMEOUT:
    329 		fprintf(stderr, "ATA command timed out\n");
    330 		exit(1);
    331 	case ATACMD_DF:
    332 		fprintf(stderr, "ATA device returned a Device Fault\n");
    333 		exit(1);
    334 	case ATACMD_ERROR:
    335 		if (req->error & WDCE_ABRT)
    336 			fprintf(stderr, "ATA device returned Aborted "
    337 				"Command\n");
    338 		else
    339 			fprintf(stderr, "ATA device returned error register "
    340 				"%0x\n", req->error);
    341 		exit(1);
    342 	default:
    343 		fprintf(stderr, "ATAIOCCOMMAND returned unknown result code "
    344 			"%d\n", req->retsts);
    345 		exit(1);
    346 	}
    347 }
    348 
    349 /*
    350  * Print out strings associated with particular bitmasks
    351  */
    352 
    353 void
    354 print_bitinfo(const char *bf, const char *af, u_int bits, struct bitinfo *binfo)
    355 {
    356 
    357 	for (; binfo->bitmask != 0; binfo++)
    358 		if (bits & binfo->bitmask)
    359 			printf("%s%s%s", bf, binfo->string, af);
    360 }
    361 
    362 
    363 /*
    364  * Try to print SMART temperature field
    365  */
    366 
    367 void
    368 device_smart_temp(struct ata_smart_attr *attr, uint64_t raw_value)
    369 {
    370 	printf("%" PRIu8, attr->raw[0]);
    371 	if (attr->raw[0] != raw_value)
    372 		printf(" Lifetime max/min %" PRIu8 "/%" PRIu8,
    373 		    attr->raw[2], attr->raw[4]);
    374 }
    375 
    376 
    377 /*
    378  * Print out SMART attribute thresholds and values
    379  */
    380 
    381 void
    382 print_smart_status(void *vbuf, void *tbuf)
    383 {
    384 	struct ata_smart_attributes *value_buf = vbuf;
    385 	struct ata_smart_thresholds *threshold_buf = tbuf;
    386 	struct ata_smart_attr *attr;
    387 	uint64_t raw_value;
    388 	int flags;
    389 	int i, j;
    390 	int aid;
    391 	int8_t checksum;
    392 
    393 	for (i = checksum = 0; i < 511; i++)
    394 		checksum += ((int8_t *) value_buf)[i];
    395 	checksum *= -1;
    396 	if (checksum != value_buf->checksum) {
    397 		fprintf(stderr, "SMART attribute values checksum error\n");
    398 		return;
    399 	}
    400 
    401 	for (i = checksum = 0; i < 511; i++)
    402 		checksum += ((int8_t *) threshold_buf)[i];
    403 	checksum *= -1;
    404 	if (checksum != threshold_buf->checksum) {
    405 		fprintf(stderr, "SMART attribute thresholds checksum error\n");
    406 		return;
    407 	}
    408 
    409 	printf("id value thresh crit collect reliability description\t\t\traw\n");
    410 	for (i = 0; i < 256; i++) {
    411 		int thresh = 0;
    412 
    413 		attr = NULL;
    414 
    415 		for (j = 0; j < 30; j++) {
    416 			if (value_buf->attributes[j].id == i)
    417 				attr = &value_buf->attributes[j];
    418 			if (threshold_buf->thresholds[j].id == i)
    419 				thresh = threshold_buf->thresholds[j].value;
    420 		}
    421 
    422 		if (thresh && attr == NULL)
    423 			errx(1, "threshold but not attr %d", i);
    424 		if (attr == NULL)
    425 			continue;
    426 
    427 		if (attr->value == 0||attr->value == 0xFE||attr->value == 0xFF)
    428 			continue;
    429 
    430 		for (aid = 0;
    431 		     smart_attrs[aid].id != i && smart_attrs[aid].id != 0;
    432 		     aid++)
    433 			;
    434 
    435 		flags = attr->flags;
    436 
    437 		printf("%3d %3d  %3d     %-3s %-7s %stive    %-24s\t",
    438 		    i, attr->value, thresh,
    439 		    flags & WDSM_ATTR_ADVISORY ? "yes" : "no",
    440 		    flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline",
    441 		    attr->value > thresh ? "posi" : "nega",
    442 		    smart_attrs[aid].name);
    443 
    444 		for (j = 0, raw_value = 0; j < 6; j++)
    445 			raw_value += ((uint64_t)attr->raw[j]) << (8*j);
    446 
    447 		if (smart_attrs[aid].special)
    448 			(*smart_attrs[aid].special)(attr, raw_value);
    449 		else
    450 			printf("%" PRIu64, raw_value);
    451 		printf("\n");
    452 		}
    453 	}
    454 
    455 struct {
    456 	int number;
    457 	const char *name;
    458 } selftest_name[] = {
    459 	{ 0, "Off-line" },
    460 	{ 1, "Short off-line" },
    461 	{ 2, "Extended off-line" },
    462 	{ 127, "Abort off-line test" },
    463 	{ 129, "Short captive" },
    464 	{ 130, "Extended captive" },
    465 	{ 256, "Unknown test" }, /* larger then u_int8_t */
    466 	{ 0, NULL }
    467 };
    468 
    469 const char *selftest_status[] = {
    470 	"No error",
    471 	"Aborted by the host",
    472 	"Interruped by the host by reset",
    473 	"Fatal error or unknown test error",
    474 	"Unknown test element failed",
    475 	"Electrical test element failed",
    476 	"The Servo (and/or seek) test element failed",
    477 	"Read element of test failed",
    478 	"Reserved",
    479 	"Reserved",
    480 	"Reserved",
    481 	"Reserved",
    482 	"Reserved",
    483 	"Reserved",
    484 	"Reserved",
    485 	"Self-test in progress"
    486 };
    487 
    488 void
    489 print_selftest_entry(int num, struct ata_smart_selftest *le)
    490 {
    491 	unsigned char *p;
    492 	int i;
    493 
    494 	/* check if all zero */
    495 	for (p = (void *)le, i = 0; i < sizeof(*le); i++)
    496 		if (p[i] != 0)
    497 			break;
    498 	if (i == sizeof(*le))
    499 		return;
    500 
    501 	printf("Log entry: %d\n", num);
    502 
    503 	/* Get test name */
    504 	for (i = 0; selftest_name[i].name != NULL; i++)
    505 		if (selftest_name[i].number == le->number)
    506 			break;
    507 	if (selftest_name[i].number == 0)
    508 		i = 255; /* unknown test */
    509 
    510 	printf("\tName: %s\n", selftest_name[i].name);
    511 	printf("\tStatus: %s\n", selftest_status[le->status >> 4]);
    512 	if (le->status >> 4 == 15)
    513 		printf("\tPrecent of test remaning: %1d0\n", le->status & 0xf);
    514 	if (le->status)
    515 		printf("LBA first error: %d\n", le->lba_first_error);
    516 }
    517 
    518 void
    519 print_selftest(void *buf)
    520 {
    521 	struct ata_smart_selftestlog *stlog = buf;
    522 	int8_t checksum;
    523 	int i;
    524 
    525 	for (i = checksum = 0; i < 511; i++)
    526 		checksum += ((int8_t *) buf)[i];
    527   	checksum *= -1;
    528 	if ((u_int8_t)checksum != stlog->checksum) {
    529 		fprintf(stderr, "SMART selftest log checksum error\n");
    530 		return;
    531 	}
    532 
    533 	if (stlog->data_structure_revision != 1) {
    534 		fprintf(stderr, "Log revision not 1");
    535 		return;
    536 	}
    537 
    538 	if (stlog->mostrecenttest == 0) {
    539 		printf("No self-tests have been logged\n");
    540 		return;
    541 	}
    542 
    543 	if (stlog->mostrecenttest > 22) {
    544 		fprintf(stderr, "Most recent test is too large\n");
    545 		return;
    546 	}
    547 
    548 	for (i = stlog->mostrecenttest; i < 22; i++)
    549 		print_selftest_entry(i, &stlog->log_entries[i]);
    550 	for (i = 0; i < stlog->mostrecenttest; i++)
    551 		print_selftest_entry(i, &stlog->log_entries[i]);
    552 }
    553 
    554 /*
    555  * is_smart:
    556  *
    557  *	Detect whether device supports SMART and SMART is enabled.
    558  */
    559 
    560 int
    561 is_smart(void)
    562 {
    563 	int retval = 0;
    564 	struct atareq req;
    565 	unsigned char inbuf[DEV_BSIZE];
    566 	struct ataparams *inqbuf;
    567 	char *status;
    568 
    569 	memset(&inbuf, 0, sizeof(inbuf));
    570 	memset(&req, 0, sizeof(req));
    571 
    572 	inqbuf = (struct ataparams *) inbuf;
    573 
    574 	req.flags = ATACMD_READ;
    575 	req.command = WDCC_IDENTIFY;
    576 	req.databuf = (caddr_t) inbuf;
    577 	req.datalen = sizeof(inbuf);
    578 	req.timeout = 1000;
    579 
    580 	ata_command(&req);
    581 
    582 	if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
    583 		if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
    584 			fprintf(stderr, "SMART unsupported\n");
    585 		} else {
    586 			if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
    587 			    inqbuf->atap_cmd_set2 == 0xffff ||
    588 			    inqbuf->atap_cmd_set2 == 0x0000) {
    589 				status = "status unknown";
    590 				retval = 2;
    591 			} else {
    592 				if (inqbuf->atap_cmd1_en & WDC_CMD1_SMART) {
    593 					status = "enabled";
    594 					retval = 1;
    595 				} else {
    596 					status = "disabled";
    597 				}
    598 			}
    599 			printf("SMART supported, SMART %s\n", status);
    600 		}
    601 	}
    602 	return retval;
    603 }
    604 
    605 /*
    606  * DEVICE COMMANDS
    607  */
    608 
    609 /*
    610  * device_identify:
    611  *
    612  *	Display the identity of the device
    613  */
    614 void
    615 device_identify(int argc, char *argv[])
    616 {
    617 	struct ataparams *inqbuf;
    618 	struct atareq req;
    619 	unsigned char inbuf[DEV_BSIZE];
    620 #if BYTE_ORDER == LITTLE_ENDIAN
    621 	int i;
    622 	u_int16_t *p;
    623 #endif
    624 
    625 	/* No arguments. */
    626 	if (argc != 0)
    627 		usage();
    628 
    629 	memset(&inbuf, 0, sizeof(inbuf));
    630 	memset(&req, 0, sizeof(req));
    631 
    632 	inqbuf = (struct ataparams *) inbuf;
    633 
    634 	req.flags = ATACMD_READ;
    635 	req.command = WDCC_IDENTIFY;
    636 	req.databuf = (caddr_t) inbuf;
    637 	req.datalen = sizeof(inbuf);
    638 	req.timeout = 1000;
    639 
    640 	ata_command(&req);
    641 
    642 #if BYTE_ORDER == LITTLE_ENDIAN
    643 	/*
    644 	 * On little endian machines, we need to shuffle the string
    645 	 * byte order.  However, we don't have to do this for NEC or
    646 	 * Mitsumi ATAPI devices
    647 	 */
    648 
    649 	if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI &&
    650 	      ((inqbuf->atap_model[0] == 'N' &&
    651 		  inqbuf->atap_model[1] == 'E') ||
    652 	       (inqbuf->atap_model[0] == 'F' &&
    653 		  inqbuf->atap_model[1] == 'X')))) {
    654 		for (i = 0 ; i < sizeof(inqbuf->atap_model); i += 2) {
    655 			p = (u_short *) (inqbuf->atap_model + i);
    656 			*p = ntohs(*p);
    657 		}
    658 		for (i = 0 ; i < sizeof(inqbuf->atap_serial); i += 2) {
    659 			p = (u_short *) (inqbuf->atap_serial + i);
    660 			*p = ntohs(*p);
    661 		}
    662 		for (i = 0 ; i < sizeof(inqbuf->atap_revision); i += 2) {
    663 			p = (u_short *) (inqbuf->atap_revision + i);
    664 			*p = ntohs(*p);
    665 		}
    666 	}
    667 #endif
    668 
    669 	/*
    670 	 * Strip blanks off of the info strings.  Yuck, I wish this was
    671 	 * cleaner.
    672 	 */
    673 
    674 	if (inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] == ' ') {
    675 		inqbuf->atap_model[sizeof(inqbuf->atap_model) - 1] = '\0';
    676 		while (inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] == ' ')
    677 			inqbuf->atap_model[strlen(inqbuf->atap_model) - 1] = '\0';
    678 	}
    679 
    680 	if (inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] == ' ') {
    681 		inqbuf->atap_revision[sizeof(inqbuf->atap_revision) - 1] = '\0';
    682 		while (inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] == ' ')
    683 			inqbuf->atap_revision[strlen(inqbuf->atap_revision) - 1] = '\0';
    684 	}
    685 
    686 	if (inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] == ' ') {
    687 		inqbuf->atap_serial[sizeof(inqbuf->atap_serial) - 1] = '\0';
    688 		while (inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] == ' ')
    689 			inqbuf->atap_serial[strlen(inqbuf->atap_serial) - 1] = '\0';
    690 	}
    691 
    692 	printf("Model: %.*s, Rev: %.*s, Serial #: %.*s\n",
    693 	       (int) sizeof(inqbuf->atap_model), inqbuf->atap_model,
    694 	       (int) sizeof(inqbuf->atap_revision), inqbuf->atap_revision,
    695 	       (int) sizeof(inqbuf->atap_serial), inqbuf->atap_serial);
    696 
    697 	printf("Device type: %s, %s\n", inqbuf->atap_config & WDC_CFG_ATAPI ?
    698 	       "ATAPI" : "ATA", inqbuf->atap_config & ATA_CFG_FIXED ? "fixed" :
    699 	       "removable");
    700 
    701 	if ((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == 0)
    702 		printf("Cylinders: %d, heads: %d, sec/track: %d, total "
    703 		       "sectors: %d\n", inqbuf->atap_cylinders,
    704 		       inqbuf->atap_heads, inqbuf->atap_sectors,
    705 		       (inqbuf->atap_capacity[1] << 16) |
    706 		       inqbuf->atap_capacity[0]);
    707 
    708 	if (inqbuf->atap_queuedepth & WDC_QUEUE_DEPTH_MASK)
    709 		printf("Device supports command queue depth of %d\n",
    710 		       inqbuf->atap_queuedepth & 0xf);
    711 
    712 	printf("Device capabilities:\n");
    713 	print_bitinfo("\t", "\n", inqbuf->atap_capabilities1, ata_caps);
    714 
    715 	if (inqbuf->atap_ata_major != 0 && inqbuf->atap_ata_major != 0xffff) {
    716 		printf("Device supports following standards:\n");
    717 		print_bitinfo("", " ", inqbuf->atap_ata_major, ata_vers);
    718 		printf("\n");
    719 	}
    720 
    721 	if (inqbuf->atap_cmd_set1 != 0 && inqbuf->atap_cmd_set1 != 0xffff &&
    722 	    inqbuf->atap_cmd_set2 != 0 && inqbuf->atap_cmd_set2 != 0xffff) {
    723 		printf("Command set support:\n");
    724 		print_bitinfo("\t", "\n", inqbuf->atap_cmd_set1, ata_cmd_set1);
    725 		print_bitinfo("\t", "\n", inqbuf->atap_cmd_set2, ata_cmd_set2);
    726 		if (inqbuf->atap_cmd_ext != 0 && inqbuf->atap_cmd_ext != 0xffff)
    727 			print_bitinfo("\t", "\n", inqbuf->atap_cmd_ext,
    728 			    ata_cmd_ext);
    729 	}
    730 
    731 	if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
    732 		printf("Command sets/features enabled:\n");
    733 		print_bitinfo("\t", "\n", inqbuf->atap_cmd1_en &
    734 			      (WDC_CMD1_SRV | WDC_CMD1_RLSE | WDC_CMD1_AHEAD |
    735 			       WDC_CMD1_CACHE | WDC_CMD1_SEC | WDC_CMD1_SMART),
    736 			       ata_cmd_set1);
    737 		print_bitinfo("\t", "\n", inqbuf->atap_cmd2_en &
    738 			      (WDC_CMD2_RMSN | ATA_CMD2_APM), ata_cmd_set2);
    739 	}
    740 
    741 	return;
    742 }
    743 
    744 /*
    745  * device idle:
    746  *
    747  * issue the IDLE IMMEDIATE command to the drive
    748  */
    749 
    750 void
    751 device_idle(int argc, char *argv[])
    752 {
    753 	struct atareq req;
    754 
    755 	/* No arguments. */
    756 	if (argc != 0)
    757 		usage();
    758 
    759 	memset(&req, 0, sizeof(req));
    760 
    761 	if (strcmp(cmdname, "idle") == 0)
    762 		req.command = WDCC_IDLE_IMMED;
    763 	else if (strcmp(cmdname, "standby") == 0)
    764 		req.command = WDCC_STANDBY_IMMED;
    765 	else
    766 		req.command = WDCC_SLEEP;
    767 
    768 	req.timeout = 1000;
    769 
    770 	ata_command(&req);
    771 
    772 	return;
    773 }
    774 
    775 /*
    776  * Set the idle timer on the disk.  Set it for either idle mode or
    777  * standby mode, depending on how we were invoked.
    778  */
    779 
    780 void
    781 device_setidle(int argc, char *argv[])
    782 {
    783 	unsigned long idle;
    784 	struct atareq req;
    785 	char *end;
    786 
    787 	/* Only one argument */
    788 	if (argc != 1)
    789 		usage();
    790 
    791 	idle = strtoul(argv[0], &end, 0);
    792 
    793 	if (*end != '\0') {
    794 		fprintf(stderr, "Invalid idle time: \"%s\"\n", argv[0]);
    795 		exit(1);
    796 	}
    797 
    798 	if (idle > 19800) {
    799 		fprintf(stderr, "Idle time has a maximum value of 5.5 "
    800 			"hours\n");
    801 		exit(1);
    802 	}
    803 
    804 	if (idle != 0 && idle < 5) {
    805 		fprintf(stderr, "Idle timer must be at least 5 seconds\n");
    806 		exit(1);
    807 	}
    808 
    809 	memset(&req, 0, sizeof(req));
    810 
    811 	if (idle <= 240*5)
    812 		req.sec_count = idle / 5;
    813 	else
    814 		req.sec_count = idle / (30*60) + 240;
    815 
    816 	req.command = cmdname[3] == 's' ? WDCC_STANDBY : WDCC_IDLE;
    817 	req.timeout = 1000;
    818 
    819 	ata_command(&req);
    820 
    821 	return;
    822 }
    823 
    824 /*
    825  * Query the device for the current power mode
    826  */
    827 
    828 void
    829 device_checkpower(int argc, char *argv[])
    830 {
    831 	struct atareq req;
    832 
    833 	/* No arguments. */
    834 	if (argc != 0)
    835 		usage();
    836 
    837 	memset(&req, 0, sizeof(req));
    838 
    839 	req.command = WDCC_CHECK_PWR;
    840 	req.timeout = 1000;
    841 	req.flags = ATACMD_READREG;
    842 
    843 	ata_command(&req);
    844 
    845 	printf("Current power status: ");
    846 
    847 	switch (req.sec_count) {
    848 	case 0x00:
    849 		printf("Standby mode\n");
    850 		break;
    851 	case 0x80:
    852 		printf("Idle mode\n");
    853 		break;
    854 	case 0xff:
    855 		printf("Active mode\n");
    856 		break;
    857 	default:
    858 		printf("Unknown power code (%02x)\n", req.sec_count);
    859 	}
    860 
    861 	return;
    862 }
    863 
    864 /*
    865  * device_smart:
    866  *
    867  *	Display SMART status
    868  */
    869 void
    870 device_smart(int argc, char *argv[])
    871 {
    872 	struct atareq req;
    873 	unsigned char inbuf[DEV_BSIZE];
    874 	unsigned char inbuf2[DEV_BSIZE];
    875 
    876 	/* Only one argument */
    877 	if (argc != 1)
    878 		usage();
    879 
    880 	if (strcmp(argv[0], "enable") == 0) {
    881 		memset(&req, 0, sizeof(req));
    882 
    883 		req.features = WDSM_ENABLE_OPS;
    884 		req.command = WDCC_SMART;
    885 		req.cylinder = htole16(WDSMART_CYL);
    886 		req.timeout = 1000;
    887 
    888 		ata_command(&req);
    889 
    890 		is_smart();
    891 	} else if (strcmp(argv[0], "disable") == 0) {
    892 		memset(&req, 0, sizeof(req));
    893 
    894 		req.features = WDSM_DISABLE_OPS;
    895 		req.command = WDCC_SMART;
    896 		req.cylinder = htole16(WDSMART_CYL);
    897 		req.timeout = 1000;
    898 
    899 		ata_command(&req);
    900 
    901 		is_smart();
    902 	} else if (strcmp(argv[0], "status") == 0) {
    903 		if (!is_smart()) {
    904 			fprintf(stderr, "SMART not supported\n");
    905 			return;
    906 		}
    907 
    908 			memset(&inbuf, 0, sizeof(inbuf));
    909 			memset(&req, 0, sizeof(req));
    910 
    911 			req.features = WDSM_STATUS;
    912 			req.command = WDCC_SMART;
    913 			req.cylinder = htole16(WDSMART_CYL);
    914 			req.timeout = 1000;
    915 
    916 			ata_command(&req);
    917 
    918 			if (req.cylinder != htole16(WDSMART_CYL)) {
    919 				fprintf(stderr, "Threshold exceeds condition\n");
    920 			}
    921 
    922 			/* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
    923 			 * features, the following ata_command()'s may error
    924 			 * and exit().
    925 			 */
    926 
    927 			memset(&inbuf, 0, sizeof(inbuf));
    928 			memset(&req, 0, sizeof(req));
    929 
    930 			req.flags = ATACMD_READ;
    931 			req.features = WDSM_RD_DATA;
    932 			req.command = WDCC_SMART;
    933 			req.databuf = (caddr_t) inbuf;
    934 			req.datalen = sizeof(inbuf);
    935 			req.cylinder = htole16(WDSMART_CYL);
    936 			req.timeout = 1000;
    937 
    938 			ata_command(&req);
    939 
    940 			memset(&inbuf2, 0, sizeof(inbuf2));
    941 			memset(&req, 0, sizeof(req));
    942 
    943 			req.flags = ATACMD_READ;
    944 			req.features = WDSM_RD_THRESHOLDS;
    945 			req.command = WDCC_SMART;
    946 			req.databuf = (caddr_t) inbuf2;
    947 			req.datalen = sizeof(inbuf2);
    948 			req.cylinder = htole16(WDSMART_CYL);
    949 			req.timeout = 1000;
    950 
    951 			ata_command(&req);
    952 
    953 			print_smart_status(inbuf, inbuf2);
    954 
    955 	} else if (strcmp(argv[0], "selftest-log") == 0) {
    956 		if (!is_smart()) {
    957 			fprintf(stderr, "SMART not supported\n");
    958 			return;
    959 		}
    960 
    961 		memset(&inbuf, 0, sizeof(inbuf));
    962 		memset(&req, 0, sizeof(req));
    963 
    964 		req.flags = ATACMD_READ;
    965 		req.features = WDSM_RD_LOG;
    966 		req.sec_count = 1;
    967 		req.sec_num = 6;
    968 		req.command = WDCC_SMART;
    969 		req.databuf = (caddr_t) inbuf;
    970 		req.datalen = sizeof(inbuf);
    971 		req.cylinder = htole16(WDSMART_CYL);
    972 		req.timeout = 1000;
    973 
    974 		ata_command(&req);
    975 
    976 		print_selftest(inbuf);
    977 
    978 	} else {
    979 		usage();
    980 	}
    981 	return;
    982 }
    983 
    984 /*
    985  * bus_reset:
    986  *	Reset an ATA bus (will reset all devices on the bus)
    987  */
    988 void
    989 bus_reset(int argc, char *argv[])
    990 {
    991 	int error;
    992 
    993 	/* no args */
    994 	if (argc != 0)
    995 		usage();
    996 
    997 	error = ioctl(fd, ATABUSIORESET, NULL);
    998 
    999 	if (error == -1)
   1000 		err(1, "ATABUSIORESET failed");
   1001 }
   1002