xref: /dragonfly/sbin/natacontrol/natacontrol.c (revision 956939d5)
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  * $DragonFly: src/sbin/natacontrol/natacontrol.c,v 1.3 2008/09/04 21:00:28 swildner Exp $
28  */
29 
30 #include <sys/nata.h>
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <err.h>
38 
39 #include <sysexits.h>
40 #include <unistd.h>
41 
42 static const char *mode2str(int mode);
43 static int	str2mode(char *str);
44 static void	usage(void);
45 static int	version(int ver);
46 static void	param_print(struct ata_params *parm);
47 static void	cap_print(struct ata_params *parm);
48 static int	ata_cap_print(int fd);
49 static int	info_print(int fd, int channel, int prchan);
50 
51 const char *
52 mode2str(int mode)
53 {
54 	switch (mode) {
55 	case ATA_PIO: return "BIOSPIO";
56 	case ATA_PIO0: return "PIO0";
57 	case ATA_PIO1: return "PIO1";
58 	case ATA_PIO2: return "PIO2";
59 	case ATA_PIO3: return "PIO3";
60 	case ATA_PIO4: return "PIO4";
61 	case ATA_WDMA2: return "WDMA2";
62 	case ATA_UDMA2: return "UDMA33";
63 	case ATA_UDMA4: return "UDMA66";
64 	case ATA_UDMA5: return "UDMA100";
65 	case ATA_UDMA6: return "UDMA133";
66 	case ATA_SA150: return "SATA150";
67 	case ATA_SA300: return "SATA300";
68 	case ATA_USB: return "USB";
69 	case ATA_USB1: return "USB1";
70 	case ATA_USB2: return "USB2";
71 	case ATA_DMA: return "BIOSDMA";
72 	default: return "???";
73 	}
74 }
75 
76 int
77 str2mode(char *str)
78 {
79 	if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
80 	if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
81 	if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
82 	if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
83 	if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
84 	if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
85 	if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
86 	if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
87 	if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
88 	if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
89 	if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
90 	if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
91 	if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
92 	if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
93 	if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
94 	if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
95 	return -1;
96 }
97 
98 void
99 usage(void)
100 {
101 	fprintf(stderr,
102 		"usage:  natacontrol <command> args:\n"
103 		"        natacontrol list\n"
104 		"        natacontrol info channel\n"
105 		"        natacontrol attach channel\n"
106 		"        natacontrol detach channel\n"
107 		"        natacontrol reinit channel\n"
108 		"        natacontrol create type [interleave] disk0 ... diskN\n"
109 		"        natacontrol delete array\n"
110 		"        natacontrol addspare array disk\n"
111 		"        natacontrol rebuild array\n"
112 		"        natacontrol status array\n"
113 		"        natacontrol mode device [mode]\n"
114 		"        natacontrol cap device\n"
115 	);
116 	exit(EX_USAGE);
117 }
118 
119 int
120 version(int ver)
121 {
122 	int bit;
123 
124 	if (ver == 0xffff)
125 		return 0;
126 	for (bit = 15; bit >= 0; bit--)
127 		if (ver & (1<<bit))
128 			return bit;
129 	return 0;
130 }
131 
132 void
133 param_print(struct ata_params *parm)
134 {
135 	printf("<%.40s/%.8s> ", parm->model, parm->revision);
136 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
137 		if (parm->satacapabilities & ATA_SATA_GEN2)
138 			printf("Serial ATA II\n");
139 		else if (parm->satacapabilities & ATA_SATA_GEN1)
140 			printf("Serial ATA v1.0\n");
141 		else
142 			printf("Unknown serial ATA version\n");
143 	}
144 	else
145 		printf("ATA/ATAPI revision %d\n", version(parm->version_major));
146 }
147 
148 void
149 cap_print(struct ata_params *parm)
150 {
151 	u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
152 				((u_int32_t)parm->lba_size_2 << 16);
153 
154 	u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
155 				((u_int64_t)parm->lba_size48_2 << 16) |
156 				((u_int64_t)parm->lba_size48_3 << 32) |
157 				((u_int64_t)parm->lba_size48_4 << 48);
158 
159 	printf("\n");
160 	printf("Protocol              ");
161 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
162 		if (parm->satacapabilities & ATA_SATA_GEN2)
163 			printf("Serial ATA II\n");
164 		else if (parm->satacapabilities & ATA_SATA_GEN1)
165 			printf("Serial ATA v1.0\n");
166 		else
167 			printf("Unknown serial ATA version\n");
168 	}
169 	else
170 		printf("ATA/ATAPI revision %d\n", version(parm->version_major));
171 	printf("device model          %.40s\n", parm->model);
172 	printf("serial number         %.20s\n", parm->serial);
173 	printf("firmware revision     %.8s\n", parm->revision);
174 
175 	printf("cylinders             %d\n", parm->cylinders);
176 	printf("heads                 %d\n", parm->heads);
177 	printf("sectors/track         %d\n", parm->sectors);
178 
179 	printf("lba%ssupported         ",
180 		parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
181 	if (lbasize)
182 		printf("%d sectors\n", lbasize);
183 	else
184 		printf("\n");
185 
186 	printf("lba48%ssupported       ",
187 		parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
188 	if (lbasize48)
189 		printf("%llu sectors\n", (unsigned long long)lbasize48);
190 	else
191 		printf("\n");
192 
193 	printf("dma%ssupported\n",
194 		parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
195 
196 	printf("overlap%ssupported\n",
197 		parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
198 
199 	printf("\nFeature                      "
200 		"Support  Enable    Value           Vendor\n");
201 
202 	printf("write cache                    %s	%s\n",
203 		parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
204 		parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
205 
206 	printf("read ahead                     %s	%s\n",
207 		parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
208 		parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
209 
210 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
211 		printf("Native Command Queuing (NCQ)   %s	%s"
212 			"	%d/0x%02X\n",
213 			parm->satacapabilities & ATA_SUPPORT_NCQ ?
214 				"yes" : "no", " -",
215 			(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
216 				ATA_QUEUE_LEN(parm->queue) : 0,
217 			(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
218 				ATA_QUEUE_LEN(parm->queue) : 0);
219 	}
220 	printf("Tagged Command Queuing (TCQ)   %s	%s	%d/0x%02X\n",
221 		parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
222 		parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
223 		ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
224 
225 	printf("SMART                          %s	%s\n",
226 		parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
227 		parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
228 
229 	printf("microcode download             %s	%s\n",
230 		parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
231 		parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
232 
233 	printf("security                       %s	%s\n",
234 		parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
235 		parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
236 
237 	printf("power management               %s	%s\n",
238 		parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
239 		parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
240 
241 	printf("advanced power management      %s	%s	%d/0x%02X\n",
242 		parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
243 		parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
244 		parm->apm_value, parm->apm_value);
245 
246 	printf("automatic acoustic management  %s	%s	"
247 		"%d/0x%02X	%d/0x%02X\n",
248 		parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
249 		parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
250 		ATA_ACOUSTIC_CURRENT(parm->acoustic),
251 		ATA_ACOUSTIC_CURRENT(parm->acoustic),
252 		ATA_ACOUSTIC_VENDOR(parm->acoustic),
253 		ATA_ACOUSTIC_VENDOR(parm->acoustic));
254 }
255 
256 int
257 ata_cap_print(int fd)
258 {
259 	struct ata_params params;
260 
261 	if (ioctl(fd, IOCATAGPARM, &params) < 0)
262 		return errno;
263 	cap_print(&params);
264 	return 0;
265 }
266 
267 int
268 info_print(int fd, int channel, int prchan)
269 {
270 	struct ata_ioc_devices devices;
271 
272 	devices.channel = channel;
273 
274 	if (ioctl(fd, IOCATADEVICES, &devices) < 0)
275 		return errno;
276 
277 	if (prchan)
278 		printf("ATA channel %d:\n", channel);
279 	printf("%sMaster: ", prchan ? "    " : "");
280 	if (*devices.name[0]) {
281 		printf("%4.4s ", devices.name[0]);
282 		param_print(&devices.params[0]);
283 	}
284 	else
285 		printf("     no device present\n");
286 	printf("%sSlave:  ", prchan ? "    " : "");
287 	if (*devices.name[1]) {
288 		printf("%4.4s ", devices.name[1]);
289 		param_print(&devices.params[1]);
290 	}
291 	else
292 		printf("     no device present\n");
293 	return 0;
294 }
295 
296 int
297 main(int argc, char **argv)
298 {
299 	int fd;
300 
301 	if (argc < 2)
302 		usage();
303 
304 	if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
305 		int disk, mode;
306 		char device[64];
307 
308 		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
309 		      sscanf(argv[2], "acd%d", &disk) == 1 ||
310 		      sscanf(argv[2], "afd%d", &disk) == 1 ||
311 		      sscanf(argv[2], "ast%d", &disk) == 1)) {
312 			fprintf(stderr, "natacontrol: Invalid device %s\n",
313 				argv[2]);
314 			exit(EX_USAGE);
315 		}
316 		sprintf(device, "/dev/%s", argv[2]);
317 		if ((fd = open(device, O_RDONLY)) < 0)
318 			err(1, "device not found");
319 		if (argc == 4) {
320 			mode = str2mode(argv[3]);
321 			if (ioctl(fd, IOCATASMODE, &mode) < 0)
322 				warn("ioctl(IOCATASMODE)");
323 		}
324 		if (argc == 3 || argc == 4) {
325 			if (ioctl(fd, IOCATAGMODE, &mode) < 0)
326 				err(1, "ioctl(IOCATAGMODE)");
327 			printf("current mode = %s\n", mode2str(mode));
328 		}
329 		exit(EX_OK);
330 	}
331 	if (!strcmp(argv[1], "cap") && argc == 3) {
332 		int disk;
333 		char device[64];
334 
335 		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
336 		      sscanf(argv[2], "acd%d", &disk) == 1 ||
337 		      sscanf(argv[2], "afd%d", &disk) == 1 ||
338 		      sscanf(argv[2], "ast%d", &disk) == 1)) {
339 			fprintf(stderr, "natacontrol: Invalid device %s\n",
340 				argv[2]);
341 			exit(EX_USAGE);
342 		}
343 		sprintf(device, "/dev/%s", argv[2]);
344 		if ((fd = open(device, O_RDONLY)) < 0)
345 			err(1, "device not found");
346 		ata_cap_print(fd);
347 		exit(EX_OK);
348 	}
349 
350 	if ((fd = open("/dev/ata", O_RDWR)) < 0)
351 		err(1, "control device not found");
352 
353 	if (!strcmp(argv[1], "list") && argc == 2) {
354 		int maxchannel, channel;
355 
356 		if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
357 			err(1, "ioctl(IOCATAGMAXCHANNEL)");
358 		for (channel = 0; channel < maxchannel; channel++)
359 			info_print(fd, channel, 1);
360 		exit(EX_OK);
361 	}
362 	if (!strcmp(argv[1], "info") && argc == 3) {
363 		int channel;
364 
365 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
366 			fprintf(stderr,
367 				"natacontrol: Invalid channel %s\n", argv[2]);
368                         exit(EX_USAGE);
369 		}
370 		info_print(fd, channel, 0);
371 		exit(EX_OK);
372 	}
373 	if (!strcmp(argv[1], "detach") && argc == 3) {
374 		int channel;
375 
376 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
377 			fprintf(stderr,
378 				"natacontrol: Invalid channel %s\n", argv[2]);
379                         exit(EX_USAGE);
380 		}
381 		if (ioctl(fd, IOCATADETACH, &channel) < 0)
382 			err(1, "ioctl(IOCATADETACH)");
383 		exit(EX_OK);
384 	}
385 	if (!strcmp(argv[1], "attach") && argc == 3) {
386 		int channel;
387 
388 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
389 			fprintf(stderr,
390 				"natacontrol: Invalid channel %s\n", argv[2]);
391                         exit(EX_USAGE);
392 		}
393 		if (ioctl(fd, IOCATAATTACH, &channel) < 0)
394 			err(1, "ioctl(IOCATAATTACH)");
395 		info_print(fd, channel, 0);
396 		exit(EX_OK);
397 	}
398 	if (!strcmp(argv[1], "reinit") && argc == 3) {
399 		int channel;
400 
401 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
402 			fprintf(stderr,
403 				"natacontrol: Invalid channel %s\n", argv[2]);
404                         exit(EX_USAGE);
405 		}
406 		if (ioctl(fd, IOCATAREINIT, &channel) < 0)
407 			warn("ioctl(IOCATAREINIT)");
408 		info_print(fd, channel, 0);
409 		exit(EX_OK);
410 	}
411 	if (!strcmp(argv[1], "create")) {
412 		int disk, dev, offset;
413 		struct ata_ioc_raid_config config;
414 
415 		bzero(&config, sizeof(config));
416 		if (argc > 2) {
417 			if (!strcasecmp(argv[2], "RAID0") ||
418 			    !strcasecmp(argv[2], "stripe"))
419 				config.type = AR_RAID0;
420 			if (!strcasecmp(argv[2], "RAID1") ||
421 			    !strcasecmp(argv[2],"mirror"))
422 				config.type = AR_RAID1;
423 			if (!strcasecmp(argv[2], "RAID0+1") ||
424 			    !strcasecmp(argv[2],"RAID10"))
425 				config.type = AR_RAID01;
426 			if (!strcasecmp(argv[2], "RAID5"))
427 				config.type = AR_RAID5;
428 			if (!strcasecmp(argv[2], "SPAN"))
429 				config.type = AR_SPAN;
430 			if (!strcasecmp(argv[2], "JBOD"))
431 				config.type = AR_JBOD;
432 		}
433 		if (!config.type) {
434 			fprintf(stderr, "natacontrol: Invalid RAID type %s\n",
435 				argv[2]);
436 			fprintf(stderr, "natacontrol: Valid RAID types: \n");
437 			fprintf(stderr, "             stripe | mirror | "
438 					"RAID0 | RAID1 | RAID0+1 | RAID5 | "
439 					"SPAN | JBOD\n");
440 			exit(EX_USAGE);
441 		}
442 
443 		if (config.type == AR_RAID0 ||
444 		    config.type == AR_RAID01 ||
445 		    config.type == AR_RAID5) {
446 			if (argc < 4 ||
447 			    !sscanf(argv[3], "%d", &config.interleave) == 1) {
448 				fprintf(stderr,
449 					"natacontrol: Invalid interleave %s\n",
450 					argv[3]);
451 				exit(EX_USAGE);
452 			}
453 			offset = 4;
454 		}
455 		else
456 			offset = 3;
457 
458 		for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
459 			if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
460 				fprintf(stderr,
461 					"natacontrol: Invalid disk %s\n",
462 					argv[offset + disk]);
463 				exit(EX_USAGE);
464 			}
465 			config.disks[disk] = dev;
466 		}
467 
468 		if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
469 		    disk < 2) {
470 			fprintf(stderr, "natacontrol: At least 2 disks must be "
471 				"specified\n");
472 			exit(EX_USAGE);
473 		}
474 
475 		config.total_disks = disk;
476 		if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
477 			err(1, "ioctl(IOCATARAIDCREATE)");
478 		else
479 			printf("ar%d created\n", config.lun);
480 		exit(EX_OK);
481 	}
482 	if (!strcmp(argv[1], "delete") && argc == 3) {
483 		int array;
484 
485 		if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
486 			fprintf(stderr,
487 				"natacontrol: Invalid array %s\n", argv[2]);
488                         exit(EX_USAGE);
489 		}
490 		if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
491 			warn("ioctl(IOCATARAIDDELETE)");
492 		exit(EX_OK);
493 	}
494 	if (!strcmp(argv[1], "addspare") && argc == 4) {
495 		struct ata_ioc_raid_config config;
496 
497 		if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
498 			fprintf(stderr,
499 				"natacontrol: Invalid array %s\n", argv[2]);
500 			usage();
501 		}
502 		if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
503 			fprintf(stderr,
504 				"natacontrol: Invalid disk %s\n", argv[3]);
505 			usage();
506 		}
507 		if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
508 			warn("ioctl(IOCATARAIDADDSPARE)");
509 		exit(EX_OK);
510 	}
511 	if (!strcmp(argv[1], "rebuild") && argc == 3) {
512 		int array;
513 
514 		if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
515 			fprintf(stderr,
516 				"natacontrol: Invalid array %s\n", argv[2]);
517 			usage();
518 		}
519 		if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
520 			warn("ioctl(IOCATARAIDREBUILD)");
521 		else {
522 			char device[64];
523 			char *buffer;
524 			ssize_t len;
525 			int arfd;
526 
527 			if (daemon(0, 1) == -1)
528 				err(1, "daemon");
529 			nice(20);
530 			snprintf(device, sizeof(device), "/dev/ar%d",
531 			    array);
532 			if ((arfd = open(device, O_RDONLY)) == -1)
533 				err(1, "open %s", device);
534 			if ((buffer = malloc(1024 * 1024)) == NULL)
535 				err(1, "malloc");
536 			while ((len = read(arfd, buffer, 1024 * 1024)) > 0)
537 				;
538 			if (len == -1)
539 				err(1, "read");
540 			else
541 				fprintf(stderr,
542 				    "atacontrol: ar%d rebuild completed\n",
543 				    array);
544 			free(buffer);
545 			close(arfd);
546 		}
547 		exit(EX_OK);
548 	}
549 	if (!strcmp(argv[1], "status") && argc == 3) {
550 		struct ata_ioc_raid_config config;
551 		int i;
552 
553 		if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
554 			fprintf(stderr,
555 				"natacontrol: Invalid array %s\n", argv[2]);
556 			usage();
557 		}
558 		if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0)
559 			err(1, "ioctl(IOCATARAIDSTATUS)");
560 
561 		printf("ar%d: ATA ", config.lun);
562 		switch (config.type) {
563 		case AR_RAID0:
564 			printf("RAID0 stripesize=%d", config.interleave);
565 			break;
566 		case AR_RAID1:
567 			printf("RAID1");
568 			break;
569 		case AR_RAID01:
570 			printf("RAID0+1 stripesize=%d", config.interleave);
571 			break;
572 		case AR_RAID5:
573 			printf("RAID5 stripesize=%d", config.interleave);
574 			break;
575 		case AR_JBOD:
576 			printf("JBOD");
577 		case AR_SPAN:
578 			printf("SPAN");
579 			break;
580 		}
581 		printf(" subdisks: ");
582 		for (i = 0; i < config.total_disks; i++) {
583 			if (config.disks[i] >= 0)
584 				printf("ad%d ", config.disks[i]);
585 			else
586 				printf("DOWN ");
587 		}
588 		printf("status: ");
589 		switch (config.status) {
590 		case AR_READY:
591 			printf("READY\n");
592 			break;
593 		case AR_READY | AR_DEGRADED:
594 			printf("DEGRADED\n");
595 			break;
596 		case AR_READY | AR_DEGRADED | AR_REBUILDING:
597 			printf("REBUILDING %d%% completed\n",
598 				config.progress);
599 			break;
600 		default:
601 			printf("BROKEN\n");
602 		}
603 		exit(EX_OK);
604 	}
605 	usage();
606 	exit(EX_OK);
607 }
608