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