xref: /dragonfly/sbin/natacontrol/natacontrol.c (revision b29f78b5)
1 /*-
2  * Copyright (c) 2000 - 2006 Søren Schmidt <sos@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sbin/atacontrol/atacontrol.c,v 1.42 2006/03/15 19:32:43 sos Exp $
27  */
28 
29 #include <sys/nata.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <err.h>
37 
38 #include <sysexits.h>
39 #include <unistd.h>
40 
41 static const char *mode2str(int mode);
42 static int	str2mode(char *str);
43 static void	usage(void);
44 static int	version(int ver);
45 static void	param_print(struct ata_params *parm);
46 static void	cap_print(struct ata_params *parm);
47 static int	ata_cap_print(int fd);
48 static int	info_print(int fd, int channel, int prchan);
49 
50 const char *
51 mode2str(int mode)
52 {
53 	switch (mode) {
54 	case ATA_PIO: return "BIOSPIO";
55 	case ATA_PIO0: return "PIO0";
56 	case ATA_PIO1: return "PIO1";
57 	case ATA_PIO2: return "PIO2";
58 	case ATA_PIO3: return "PIO3";
59 	case ATA_PIO4: return "PIO4";
60 	case ATA_WDMA2: return "WDMA2";
61 	case ATA_UDMA2: return "UDMA33";
62 	case ATA_UDMA4: return "UDMA66";
63 	case ATA_UDMA5: return "UDMA100";
64 	case ATA_UDMA6: return "UDMA133";
65 	case ATA_SA150: return "SATA150";
66 	case ATA_SA300: return "SATA300";
67 	case ATA_USB: return "USB";
68 	case ATA_USB1: return "USB1";
69 	case ATA_USB2: return "USB2";
70 	case ATA_DMA: return "BIOSDMA";
71 	default: return "???";
72 	}
73 }
74 
75 int
76 str2mode(char *str)
77 {
78 	if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
79 	if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
80 	if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
81 	if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
82 	if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
83 	if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
84 	if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
85 	if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
86 	if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
87 	if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
88 	if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
89 	if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
90 	if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
91 	if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
92 	if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
93 	if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
94 	return -1;
95 }
96 
97 void
98 usage(void)
99 {
100 	fprintf(stderr,
101 		"usage:  natacontrol <command> args:\n"
102 		"        natacontrol list\n"
103 		"        natacontrol info channel\n"
104 		"        natacontrol attach channel\n"
105 		"        natacontrol detach channel\n"
106 		"        natacontrol reinit channel\n"
107 		"        natacontrol create type [interleave] disk0 ... diskN\n"
108 		"        natacontrol delete array\n"
109 		"        natacontrol addspare array disk\n"
110 		"        natacontrol rebuild array\n"
111 		"        natacontrol status array\n"
112 		"        natacontrol mode device [mode]\n"
113 		"        natacontrol feature device apm apmlevel\n"
114 		"        natacontrol feature device acoustic soundsupplevel\n"
115 		"        natacontrol cap device\n"
116 	);
117 	exit(EX_USAGE);
118 }
119 
120 int
121 version(int ver)
122 {
123 	int bit;
124 
125 	if (ver == 0xffff)
126 		return 0;
127 	for (bit = 15; bit >= 0; bit--)
128 		if (ver & (1<<bit))
129 			return bit;
130 	return 0;
131 }
132 
133 void
134 param_print(struct ata_params *parm)
135 {
136 	printf("<%.40s/%.8s> ", parm->model, parm->revision);
137 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
138 		if (parm->satacapabilities & ATA_SATA_GEN2)
139 			printf("Serial ATA II\n");
140 		else if (parm->satacapabilities & ATA_SATA_GEN1)
141 			printf("Serial ATA v1.0\n");
142 		else
143 			printf("Unknown serial ATA version\n");
144 	}
145 	else
146 		printf("ATA/ATAPI revision %d\n", version(parm->version_major));
147 }
148 
149 void
150 cap_print(struct ata_params *parm)
151 {
152 	u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
153 				((u_int32_t)parm->lba_size_2 << 16);
154 
155 	u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
156 				((u_int64_t)parm->lba_size48_2 << 16) |
157 				((u_int64_t)parm->lba_size48_3 << 32) |
158 				((u_int64_t)parm->lba_size48_4 << 48);
159 
160 	printf("\n");
161 	printf("Protocol              ");
162 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
163 		if (parm->satacapabilities & ATA_SATA_GEN2)
164 			printf("Serial ATA II\n");
165 		else if (parm->satacapabilities & ATA_SATA_GEN1)
166 			printf("Serial ATA v1.0\n");
167 		else
168 			printf("Unknown serial ATA version\n");
169 	}
170 	else
171 		printf("ATA/ATAPI revision %d\n", version(parm->version_major));
172 	printf("device model          %.40s\n", parm->model);
173 	printf("serial number         %.20s\n", parm->serial);
174 	printf("firmware revision     %.8s\n", parm->revision);
175 
176 	printf("cylinders             %d\n", parm->cylinders);
177 	printf("heads                 %d\n", parm->heads);
178 	printf("sectors/track         %d\n", parm->sectors);
179 
180 	printf("lba%ssupported         ",
181 		parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
182 	if (lbasize)
183 		printf("%d sectors\n", lbasize);
184 	else
185 		printf("\n");
186 
187 	printf("lba48%ssupported       ",
188 		parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
189 	if (lbasize48)
190 		printf("%llu sectors\n", (unsigned long long)lbasize48);
191 	else
192 		printf("\n");
193 
194 	printf("dma%ssupported\n",
195 		parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
196 
197 	printf("overlap%ssupported\n",
198 		parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
199 
200 	printf("\nFeature                      "
201 		"Support  Enable    Value           Vendor\n");
202 
203 	printf("write cache                    %s	%s\n",
204 		parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
205 		parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
206 
207 	printf("read ahead                     %s	%s\n",
208 		parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
209 		parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
210 
211 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
212 		printf("Native Command Queuing (NCQ)   %s	%s"
213 			"	%d/0x%02X\n",
214 			parm->satacapabilities & ATA_SUPPORT_NCQ ?
215 				"yes" : "no", " -",
216 			(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
217 				ATA_QUEUE_LEN(parm->queue) : 0,
218 			(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
219 				ATA_QUEUE_LEN(parm->queue) : 0);
220 	}
221 	printf("Tagged Command Queuing (TCQ)   %s	%s	%d/0x%02X\n",
222 		parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
223 		parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
224 		ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
225 
226 	printf("SMART                          %s	%s\n",
227 		parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
228 		parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
229 
230 	printf("microcode download             %s	%s\n",
231 		parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
232 		parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
233 
234 	printf("security                       %s	%s\n",
235 		parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
236 		parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
237 
238 	printf("power management               %s	%s\n",
239 		parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
240 		parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
241 
242 	printf("advanced power management      %s	%s	%d/0x%02X\n",
243 		parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
244 		parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
245 		parm->apm_value, parm->apm_value);
246 
247 	printf("automatic acoustic management  %s	%s	"
248 		"%d/0x%02X	%d/0x%02X\n",
249 		parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
250 		parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
251 		ATA_ACOUSTIC_CURRENT(parm->acoustic),
252 		ATA_ACOUSTIC_CURRENT(parm->acoustic),
253 		ATA_ACOUSTIC_VENDOR(parm->acoustic),
254 		ATA_ACOUSTIC_VENDOR(parm->acoustic));
255 }
256 
257 int
258 ata_cap_print(int fd)
259 {
260 	struct ata_params params;
261 
262 	if (ioctl(fd, IOCATAGPARM, &params) < 0)
263 		return errno;
264 	cap_print(&params);
265 	return 0;
266 }
267 
268 int
269 info_print(int fd, int channel, int prchan)
270 {
271 	struct ata_ioc_devices devices;
272 
273 	devices.channel = channel;
274 
275 	if (ioctl(fd, IOCATADEVICES, &devices) < 0)
276 		return errno;
277 
278 	if (prchan)
279 		printf("ATA channel %d:\n", channel);
280 	printf("%sMaster: ", prchan ? "    " : "");
281 	if (*devices.name[0]) {
282 		printf("%4.4s ", devices.name[0]);
283 		param_print(&devices.params[0]);
284 	}
285 	else
286 		printf("     no device present\n");
287 	printf("%sSlave:  ", prchan ? "    " : "");
288 	if (*devices.name[1]) {
289 		printf("%4.4s ", devices.name[1]);
290 		param_print(&devices.params[1]);
291 	}
292 	else
293 		printf("     no device present\n");
294 	return 0;
295 }
296 
297 int
298 main(int argc, char **argv)
299 {
300 	int fd;
301 
302 	if (argc < 2)
303 		usage();
304 
305 	if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
306 		int disk, mode;
307 		char device[64];
308 
309 		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
310 		      sscanf(argv[2], "acd%d", &disk) == 1 ||
311 		      sscanf(argv[2], "afd%d", &disk) == 1 ||
312 		      sscanf(argv[2], "ast%d", &disk) == 1)) {
313 			fprintf(stderr, "natacontrol: Invalid device %s\n",
314 				argv[2]);
315 			exit(EX_USAGE);
316 		}
317 		sprintf(device, "/dev/%s", argv[2]);
318 		if ((fd = open(device, O_RDONLY)) < 0)
319 			err(1, "device not found");
320 		if (argc == 4) {
321 			mode = str2mode(argv[3]);
322 			if (ioctl(fd, IOCATASMODE, &mode) < 0)
323 				warn("ioctl(IOCATASMODE)");
324 		}
325 		if (argc == 3 || argc == 4) {
326 			if (ioctl(fd, IOCATAGMODE, &mode) < 0)
327 				err(1, "ioctl(IOCATAGMODE)");
328 			printf("current mode = %s\n", mode2str(mode));
329 		}
330 		exit(EX_OK);
331 	}
332 	if (!strcmp(argv[1], "feature") && argc == 5) {
333 		int disk;
334 		char device[64];
335 		struct ata_ioc_request request;
336 
337 		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
338 		      sscanf(argv[2], "acd%d", &disk) == 1 ||
339 		      sscanf(argv[2], "afd%d", &disk) == 1 ||
340 		      sscanf(argv[2], "ast%d", &disk) == 1)) {
341 			fprintf(stderr, "natacontrol: Invalid device %s\n",
342 			    argv[2]);
343 			exit(EX_USAGE);
344 		}
345 		sprintf(device, "/dev/%s", argv[2]);
346 		if ((fd = open(device, O_RDONLY)) < 0)
347 			err(1, "device not found");
348 
349 		bzero(&request, sizeof(struct ata_ioc_request));
350 		request.u.ata.command = ATA_SETFEATURES;
351 		request.flags = ATA_CMD_CONTROL;
352 		request.timeout = 500;
353 		if (!strcmp(argv[3], "apm")) {
354 			if (!strcmp(argv[4], "off")) {
355 				request.u.ata.feature = ATA_SF_DIS_APM;
356 			} else if (!strcmp(argv[4], "maxperf")) {
357 				request.u.ata.feature = ATA_SF_ENAB_APM;
358 				request.u.ata.count = 0xfe;
359 			} else if (!strcmp(argv[4], "minpower")) {
360 				request.u.ata.feature = ATA_SF_ENAB_APM;
361 				request.u.ata.count = 0x01;
362 			} else {
363 				int offset = 0;
364 
365 				request.u.ata.feature = ATA_SF_ENAB_APM;
366 				if (argv[4][0] == 's') {
367 					offset = atoi(&argv[4][1]);
368 					request.u.ata.count = 0x01;
369 				} else {
370 					offset = atoi(&argv[4][1]);
371 					request.u.ata.count = 0x80;
372 				}
373 				if (offset >= 0 && offset <= 127)
374 					request.u.ata.count += offset;
375 			}
376 		} else if (!strcmp(argv[3], "acoustic")) {
377 			if (!strcmp(argv[4], "off")) {
378 				request.u.ata.feature = ATA_SF_DIS_ACCOUS;
379 			} else if (!strcmp(argv[4], "maxperf")) {
380 				request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
381 				request.u.ata.count = 0xfe;
382 			} else if (!strcmp(argv[4], "maxquiet")) {
383 				request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
384 				request.u.ata.count = 0x80;
385 			} else {
386 				request.u.ata.feature = ATA_SF_ENAB_ACCOUS;
387 				request.u.ata.count = atoi(argv[4]);
388 				if (request.u.ata.count > 124)
389 					request.u.ata.count = 124;
390 			}
391 		} else {
392 			usage();
393 		}
394 
395 		if (ioctl(fd, IOCATAREQUEST, &request) < 0)
396 			err(1, "ioctl(IOCATAREQUEST)");
397 
398 		if (request.error != 0) {
399 			fprintf(stderr,
400 			    "IOCATAREQUEST returned err status %d",
401 			    request.error);
402 			exit(EX_IOERR);
403 		}
404 		exit(EX_OK);
405 	}
406 	if (!strcmp(argv[1], "cap") && argc == 3) {
407 		int disk;
408 		char device[64];
409 
410 		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
411 		      sscanf(argv[2], "acd%d", &disk) == 1 ||
412 		      sscanf(argv[2], "afd%d", &disk) == 1 ||
413 		      sscanf(argv[2], "ast%d", &disk) == 1)) {
414 			fprintf(stderr, "natacontrol: Invalid device %s\n",
415 				argv[2]);
416 			exit(EX_USAGE);
417 		}
418 		sprintf(device, "/dev/%s", argv[2]);
419 		if ((fd = open(device, O_RDONLY)) < 0)
420 			err(1, "device not found");
421 		ata_cap_print(fd);
422 		exit(EX_OK);
423 	}
424 
425 	if ((fd = open("/dev/ata", O_RDWR)) < 0)
426 		err(1, "control device not found");
427 
428 	if (!strcmp(argv[1], "list") && argc == 2) {
429 		int maxchannel, channel;
430 
431 		if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
432 			err(1, "ioctl(IOCATAGMAXCHANNEL)");
433 		for (channel = 0; channel < maxchannel; channel++)
434 			info_print(fd, channel, 1);
435 		exit(EX_OK);
436 	}
437 	if (!strcmp(argv[1], "info") && argc == 3) {
438 		int channel;
439 
440 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
441 			fprintf(stderr,
442 				"natacontrol: Invalid channel %s\n", argv[2]);
443                         exit(EX_USAGE);
444 		}
445 		info_print(fd, channel, 0);
446 		exit(EX_OK);
447 	}
448 	if (!strcmp(argv[1], "detach") && argc == 3) {
449 		int channel;
450 
451 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
452 			fprintf(stderr,
453 				"natacontrol: Invalid channel %s\n", argv[2]);
454                         exit(EX_USAGE);
455 		}
456 		if (ioctl(fd, IOCATADETACH, &channel) < 0)
457 			err(1, "ioctl(IOCATADETACH)");
458 		exit(EX_OK);
459 	}
460 	if (!strcmp(argv[1], "attach") && argc == 3) {
461 		int channel;
462 
463 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
464 			fprintf(stderr,
465 				"natacontrol: Invalid channel %s\n", argv[2]);
466                         exit(EX_USAGE);
467 		}
468 		if (ioctl(fd, IOCATAATTACH, &channel) < 0)
469 			err(1, "ioctl(IOCATAATTACH)");
470 		info_print(fd, channel, 0);
471 		exit(EX_OK);
472 	}
473 	if (!strcmp(argv[1], "reinit") && argc == 3) {
474 		int channel;
475 
476 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
477 			fprintf(stderr,
478 				"natacontrol: Invalid channel %s\n", argv[2]);
479                         exit(EX_USAGE);
480 		}
481 		if (ioctl(fd, IOCATAREINIT, &channel) < 0)
482 			warn("ioctl(IOCATAREINIT)");
483 		info_print(fd, channel, 0);
484 		exit(EX_OK);
485 	}
486 	if (!strcmp(argv[1], "create")) {
487 		int disk, dev, offset;
488 		struct ata_ioc_raid_config config;
489 
490 		bzero(&config, sizeof(config));
491 		if (argc > 2) {
492 			if (!strcasecmp(argv[2], "RAID0") ||
493 			    !strcasecmp(argv[2], "stripe"))
494 				config.type = AR_RAID0;
495 			if (!strcasecmp(argv[2], "RAID1") ||
496 			    !strcasecmp(argv[2],"mirror"))
497 				config.type = AR_RAID1;
498 			if (!strcasecmp(argv[2], "RAID0+1") ||
499 			    !strcasecmp(argv[2],"RAID10"))
500 				config.type = AR_RAID01;
501 			if (!strcasecmp(argv[2], "RAID5"))
502 				config.type = AR_RAID5;
503 			if (!strcasecmp(argv[2], "SPAN"))
504 				config.type = AR_SPAN;
505 			if (!strcasecmp(argv[2], "JBOD"))
506 				config.type = AR_JBOD;
507 		}
508 		if (!config.type) {
509 			fprintf(stderr, "natacontrol: Invalid RAID type %s\n",
510 				argv[2]);
511 			fprintf(stderr, "natacontrol: Valid RAID types: \n");
512 			fprintf(stderr, "             stripe | mirror | "
513 					"RAID0 | RAID1 | RAID0+1 | RAID5 | "
514 					"SPAN | JBOD\n");
515 			exit(EX_USAGE);
516 		}
517 
518 		if (config.type == AR_RAID0 ||
519 		    config.type == AR_RAID01 ||
520 		    config.type == AR_RAID5) {
521 			if (argc < 4 ||
522 			    sscanf(argv[3], "%d", &config.interleave) != 1) {
523 				fprintf(stderr,
524 					"natacontrol: Invalid interleave %s\n",
525 					argv[3]);
526 				exit(EX_USAGE);
527 			}
528 			offset = 4;
529 		}
530 		else
531 			offset = 3;
532 
533 		for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
534 			if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
535 				fprintf(stderr,
536 					"natacontrol: Invalid disk %s\n",
537 					argv[offset + disk]);
538 				exit(EX_USAGE);
539 			}
540 			config.disks[disk] = dev;
541 		}
542 
543 		if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
544 		    disk < 2) {
545 			fprintf(stderr, "natacontrol: At least 2 disks must be "
546 				"specified\n");
547 			exit(EX_USAGE);
548 		}
549 
550 		config.total_disks = disk;
551 		if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
552 			err(1, "ioctl(IOCATARAIDCREATE)");
553 		else
554 			printf("ar%d created\n", config.lun);
555 		exit(EX_OK);
556 	}
557 	if (!strcmp(argv[1], "delete") && argc == 3) {
558 		int array;
559 
560 		if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
561 			fprintf(stderr,
562 				"natacontrol: Invalid array %s\n", argv[2]);
563                         exit(EX_USAGE);
564 		}
565 		if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
566 			warn("ioctl(IOCATARAIDDELETE)");
567 		exit(EX_OK);
568 	}
569 	if (!strcmp(argv[1], "addspare") && argc == 4) {
570 		struct ata_ioc_raid_config config;
571 
572 		if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
573 			fprintf(stderr,
574 				"natacontrol: Invalid array %s\n", argv[2]);
575 			usage();
576 		}
577 		if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
578 			fprintf(stderr,
579 				"natacontrol: Invalid disk %s\n", argv[3]);
580 			usage();
581 		}
582 		if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
583 			warn("ioctl(IOCATARAIDADDSPARE)");
584 		exit(EX_OK);
585 	}
586 	if (!strcmp(argv[1], "rebuild") && argc == 3) {
587 		int array;
588 
589 		if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
590 			fprintf(stderr,
591 				"natacontrol: Invalid array %s\n", argv[2]);
592 			usage();
593 		}
594 		if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
595 			warn("ioctl(IOCATARAIDREBUILD)");
596 		else {
597 			char device[64];
598 			char *buffer;
599 			ssize_t len;
600 			int arfd;
601 
602 			if (daemon(0, 1) == -1)
603 				err(1, "daemon");
604 			nice(20);
605 			snprintf(device, sizeof(device), "/dev/ar%d",
606 			    array);
607 			if ((arfd = open(device, O_RDONLY)) == -1)
608 				err(1, "open %s", device);
609 			if ((buffer = malloc(1024 * 1024)) == NULL)
610 				err(1, "malloc");
611 			while ((len = read(arfd, buffer, 1024 * 1024)) > 0)
612 				;
613 			if (len == -1)
614 				err(1, "read");
615 			else
616 				fprintf(stderr,
617 				    "natacontrol: ar%d rebuild completed\n",
618 				    array);
619 			free(buffer);
620 			close(arfd);
621 		}
622 		exit(EX_OK);
623 	}
624 	if (!strcmp(argv[1], "status") && argc == 3) {
625 		struct ata_ioc_raid_config config;
626 		int i;
627 
628 		if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
629 			fprintf(stderr,
630 				"natacontrol: Invalid array %s\n", argv[2]);
631 			usage();
632 		}
633 		if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0)
634 			err(1, "ioctl(IOCATARAIDSTATUS)");
635 
636 		printf("ar%d: ATA ", config.lun);
637 		switch (config.type) {
638 		case AR_RAID0:
639 			printf("RAID0 stripesize=%d", config.interleave);
640 			break;
641 		case AR_RAID1:
642 			printf("RAID1");
643 			break;
644 		case AR_RAID01:
645 			printf("RAID0+1 stripesize=%d", config.interleave);
646 			break;
647 		case AR_RAID5:
648 			printf("RAID5 stripesize=%d", config.interleave);
649 			break;
650 		case AR_JBOD:
651 			printf("JBOD");
652 		case AR_SPAN:
653 			printf("SPAN");
654 			break;
655 		}
656 		printf(" subdisks: ");
657 		for (i = 0; i < config.total_disks; i++) {
658 			if (config.disks[i] >= 0)
659 				printf("ad%d ", config.disks[i]);
660 			else
661 				printf("DOWN ");
662 		}
663 		printf("status: ");
664 		switch (config.status) {
665 		case AR_READY:
666 			printf("READY\n");
667 			break;
668 		case AR_READY | AR_DEGRADED:
669 			printf("DEGRADED\n");
670 			break;
671 		case AR_READY | AR_DEGRADED | AR_REBUILDING:
672 			printf("REBUILDING %d%% completed\n",
673 				config.progress);
674 			break;
675 		default:
676 			printf("BROKEN\n");
677 		}
678 		exit(EX_OK);
679 	}
680 	usage();
681 	exit(EX_OK);
682 }
683