xref: /dragonfly/sbin/natacontrol/natacontrol.c (revision 7bc7e232)
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.2 2007/08/01 22:54:00 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 
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()
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 cap device\n"
114 	);
115 	exit(EX_USAGE);
116 }
117 
118 int
119 version(int ver)
120 {
121 	int bit;
122 
123 	if (ver == 0xffff)
124 		return 0;
125 	for (bit = 15; bit >= 0; bit--)
126 		if (ver & (1<<bit))
127 			return bit;
128 	return 0;
129 }
130 
131 void
132 param_print(struct ata_params *parm)
133 {
134 	printf("<%.40s/%.8s> ", parm->model, parm->revision);
135 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
136 		if (parm->satacapabilities & ATA_SATA_GEN2)
137 			printf("Serial ATA II\n");
138 		else if (parm->satacapabilities & ATA_SATA_GEN1)
139 			printf("Serial ATA v1.0\n");
140 		else
141 			printf("Unknown serial ATA version\n");
142 	}
143 	else
144 		printf("ATA/ATAPI revision %d\n", version(parm->version_major));
145 }
146 
147 void
148 cap_print(struct ata_params *parm)
149 {
150 	u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
151 				((u_int32_t)parm->lba_size_2 << 16);
152 
153 	u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
154 				((u_int64_t)parm->lba_size48_2 << 16) |
155 				((u_int64_t)parm->lba_size48_3 << 32) |
156 				((u_int64_t)parm->lba_size48_4 << 48);
157 
158 	printf("\n");
159 	printf("Protocol              ");
160 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
161 		if (parm->satacapabilities & ATA_SATA_GEN2)
162 			printf("Serial ATA II\n");
163 		else if (parm->satacapabilities & ATA_SATA_GEN1)
164 			printf("Serial ATA v1.0\n");
165 		else
166 			printf("Unknown serial ATA version\n");
167 	}
168 	else
169 		printf("ATA/ATAPI revision %d\n", version(parm->version_major));
170 	printf("device model          %.40s\n", parm->model);
171 	printf("serial number         %.20s\n", parm->serial);
172 	printf("firmware revision     %.8s\n", parm->revision);
173 
174 	printf("cylinders             %d\n", parm->cylinders);
175 	printf("heads                 %d\n", parm->heads);
176 	printf("sectors/track         %d\n", parm->sectors);
177 
178 	printf("lba%ssupported         ",
179 		parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
180 	if (lbasize)
181 		printf("%d sectors\n", lbasize);
182 	else
183 		printf("\n");
184 
185 	printf("lba48%ssupported       ",
186 		parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
187 	if (lbasize48)
188 		printf("%llu sectors\n", (unsigned long long)lbasize48);
189 	else
190 		printf("\n");
191 
192 	printf("dma%ssupported\n",
193 		parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
194 
195 	printf("overlap%ssupported\n",
196 		parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
197 
198 	printf("\nFeature                      "
199 		"Support  Enable    Value           Vendor\n");
200 
201 	printf("write cache                    %s	%s\n",
202 		parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
203 		parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
204 
205 	printf("read ahead                     %s	%s\n",
206 		parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
207 		parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
208 
209 	if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
210 		printf("Native Command Queuing (NCQ)   %s	%s"
211 			"	%d/0x%02X\n",
212 			parm->satacapabilities & ATA_SUPPORT_NCQ ?
213 				"yes" : "no", " -",
214 			(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
215 				ATA_QUEUE_LEN(parm->queue) : 0,
216 			(parm->satacapabilities & ATA_SUPPORT_NCQ) ?
217 				ATA_QUEUE_LEN(parm->queue) : 0);
218 	}
219 	printf("Tagged Command Queuing (TCQ)   %s	%s	%d/0x%02X\n",
220 		parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
221 		parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
222 		ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
223 
224 	printf("SMART                          %s	%s\n",
225 		parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
226 		parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
227 
228 	printf("microcode download             %s	%s\n",
229 		parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
230 		parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
231 
232 	printf("security                       %s	%s\n",
233 		parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
234 		parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
235 
236 	printf("power management               %s	%s\n",
237 		parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
238 		parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
239 
240 	printf("advanced power management      %s	%s	%d/0x%02X\n",
241 		parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
242 		parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
243 		parm->apm_value, parm->apm_value);
244 
245 	printf("automatic acoustic management  %s	%s	"
246 		"%d/0x%02X	%d/0x%02X\n",
247 		parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
248 		parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
249 		ATA_ACOUSTIC_CURRENT(parm->acoustic),
250 		ATA_ACOUSTIC_CURRENT(parm->acoustic),
251 		ATA_ACOUSTIC_VENDOR(parm->acoustic),
252 		ATA_ACOUSTIC_VENDOR(parm->acoustic));
253 }
254 
255 int
256 ata_cap_print(int fd)
257 {
258 	struct ata_params params;
259 
260 	if (ioctl(fd, IOCATAGPARM, &params) < 0)
261 		return errno;
262 	cap_print(&params);
263 	return 0;
264 }
265 
266 int
267 info_print(int fd, int channel, int prchan)
268 {
269 	struct ata_ioc_devices devices;
270 
271 	devices.channel = channel;
272 
273 	if (ioctl(fd, IOCATADEVICES, &devices) < 0)
274 		return errno;
275 
276 	if (prchan)
277 		printf("ATA channel %d:\n", channel);
278 	printf("%sMaster: ", prchan ? "    " : "");
279 	if (*devices.name[0]) {
280 		printf("%4.4s ", devices.name[0]);
281 		param_print(&devices.params[0]);
282 	}
283 	else
284 		printf("     no device present\n");
285 	printf("%sSlave:  ", prchan ? "    " : "");
286 	if (*devices.name[1]) {
287 		printf("%4.4s ", devices.name[1]);
288 		param_print(&devices.params[1]);
289 	}
290 	else
291 		printf("     no device present\n");
292 	return 0;
293 }
294 
295 int
296 main(int argc, char **argv)
297 {
298 	int fd;
299 
300 	if (argc < 2)
301 		usage();
302 
303 	if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
304 		int disk, mode;
305 		char device[64];
306 
307 		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
308 		      sscanf(argv[2], "acd%d", &disk) == 1 ||
309 		      sscanf(argv[2], "afd%d", &disk) == 1 ||
310 		      sscanf(argv[2], "ast%d", &disk) == 1)) {
311 			fprintf(stderr, "natacontrol: Invalid device %s\n",
312 				argv[2]);
313 			exit(EX_USAGE);
314 		}
315 		sprintf(device, "/dev/%s", argv[2]);
316 		if ((fd = open(device, O_RDONLY)) < 0)
317 			err(1, "device not found");
318 		if (argc == 4) {
319 			mode = str2mode(argv[3]);
320 			if (ioctl(fd, IOCATASMODE, &mode) < 0)
321 				warn("ioctl(IOCATASMODE)");
322 		}
323 		if (argc == 3 || argc == 4) {
324 			if (ioctl(fd, IOCATAGMODE, &mode) < 0)
325 				err(1, "ioctl(IOCATAGMODE)");
326 			printf("current mode = %s\n", mode2str(mode));
327 		}
328 		exit(EX_OK);
329 	}
330 	if (!strcmp(argv[1], "cap") && argc == 3) {
331 		int disk;
332 		char device[64];
333 
334 		if (!(sscanf(argv[2], "ad%d", &disk) == 1 ||
335 		      sscanf(argv[2], "acd%d", &disk) == 1 ||
336 		      sscanf(argv[2], "afd%d", &disk) == 1 ||
337 		      sscanf(argv[2], "ast%d", &disk) == 1)) {
338 			fprintf(stderr, "natacontrol: Invalid device %s\n",
339 				argv[2]);
340 			exit(EX_USAGE);
341 		}
342 		sprintf(device, "/dev/%s", argv[2]);
343 		if ((fd = open(device, O_RDONLY)) < 0)
344 			err(1, "device not found");
345 		ata_cap_print(fd);
346 		exit(EX_OK);
347 	}
348 
349 	if ((fd = open("/dev/ata", O_RDWR)) < 0)
350 		err(1, "control device not found");
351 
352 	if (!strcmp(argv[1], "list") && argc == 2) {
353 		int maxchannel, channel;
354 
355 		if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
356 			err(1, "ioctl(IOCATAGMAXCHANNEL)");
357 		for (channel = 0; channel < maxchannel; channel++)
358 			info_print(fd, channel, 1);
359 		exit(EX_OK);
360 	}
361 	if (!strcmp(argv[1], "info") && argc == 3) {
362 		int channel;
363 
364 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
365 			fprintf(stderr,
366 				"natacontrol: Invalid channel %s\n", argv[2]);
367                         exit(EX_USAGE);
368 		}
369 		info_print(fd, channel, 0);
370 		exit(EX_OK);
371 	}
372 	if (!strcmp(argv[1], "detach") && argc == 3) {
373 		int channel;
374 
375 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
376 			fprintf(stderr,
377 				"natacontrol: Invalid channel %s\n", argv[2]);
378                         exit(EX_USAGE);
379 		}
380 		if (ioctl(fd, IOCATADETACH, &channel) < 0)
381 			err(1, "ioctl(IOCATADETACH)");
382 		exit(EX_OK);
383 	}
384 	if (!strcmp(argv[1], "attach") && argc == 3) {
385 		int channel;
386 
387 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
388 			fprintf(stderr,
389 				"natacontrol: Invalid channel %s\n", argv[2]);
390                         exit(EX_USAGE);
391 		}
392 		if (ioctl(fd, IOCATAATTACH, &channel) < 0)
393 			err(1, "ioctl(IOCATAATTACH)");
394 		info_print(fd, channel, 0);
395 		exit(EX_OK);
396 	}
397 	if (!strcmp(argv[1], "reinit") && argc == 3) {
398 		int channel;
399 
400 		if (!(sscanf(argv[2], "ata%d", &channel) == 1)) {
401 			fprintf(stderr,
402 				"natacontrol: Invalid channel %s\n", argv[2]);
403                         exit(EX_USAGE);
404 		}
405 		if (ioctl(fd, IOCATAREINIT, &channel) < 0)
406 			warn("ioctl(IOCATAREINIT)");
407 		info_print(fd, channel, 0);
408 		exit(EX_OK);
409 	}
410 	if (!strcmp(argv[1], "create")) {
411 		int disk, dev, offset;
412 		struct ata_ioc_raid_config config;
413 
414 		bzero(&config, sizeof(config));
415 		if (argc > 2) {
416 			if (!strcasecmp(argv[2], "RAID0") ||
417 			    !strcasecmp(argv[2], "stripe"))
418 				config.type = AR_RAID0;
419 			if (!strcasecmp(argv[2], "RAID1") ||
420 			    !strcasecmp(argv[2],"mirror"))
421 				config.type = AR_RAID1;
422 			if (!strcasecmp(argv[2], "RAID0+1") ||
423 			    !strcasecmp(argv[2],"RAID10"))
424 				config.type = AR_RAID01;
425 			if (!strcasecmp(argv[2], "RAID5"))
426 				config.type = AR_RAID5;
427 			if (!strcasecmp(argv[2], "SPAN"))
428 				config.type = AR_SPAN;
429 			if (!strcasecmp(argv[2], "JBOD"))
430 				config.type = AR_JBOD;
431 		}
432 		if (!config.type) {
433 			fprintf(stderr, "natacontrol: Invalid RAID type %s\n",
434 				argv[2]);
435 			fprintf(stderr, "natacontrol: Valid RAID types: \n");
436 			fprintf(stderr, "             stripe | mirror | "
437 					"RAID0 | RAID1 | RAID0+1 | RAID5 | "
438 					"SPAN | JBOD\n");
439 			exit(EX_USAGE);
440 		}
441 
442 		if (config.type == AR_RAID0 ||
443 		    config.type == AR_RAID01 ||
444 		    config.type == AR_RAID5) {
445 			if (argc < 4 ||
446 			    !sscanf(argv[3], "%d", &config.interleave) == 1) {
447 				fprintf(stderr,
448 					"natacontrol: Invalid interleave %s\n",
449 					argv[3]);
450 				exit(EX_USAGE);
451 			}
452 			offset = 4;
453 		}
454 		else
455 			offset = 3;
456 
457 		for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
458 			if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
459 				fprintf(stderr,
460 					"natacontrol: Invalid disk %s\n",
461 					argv[offset + disk]);
462 				exit(EX_USAGE);
463 			}
464 			config.disks[disk] = dev;
465 		}
466 
467 		if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
468 		    disk < 2) {
469 			fprintf(stderr, "natacontrol: At least 2 disks must be "
470 				"specified\n");
471 			exit(EX_USAGE);
472 		}
473 
474 		config.total_disks = disk;
475 		if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
476 			err(1, "ioctl(IOCATARAIDCREATE)");
477 		else
478 			printf("ar%d created\n", config.lun);
479 		exit(EX_OK);
480 	}
481 	if (!strcmp(argv[1], "delete") && argc == 3) {
482 		int array;
483 
484 		if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
485 			fprintf(stderr,
486 				"natacontrol: Invalid array %s\n", argv[2]);
487                         exit(EX_USAGE);
488 		}
489 		if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
490 			warn("ioctl(IOCATARAIDDELETE)");
491 		exit(EX_OK);
492 	}
493 	if (!strcmp(argv[1], "addspare") && argc == 4) {
494 		struct ata_ioc_raid_config config;
495 
496 		if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
497 			fprintf(stderr,
498 				"natacontrol: Invalid array %s\n", argv[2]);
499 			usage();
500 		}
501 		if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
502 			fprintf(stderr,
503 				"natacontrol: Invalid disk %s\n", argv[3]);
504 			usage();
505 		}
506 		if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
507 			warn("ioctl(IOCATARAIDADDSPARE)");
508 		exit(EX_OK);
509 	}
510 	if (!strcmp(argv[1], "rebuild") && argc == 3) {
511 		int array;
512 
513 		if (!(sscanf(argv[2], "ar%d", &array) == 1)) {
514 			fprintf(stderr,
515 				"natacontrol: Invalid array %s\n", argv[2]);
516 			usage();
517 		}
518 		if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
519 			warn("ioctl(IOCATARAIDREBUILD)");
520 		else {
521 			char buffer[128];
522 			sprintf(buffer, "/usr/bin/nice -n 20 /bin/dd "
523 				"if=/dev/ar%d of=/dev/null bs=1m &",
524 				array);
525 			if (system(buffer))
526 				warn("background dd");
527 		}
528 		exit(EX_OK);
529 	}
530 	if (!strcmp(argv[1], "status") && argc == 3) {
531 		struct ata_ioc_raid_config config;
532 		int i;
533 
534 		if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) {
535 			fprintf(stderr,
536 				"natacontrol: Invalid array %s\n", argv[2]);
537 			usage();
538 		}
539 		if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0)
540 			err(1, "ioctl(IOCATARAIDSTATUS)");
541 
542 		printf("ar%d: ATA ", config.lun);
543 		switch (config.type) {
544 		case AR_RAID0:
545 			printf("RAID0 stripesize=%d", config.interleave);
546 			break;
547 		case AR_RAID1:
548 			printf("RAID1");
549 			break;
550 		case AR_RAID01:
551 			printf("RAID0+1 stripesize=%d", config.interleave);
552 			break;
553 		case AR_RAID5:
554 			printf("RAID5 stripesize=%d", config.interleave);
555 			break;
556 		case AR_JBOD:
557 			printf("JBOD");
558 		case AR_SPAN:
559 			printf("SPAN");
560 			break;
561 		}
562 		printf(" subdisks: ");
563 		for (i = 0; i < config.total_disks; i++) {
564 			if (config.disks[i] >= 0)
565 				printf("ad%d ", config.disks[i]);
566 			else
567 				printf("DOWN ");
568 		}
569 		printf("status: ");
570 		switch (config.status) {
571 		case AR_READY:
572 			printf("READY\n");
573 			break;
574 		case AR_READY | AR_DEGRADED:
575 			printf("DEGRADED\n");
576 			break;
577 		case AR_READY | AR_DEGRADED | AR_REBUILDING:
578 			printf("REBUILDING %d%% completed\n",
579 				config.progress);
580 			break;
581 		default:
582 			printf("BROKEN\n");
583 		}
584 		exit(EX_OK);
585 	}
586 	usage();
587 	exit(EX_OK);
588 }
589