Merge from vendor branch GDB:
[dragonfly.git] / sbin / natacontrol / natacontrol.c
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 }