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