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 */ 28 29 #include <sys/nata.h> 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <fcntl.h> 35 #include <errno.h> 36 #include <err.h> 37 38 #include <sysexits.h> 39 #include <unistd.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(void) 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 feature device apm apmlevel\n" 114 " natacontrol feature device acoustic soundsupplevel\n" 115 " natacontrol cap device\n" 116 ); 117 exit(EX_USAGE); 118 } 119 120 int 121 version(int ver) 122 { 123 int bit; 124 125 if (ver == 0xffff) 126 return 0; 127 for (bit = 15; bit >= 0; bit--) 128 if (ver & (1<<bit)) 129 return bit; 130 return 0; 131 } 132 133 void 134 param_print(struct ata_params *parm) 135 { 136 printf("<%.40s/%.8s> ", parm->model, parm->revision); 137 if (parm->satacapabilities && parm->satacapabilities != 0xffff) { 138 if (parm->satacapabilities & ATA_SATA_GEN2) 139 printf("Serial ATA II\n"); 140 else if (parm->satacapabilities & ATA_SATA_GEN1) 141 printf("Serial ATA v1.0\n"); 142 else 143 printf("Unknown serial ATA version\n"); 144 } 145 else 146 printf("ATA/ATAPI revision %d\n", version(parm->version_major)); 147 } 148 149 void 150 cap_print(struct ata_params *parm) 151 { 152 u_int32_t lbasize = (u_int32_t)parm->lba_size_1 | 153 ((u_int32_t)parm->lba_size_2 << 16); 154 155 u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) | 156 ((u_int64_t)parm->lba_size48_2 << 16) | 157 ((u_int64_t)parm->lba_size48_3 << 32) | 158 ((u_int64_t)parm->lba_size48_4 << 48); 159 160 printf("\n"); 161 printf("Protocol "); 162 if (parm->satacapabilities && parm->satacapabilities != 0xffff) { 163 if (parm->satacapabilities & ATA_SATA_GEN2) 164 printf("Serial ATA II\n"); 165 else if (parm->satacapabilities & ATA_SATA_GEN1) 166 printf("Serial ATA v1.0\n"); 167 else 168 printf("Unknown serial ATA version\n"); 169 } 170 else 171 printf("ATA/ATAPI revision %d\n", version(parm->version_major)); 172 printf("device model %.40s\n", parm->model); 173 printf("serial number %.20s\n", parm->serial); 174 printf("firmware revision %.8s\n", parm->revision); 175 176 printf("cylinders %d\n", parm->cylinders); 177 printf("heads %d\n", parm->heads); 178 printf("sectors/track %d\n", parm->sectors); 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("%llu sectors\n", (unsigned long long)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 int 258 ata_cap_print(int fd) 259 { 260 struct ata_params params; 261 262 if (ioctl(fd, IOCATAGPARM, ¶ms) < 0) 263 return errno; 264 cap_print(¶ms); 265 return 0; 266 } 267 268 int 269 info_print(int fd, int channel, int prchan) 270 { 271 struct ata_ioc_devices devices; 272 273 devices.channel = channel; 274 275 if (ioctl(fd, IOCATADEVICES, &devices) < 0) 276 return errno; 277 278 if (prchan) 279 printf("ATA channel %d:\n", channel); 280 printf("%sMaster: ", prchan ? " " : ""); 281 if (*devices.name[0]) { 282 printf("%4.4s ", devices.name[0]); 283 param_print(&devices.params[0]); 284 } 285 else 286 printf(" no device present\n"); 287 printf("%sSlave: ", prchan ? " " : ""); 288 if (*devices.name[1]) { 289 printf("%4.4s ", devices.name[1]); 290 param_print(&devices.params[1]); 291 } 292 else 293 printf(" no device present\n"); 294 return 0; 295 } 296 297 int 298 main(int argc, char **argv) 299 { 300 int fd; 301 302 if (argc < 2) 303 usage(); 304 305 if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) { 306 int disk, mode; 307 char device[64]; 308 309 if (!(sscanf(argv[2], "ad%d", &disk) == 1 || 310 sscanf(argv[2], "acd%d", &disk) == 1 || 311 sscanf(argv[2], "afd%d", &disk) == 1 || 312 sscanf(argv[2], "ast%d", &disk) == 1)) { 313 fprintf(stderr, "natacontrol: Invalid device %s\n", 314 argv[2]); 315 exit(EX_USAGE); 316 } 317 sprintf(device, "/dev/%s", argv[2]); 318 if ((fd = open(device, O_RDONLY)) < 0) 319 err(1, "device not found"); 320 if (argc == 4) { 321 mode = str2mode(argv[3]); 322 if (ioctl(fd, IOCATASMODE, &mode) < 0) 323 warn("ioctl(IOCATASMODE)"); 324 } 325 if (argc == 3 || argc == 4) { 326 if (ioctl(fd, IOCATAGMODE, &mode) < 0) 327 err(1, "ioctl(IOCATAGMODE)"); 328 printf("current mode = %s\n", mode2str(mode)); 329 } 330 exit(EX_OK); 331 } 332 if (!strcmp(argv[1], "feature") && argc == 5) { 333 int disk; 334 char device[64]; 335 struct ata_ioc_request request; 336 337 if (!(sscanf(argv[2], "ad%d", &disk) == 1 || 338 sscanf(argv[2], "acd%d", &disk) == 1 || 339 sscanf(argv[2], "afd%d", &disk) == 1 || 340 sscanf(argv[2], "ast%d", &disk) == 1)) { 341 fprintf(stderr, "natacontrol: Invalid device %s\n", 342 argv[2]); 343 exit(EX_USAGE); 344 } 345 sprintf(device, "/dev/%s", argv[2]); 346 if ((fd = open(device, O_RDONLY)) < 0) 347 err(1, "device not found"); 348 349 bzero(&request, sizeof(struct ata_ioc_request)); 350 request.u.ata.command = ATA_SETFEATURES; 351 request.flags = ATA_CMD_CONTROL; 352 request.timeout = 500; 353 if (!strcmp(argv[3], "apm")) { 354 if (!strcmp(argv[4], "off")) { 355 request.u.ata.feature = ATA_SF_DIS_APM; 356 } else if (!strcmp(argv[4], "maxperf")) { 357 request.u.ata.feature = ATA_SF_ENAB_APM; 358 request.u.ata.count = 0xfe; 359 } else if (!strcmp(argv[4], "minpower")) { 360 request.u.ata.feature = ATA_SF_ENAB_APM; 361 request.u.ata.count = 0x01; 362 } else { 363 int offset = 0; 364 365 request.u.ata.feature = ATA_SF_ENAB_APM; 366 if (argv[4][0] == 's') { 367 offset = atoi(&argv[4][1]); 368 request.u.ata.count = 0x01; 369 } else { 370 offset = atoi(&argv[4][1]); 371 request.u.ata.count = 0x80; 372 } 373 if (offset >= 0 && offset <= 127) 374 request.u.ata.count += offset; 375 } 376 } else if (!strcmp(argv[3], "acoustic")) { 377 if (!strcmp(argv[4], "off")) { 378 request.u.ata.feature = ATA_SF_DIS_ACCOUS; 379 } else if (!strcmp(argv[4], "maxperf")) { 380 request.u.ata.feature = ATA_SF_ENAB_ACCOUS; 381 request.u.ata.count = 0xfe; 382 } else if (!strcmp(argv[4], "maxquiet")) { 383 request.u.ata.feature = ATA_SF_ENAB_ACCOUS; 384 request.u.ata.count = 0x80; 385 } else { 386 request.u.ata.feature = ATA_SF_ENAB_ACCOUS; 387 request.u.ata.count = atoi(argv[4]); 388 if (request.u.ata.count > 124) 389 request.u.ata.count = 124; 390 } 391 } else { 392 usage(); 393 } 394 395 if (ioctl(fd, IOCATAREQUEST, &request) < 0) 396 err(1, "ioctl(IOCATAREQUEST)"); 397 398 if (request.error != 0) { 399 fprintf(stderr, 400 "IOCATAREQUEST returned err status %d", 401 request.error); 402 exit(EX_IOERR); 403 } 404 exit(EX_OK); 405 } 406 if (!strcmp(argv[1], "cap") && argc == 3) { 407 int disk; 408 char device[64]; 409 410 if (!(sscanf(argv[2], "ad%d", &disk) == 1 || 411 sscanf(argv[2], "acd%d", &disk) == 1 || 412 sscanf(argv[2], "afd%d", &disk) == 1 || 413 sscanf(argv[2], "ast%d", &disk) == 1)) { 414 fprintf(stderr, "natacontrol: Invalid device %s\n", 415 argv[2]); 416 exit(EX_USAGE); 417 } 418 sprintf(device, "/dev/%s", argv[2]); 419 if ((fd = open(device, O_RDONLY)) < 0) 420 err(1, "device not found"); 421 ata_cap_print(fd); 422 exit(EX_OK); 423 } 424 425 if ((fd = open("/dev/ata", O_RDWR)) < 0) 426 err(1, "control device not found"); 427 428 if (!strcmp(argv[1], "list") && argc == 2) { 429 int maxchannel, channel; 430 431 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) 432 err(1, "ioctl(IOCATAGMAXCHANNEL)"); 433 for (channel = 0; channel < maxchannel; channel++) 434 info_print(fd, channel, 1); 435 exit(EX_OK); 436 } 437 if (!strcmp(argv[1], "info") && argc == 3) { 438 int channel; 439 440 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { 441 fprintf(stderr, 442 "natacontrol: Invalid channel %s\n", argv[2]); 443 exit(EX_USAGE); 444 } 445 info_print(fd, channel, 0); 446 exit(EX_OK); 447 } 448 if (!strcmp(argv[1], "detach") && argc == 3) { 449 int channel; 450 451 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { 452 fprintf(stderr, 453 "natacontrol: Invalid channel %s\n", argv[2]); 454 exit(EX_USAGE); 455 } 456 if (ioctl(fd, IOCATADETACH, &channel) < 0) 457 err(1, "ioctl(IOCATADETACH)"); 458 exit(EX_OK); 459 } 460 if (!strcmp(argv[1], "attach") && argc == 3) { 461 int channel; 462 463 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { 464 fprintf(stderr, 465 "natacontrol: Invalid channel %s\n", argv[2]); 466 exit(EX_USAGE); 467 } 468 if (ioctl(fd, IOCATAATTACH, &channel) < 0) 469 err(1, "ioctl(IOCATAATTACH)"); 470 info_print(fd, channel, 0); 471 exit(EX_OK); 472 } 473 if (!strcmp(argv[1], "reinit") && argc == 3) { 474 int channel; 475 476 if (!(sscanf(argv[2], "ata%d", &channel) == 1)) { 477 fprintf(stderr, 478 "natacontrol: Invalid channel %s\n", argv[2]); 479 exit(EX_USAGE); 480 } 481 if (ioctl(fd, IOCATAREINIT, &channel) < 0) 482 warn("ioctl(IOCATAREINIT)"); 483 info_print(fd, channel, 0); 484 exit(EX_OK); 485 } 486 if (!strcmp(argv[1], "create")) { 487 int disk, dev, offset; 488 struct ata_ioc_raid_config config; 489 490 bzero(&config, sizeof(config)); 491 if (argc > 2) { 492 if (!strcasecmp(argv[2], "RAID0") || 493 !strcasecmp(argv[2], "stripe")) 494 config.type = AR_RAID0; 495 if (!strcasecmp(argv[2], "RAID1") || 496 !strcasecmp(argv[2],"mirror")) 497 config.type = AR_RAID1; 498 if (!strcasecmp(argv[2], "RAID0+1") || 499 !strcasecmp(argv[2],"RAID10")) 500 config.type = AR_RAID01; 501 if (!strcasecmp(argv[2], "RAID5")) 502 config.type = AR_RAID5; 503 if (!strcasecmp(argv[2], "SPAN")) 504 config.type = AR_SPAN; 505 if (!strcasecmp(argv[2], "JBOD")) 506 config.type = AR_JBOD; 507 } 508 if (!config.type) { 509 fprintf(stderr, "natacontrol: Invalid RAID type %s\n", 510 argv[2]); 511 fprintf(stderr, "natacontrol: Valid RAID types: \n"); 512 fprintf(stderr, " stripe | mirror | " 513 "RAID0 | RAID1 | RAID0+1 | RAID5 | " 514 "SPAN | JBOD\n"); 515 exit(EX_USAGE); 516 } 517 518 if (config.type == AR_RAID0 || 519 config.type == AR_RAID01 || 520 config.type == AR_RAID5) { 521 if (argc < 4 || 522 !sscanf(argv[3], "%d", &config.interleave) == 1) { 523 fprintf(stderr, 524 "natacontrol: Invalid interleave %s\n", 525 argv[3]); 526 exit(EX_USAGE); 527 } 528 offset = 4; 529 } 530 else 531 offset = 3; 532 533 for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) { 534 if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) { 535 fprintf(stderr, 536 "natacontrol: Invalid disk %s\n", 537 argv[offset + disk]); 538 exit(EX_USAGE); 539 } 540 config.disks[disk] = dev; 541 } 542 543 if ((config.type == AR_RAID1 || config.type == AR_RAID01) && 544 disk < 2) { 545 fprintf(stderr, "natacontrol: At least 2 disks must be " 546 "specified\n"); 547 exit(EX_USAGE); 548 } 549 550 config.total_disks = disk; 551 if (ioctl(fd, IOCATARAIDCREATE, &config) < 0) 552 err(1, "ioctl(IOCATARAIDCREATE)"); 553 else 554 printf("ar%d created\n", config.lun); 555 exit(EX_OK); 556 } 557 if (!strcmp(argv[1], "delete") && argc == 3) { 558 int array; 559 560 if (!(sscanf(argv[2], "ar%d", &array) == 1)) { 561 fprintf(stderr, 562 "natacontrol: Invalid array %s\n", argv[2]); 563 exit(EX_USAGE); 564 } 565 if (ioctl(fd, IOCATARAIDDELETE, &array) < 0) 566 warn("ioctl(IOCATARAIDDELETE)"); 567 exit(EX_OK); 568 } 569 if (!strcmp(argv[1], "addspare") && argc == 4) { 570 struct ata_ioc_raid_config config; 571 572 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) { 573 fprintf(stderr, 574 "natacontrol: Invalid array %s\n", argv[2]); 575 usage(); 576 } 577 if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) { 578 fprintf(stderr, 579 "natacontrol: Invalid disk %s\n", argv[3]); 580 usage(); 581 } 582 if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0) 583 warn("ioctl(IOCATARAIDADDSPARE)"); 584 exit(EX_OK); 585 } 586 if (!strcmp(argv[1], "rebuild") && argc == 3) { 587 int array; 588 589 if (!(sscanf(argv[2], "ar%d", &array) == 1)) { 590 fprintf(stderr, 591 "natacontrol: Invalid array %s\n", argv[2]); 592 usage(); 593 } 594 if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0) 595 warn("ioctl(IOCATARAIDREBUILD)"); 596 else { 597 char device[64]; 598 char *buffer; 599 ssize_t len; 600 int arfd; 601 602 if (daemon(0, 1) == -1) 603 err(1, "daemon"); 604 nice(20); 605 snprintf(device, sizeof(device), "/dev/ar%d", 606 array); 607 if ((arfd = open(device, O_RDONLY)) == -1) 608 err(1, "open %s", device); 609 if ((buffer = malloc(1024 * 1024)) == NULL) 610 err(1, "malloc"); 611 while ((len = read(arfd, buffer, 1024 * 1024)) > 0) 612 ; 613 if (len == -1) 614 err(1, "read"); 615 else 616 fprintf(stderr, 617 "natacontrol: ar%d rebuild completed\n", 618 array); 619 free(buffer); 620 close(arfd); 621 } 622 exit(EX_OK); 623 } 624 if (!strcmp(argv[1], "status") && argc == 3) { 625 struct ata_ioc_raid_config config; 626 int i; 627 628 if (!(sscanf(argv[2], "ar%d", &config.lun) == 1)) { 629 fprintf(stderr, 630 "natacontrol: Invalid array %s\n", argv[2]); 631 usage(); 632 } 633 if (ioctl(fd, IOCATARAIDSTATUS, &config) < 0) 634 err(1, "ioctl(IOCATARAIDSTATUS)"); 635 636 printf("ar%d: ATA ", config.lun); 637 switch (config.type) { 638 case AR_RAID0: 639 printf("RAID0 stripesize=%d", config.interleave); 640 break; 641 case AR_RAID1: 642 printf("RAID1"); 643 break; 644 case AR_RAID01: 645 printf("RAID0+1 stripesize=%d", config.interleave); 646 break; 647 case AR_RAID5: 648 printf("RAID5 stripesize=%d", config.interleave); 649 break; 650 case AR_JBOD: 651 printf("JBOD"); 652 case AR_SPAN: 653 printf("SPAN"); 654 break; 655 } 656 printf(" subdisks: "); 657 for (i = 0; i < config.total_disks; i++) { 658 if (config.disks[i] >= 0) 659 printf("ad%d ", config.disks[i]); 660 else 661 printf("DOWN "); 662 } 663 printf("status: "); 664 switch (config.status) { 665 case AR_READY: 666 printf("READY\n"); 667 break; 668 case AR_READY | AR_DEGRADED: 669 printf("DEGRADED\n"); 670 break; 671 case AR_READY | AR_DEGRADED | AR_REBUILDING: 672 printf("REBUILDING %d%% completed\n", 673 config.progress); 674 break; 675 default: 676 printf("BROKEN\n"); 677 } 678 exit(EX_OK); 679 } 680 usage(); 681 exit(EX_OK); 682 } 683