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