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