]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sbin/atacontrol/atacontrol.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sbin / atacontrol / atacontrol.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$
27  */
28
29 #include <sys/types.h>
30 #include <sys/ata.h>
31
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sysexits.h>
40 #include <unistd.h>
41
42 static const char *
43 mode2str(int mode)
44 {
45         switch (mode) {
46         case ATA_PIO: return "BIOSPIO";
47         case ATA_PIO0: return "PIO0";
48         case ATA_PIO1: return "PIO1";
49         case ATA_PIO2: return "PIO2";
50         case ATA_PIO3: return "PIO3";
51         case ATA_PIO4: return "PIO4";
52         case ATA_WDMA2: return "WDMA2";
53         case ATA_UDMA2: return "UDMA33";
54         case ATA_UDMA4: return "UDMA66";
55         case ATA_UDMA5: return "UDMA100";
56         case ATA_UDMA6: return "UDMA133";
57         case ATA_SA150: return "SATA150";
58         case ATA_SA300: return "SATA300";
59         case ATA_USB: return "USB";
60         case ATA_USB1: return "USB1";
61         case ATA_USB2: return "USB2";
62         case ATA_DMA: return "BIOSDMA";
63         default: return "???";
64         }
65 }
66
67 static int
68 str2mode(char *str)
69 {
70         if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
71         if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
72         if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
73         if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
74         if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
75         if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
76         if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
77         if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
78         if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
79         if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
80         if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
81         if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
82         if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
83         if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
84         if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
85         if (!strcasecmp(str, "SATA150")) return ATA_SA150;
86         if (!strcasecmp(str, "SATA300")) return ATA_SA300;
87         if (!strcasecmp(str, "USB")) return ATA_USB;
88         if (!strcasecmp(str, "USB1")) return ATA_USB1;
89         if (!strcasecmp(str, "USB2")) return ATA_USB2;
90         if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
91         return -1;
92 }
93
94 static void
95 usage(void)
96 {
97         fprintf(stderr,
98                 "usage:  atacontrol <command> args:\n"
99                 "        atacontrol list\n"
100                 "        atacontrol info channel\n"
101                 "        atacontrol attach channel\n"
102                 "        atacontrol detach channel\n"
103                 "        atacontrol reinit channel\n"
104                 "        atacontrol create type [interleave] disk0 ... diskN\n"
105                 "        atacontrol delete array\n"
106                 "        atacontrol addspare array disk\n"
107                 "        atacontrol rebuild array\n"
108                 "        atacontrol status array\n"
109                 "        atacontrol mode device [mode]\n"
110                 "        atacontrol cap device\n"
111                 "        atacontrol spindown device [seconds]\n"
112         );
113         exit(EX_USAGE);
114 }
115
116 static int
117 version(int ver)
118 {
119         int bit;
120
121         if (ver == 0xffff)
122                 return 0;
123         for (bit = 15; bit >= 0; bit--)
124                 if (ver & (1<<bit))
125                         return bit;
126         return 0;
127 }
128
129 static void
130 param_print(struct ata_params *parm)
131 {
132         printf("<%.40s/%.8s> ", parm->model, parm->revision);
133         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
134                 if (parm->satacapabilities & ATA_SATA_GEN2)
135                         printf("SATA revision 2.x\n");
136                 else if (parm->satacapabilities & ATA_SATA_GEN1)
137                         printf("SATA revision 1.x\n");
138                 else
139                         printf("Unknown SATA revision\n");
140         }
141         else
142                 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
143 }
144
145 static void
146 cap_print(struct ata_params *parm)
147 {
148         u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
149                                 ((u_int32_t)parm->lba_size_2 << 16);
150
151         u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
152                                 ((u_int64_t)parm->lba_size48_2 << 16) |
153                                 ((u_int64_t)parm->lba_size48_3 << 32) |
154                                 ((u_int64_t)parm->lba_size48_4 << 48);
155
156         printf("\n");
157         printf("Protocol              ");
158         if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
159                 if (parm->satacapabilities & ATA_SATA_GEN2)
160                         printf("SATA revision 2.x\n");
161                 else if (parm->satacapabilities & ATA_SATA_GEN1)
162                         printf("SATA revision 1.x\n");
163                 else
164                         printf("Unknown SATA revision\n");
165         }
166         else
167                 printf("ATA/ATAPI revision %d\n", version(parm->version_major));
168         printf("device model          %.40s\n", parm->model);
169         printf("serial number         %.20s\n", parm->serial);
170         printf("firmware revision     %.8s\n", parm->revision);
171
172         printf("cylinders             %d\n", parm->cylinders);
173         printf("heads                 %d\n", parm->heads);
174         printf("sectors/track         %d\n", parm->sectors);
175
176         if (parm->config == ATA_PROTO_CFA ||
177             (parm->support.command2 & ATA_SUPPORT_CFA))
178                 printf("CFA supported\n");
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("%ju sectors\n", (uintmax_t)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 static void
258 ata_cap_print(int fd)
259 {
260         struct ata_params params;
261
262         if (ioctl(fd, IOCATAGPARM, &params) < 0)
263                 err(1, "ioctl(IOCATAGPARM)");
264         cap_print(&params);
265 }
266
267 static void
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                 if (!prchan)
276                         err(1, "ioctl(IOCATADEVICES)");
277                 return;
278         }
279         if (prchan)
280                 printf("ATA channel %d:\n", channel);
281         printf("%sMaster: ", prchan ? "    " : "");
282         if (*devices.name[0]) {
283                 printf("%4.4s ", devices.name[0]);
284                 param_print(&devices.params[0]);
285         }
286         else
287                 printf("     no device present\n");
288         printf("%sSlave:  ", prchan ? "    " : "");
289         if (*devices.name[1]) {
290                 printf("%4.4s ", devices.name[1]);
291                 param_print(&devices.params[1]);
292         }
293         else
294                 printf("     no device present\n");
295 }
296
297 static void
298 ata_spindown(int fd, const char *dev, const char *arg)
299 {
300         int tmo;
301
302         if (arg != NULL) {
303                 tmo = strtoul(arg, NULL, 0);
304                 if (ioctl(fd, IOCATASSPINDOWN, &tmo) < 0)
305                         err(1, "ioctl(IOCATASSPINDOWN)");
306         } else {
307                 if (ioctl(fd, IOCATAGSPINDOWN, &tmo) < 0)
308                         err(1, "ioctl(IOCATAGSPINDOWN)");
309                 if (tmo == 0)
310                         printf("%s: idle spin down disabled\n", dev);
311                 else
312                         printf("%s: spin down after %d seconds idle\n",
313                             dev, tmo);
314         }
315 }
316
317 static int
318 open_dev(const char *arg, int mode)
319 {
320         int disk, fd;
321         char device[64];
322
323         if (!(sscanf(arg, "ad%d", &disk) == 1 ||
324               sscanf(arg, "acd%d", &disk) == 1 ||
325               sscanf(arg, "afd%d", &disk) == 1 ||
326               sscanf(arg, "ast%d", &disk) == 1)) {
327                 fprintf(stderr, "atacontrol: Invalid device %s\n", arg);
328                 exit(EX_USAGE);
329         }
330         sprintf(device, "/dev/%s", arg);
331         if ((fd = open(device, mode)) < 0)
332                 err(1, "device not found");
333         return (fd);
334 }
335
336 static int
337 ar_arg(const char *arg)
338 {
339         int array;
340
341         if (!(sscanf(arg, "ar%d", &array) == 1)) {
342                 fprintf(stderr, "atacontrol: Invalid array %s\n", arg);
343                 exit(EX_USAGE);
344         }
345         return (array);
346 }
347
348 static int
349 ata_arg(const char *arg)
350 {
351         int channel;
352
353         if (!(sscanf(arg, "ata%d", &channel) == 1)) {
354                 fprintf(stderr, "atacontrol: Invalid channel %s\n", arg);
355                 exit(EX_USAGE);
356         }
357         return (channel);
358 }
359
360 int
361 main(int argc, char **argv)
362 {
363         int fd, mode, channel, array;
364
365         if (argc < 2)
366                 usage();
367
368         if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
369                 fd = open_dev(argv[2], O_RDONLY);
370                 if (argc == 4) {
371                         mode = str2mode(argv[3]);
372                         if (mode == -1)
373                                 errx(1, "unknown mode");
374                         if (ioctl(fd, IOCATASMODE, &mode) < 0)
375                                 warn("ioctl(IOCATASMODE)");
376                 }
377                 if (argc == 3 || argc == 4) {
378                         if (ioctl(fd, IOCATAGMODE, &mode) < 0)
379                                 err(1, "ioctl(IOCATAGMODE)");
380                         printf("current mode = %s\n", mode2str(mode));
381                 }
382                 exit(EX_OK);
383         }
384         if (!strcmp(argv[1], "cap") && argc == 3) {
385                 fd = open_dev(argv[2], O_RDONLY);
386                 ata_cap_print(fd);
387                 exit(EX_OK);
388         }
389
390         if (!strcmp(argv[1], "spindown") && (argc == 3 || argc == 4)) {
391                 fd = open_dev(argv[2], O_RDONLY);
392                 ata_spindown(fd, argv[2], argv[3]);
393                 exit(EX_OK);
394         }
395
396         if ((fd = open("/dev/ata", O_RDWR)) < 0)
397                 err(1, "control device not found");
398
399         if (!strcmp(argv[1], "list") && argc == 2) {
400                 int maxchannel;
401
402                 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
403                         err(1, "ioctl(IOCATAGMAXCHANNEL)");
404                 for (channel = 0; channel < maxchannel; channel++)
405                         info_print(fd, channel, 1);
406                 exit(EX_OK);
407         }
408         if (!strcmp(argv[1], "info") && argc == 3) {
409                 channel = ata_arg(argv[2]);
410                 info_print(fd, channel, 0);
411                 exit(EX_OK);
412         }
413         if (!strcmp(argv[1], "detach") && argc == 3) {
414                 channel = ata_arg(argv[2]);
415                 if (ioctl(fd, IOCATADETACH, &channel) < 0)
416                         err(1, "ioctl(IOCATADETACH)");
417                 exit(EX_OK);
418         }
419         if (!strcmp(argv[1], "attach") && argc == 3) {
420                 channel = ata_arg(argv[2]);
421                 if (ioctl(fd, IOCATAATTACH, &channel) < 0)
422                         err(1, "ioctl(IOCATAATTACH)");
423                 info_print(fd, channel, 0);
424                 exit(EX_OK);
425         }
426         if (!strcmp(argv[1], "reinit") && argc == 3) {
427                 channel = ata_arg(argv[2]);
428                 if (ioctl(fd, IOCATAREINIT, &channel) < 0)
429                         warn("ioctl(IOCATAREINIT)");
430                 info_print(fd, channel, 0);
431                 exit(EX_OK);
432         }
433         if (!strcmp(argv[1], "create")) {
434                 int disk, dev, offset;
435                 struct ata_ioc_raid_config config;
436
437                 bzero(&config, sizeof(config));
438                 if (argc > 2) {
439                         if (!strcasecmp(argv[2], "RAID0") ||
440                             !strcasecmp(argv[2], "stripe"))
441                                 config.type = AR_RAID0;
442                         if (!strcasecmp(argv[2], "RAID1") ||
443                             !strcasecmp(argv[2],"mirror"))
444                                 config.type = AR_RAID1;
445                         if (!strcasecmp(argv[2], "RAID0+1") ||
446                             !strcasecmp(argv[2],"RAID10"))
447                                 config.type = AR_RAID01;
448                         if (!strcasecmp(argv[2], "RAID5"))
449                                 config.type = AR_RAID5;
450                         if (!strcasecmp(argv[2], "SPAN"))
451                                 config.type = AR_SPAN;
452                         if (!strcasecmp(argv[2], "JBOD"))
453                                 config.type = AR_JBOD;
454                 }
455                 if (!config.type) {
456                         fprintf(stderr, "atacontrol: Invalid RAID type %s\n",
457                                 argv[2]);
458                         fprintf(stderr, "atacontrol: Valid RAID types: \n");
459                         fprintf(stderr, "            stripe | mirror | "
460                                         "RAID0 | RAID1 | RAID0+1 | RAID5 | "
461                                         "SPAN | JBOD\n");
462                         exit(EX_USAGE);
463                 }
464
465                 if (config.type == AR_RAID0 ||
466                     config.type == AR_RAID01 ||
467                     config.type == AR_RAID5) {
468                         if (argc < 4 ||
469                             !sscanf(argv[3], "%d", &config.interleave) == 1) {
470                                 fprintf(stderr,
471                                         "atacontrol: Invalid interleave %s\n",
472                                         argv[3]);
473                                 exit(EX_USAGE);
474                         }
475                         offset = 4;
476                 }
477                 else
478                         offset = 3;
479
480                 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
481                         if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
482                                 fprintf(stderr,
483                                         "atacontrol: Invalid disk %s\n",
484                                         argv[offset + disk]);
485                                 exit(EX_USAGE);
486                         }
487                         config.disks[disk] = dev;
488                 }
489
490                 if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
491                     disk < 2) {
492                         fprintf(stderr, "atacontrol: At least 2 disks must be "
493                                 "specified\n");
494                         exit(EX_USAGE);
495                 }
496
497                 config.total_disks = disk;
498                 if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
499                         err(1, "ioctl(IOCATARAIDCREATE)");
500                 else
501                         printf("ar%d created\n", config.lun);
502                 exit(EX_OK);
503         }
504         if (!strcmp(argv[1], "delete") && argc == 3) {
505                 array = ar_arg(argv[2]);
506                 if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
507                         warn("ioctl(IOCATARAIDDELETE)");
508                 exit(EX_OK);
509         }
510         if (!strcmp(argv[1], "addspare") && argc == 4) {
511                 struct ata_ioc_raid_config config;
512
513                 config.lun = ar_arg(argv[2]);
514                 if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
515                         fprintf(stderr,
516                                 "atacontrol: Invalid disk %s\n", argv[3]);
517                         usage();
518                 }
519                 if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
520                         warn("ioctl(IOCATARAIDADDSPARE)");
521                 exit(EX_OK);
522         }
523         if (!strcmp(argv[1], "rebuild") && argc == 3) {
524                 array = ar_arg(argv[2]);
525                 if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
526                         warn("ioctl(IOCATARAIDREBUILD)");
527                 else {
528                         char device[64];
529                         char *buffer;
530                         ssize_t len;
531                         int arfd;
532
533                         if (daemon(0, 1) == -1)
534                                 err(1, "daemon");
535                         nice(20);
536                         snprintf(device, sizeof(device), "/dev/ar%d",
537                             array);
538                         if ((arfd = open(device, O_RDONLY)) == -1)
539                                 err(1, "open %s", device);
540                         if ((buffer = malloc(1024 * 1024)) == NULL)
541                                 err(1, "malloc");
542                         while ((len = read(arfd, buffer, 1024 * 1024)) > 0)
543                                 ;
544                         if (len == -1)
545                                 err(1, "read");
546                         else
547                                 fprintf(stderr,
548                                     "atacontrol: ar%d rebuild completed\n",
549                                     array);
550                         free(buffer);
551                         close(arfd);
552                 }
553                 exit(EX_OK);
554         }
555         if (!strcmp(argv[1], "status") && argc == 3) {
556                 struct ata_ioc_raid_status status;
557                 int i, lun, state;
558
559                 status.lun = ar_arg(argv[2]);
560                 if (ioctl(fd, IOCATARAIDSTATUS, &status) < 0)
561                         err(1, "ioctl(IOCATARAIDSTATUS)");
562
563                 printf("ar%d: ATA ", status.lun);
564                 switch (status.type) {
565                 case AR_RAID0:
566                         printf("RAID0 stripesize=%d", status.interleave);
567                         break;
568                 case AR_RAID1:
569                         printf("RAID1");
570                         break;
571                 case AR_RAID01:
572                         printf("RAID0+1 stripesize=%d", status.interleave);
573                         break;
574                 case AR_RAID5:
575                         printf("RAID5 stripesize=%d", status.interleave);
576                         break;
577                 case AR_JBOD:
578                         printf("JBOD");
579                         break;
580                 case AR_SPAN:
581                         printf("SPAN");
582                         break;
583                 }
584                 printf(" status: ");
585                 switch (status.status) {
586                 case AR_READY:
587                         printf("READY\n");
588                         break;
589                 case AR_READY | AR_DEGRADED:
590                         printf("DEGRADED\n");
591                         break;
592                 case AR_READY | AR_DEGRADED | AR_REBUILDING:
593                         printf("REBUILDING %d%% completed\n",
594                                 status.progress);
595                         break;
596                 default:
597                         printf("BROKEN\n");
598                 }
599                 printf(" subdisks:\n");
600                 for (i = 0; i < status.total_disks; i++) {
601                         printf("  %2d ", i);
602                         lun = status.disks[i].lun;
603                         state = status.disks[i].state;
604                         if (lun < 0)
605                                 printf("---- ");
606                         else
607                                 printf("ad%-2d ", lun);
608                         if (state & AR_DISK_ONLINE)
609                                 printf("ONLINE");
610                         else if (state & AR_DISK_SPARE)
611                                 printf("SPARE");
612                         else if (state & AR_DISK_PRESENT)
613                                 printf("OFFLINE");
614                         else
615                                 printf("MISSING");
616                         printf("\n");
617                 }
618                 exit(EX_OK);
619         }
620         usage();
621         exit(EX_OK);
622 }