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