1 /*- 2 * Copyright (c) 1999 Michael Smith 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/usr.sbin/mlxcontrol/command.c,v 1.3 2008/09/12 17:40:17 sepotvin Exp $ 27 */ 28 29 #include <fcntl.h> 30 #include <paths.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <err.h> 36 37 #include <dev/raid/mlx/mlxio.h> 38 #include <dev/raid/mlx/mlxreg.h> 39 40 #include "mlxcontrol.h" 41 42 static int cmd_status(int argc, char *argv[]); 43 static int cmd_rescan(int argc, char *argv[]); 44 static int cmd_detach(int argc, char *argv[]); 45 static int cmd_check(int argc, char *argv[]); 46 static int cmd_rebuild(int argc, char *argv[]); 47 #ifdef SUPPORT_PAUSE 48 static int cmd_pause(int argc, char *argv[]); 49 #endif 50 static int cmd_help(int argc, char *argv[]); 51 static int cmd_config(int argc, char *argv[]); 52 53 static void print_span(struct mlx_sys_drv_span *span, int arms); 54 static void print_sys_drive(struct conf_config *conf, int drvno); 55 static void print_phys_drive(struct conf_config *conf, int chn, int targ); 56 57 struct 58 { 59 const char *cmd; 60 int (*func)(int argc, char *argv[]); 61 const char *desc; 62 const char *text; 63 } commands[] = { 64 {"status", cmd_status, 65 "displays device status", 66 " status [-qv] [<drive>...]\n" 67 " Display status for <drive> or all drives if none is listed\n" 68 " -q Suppress output.\n" 69 " -v Display verbose information.\n" 70 " Returns 0 if all drives tested are online, 1 if one or more are\n" 71 " critical, and 2 if one or more are offline."}, 72 {"rescan", cmd_rescan, 73 "scan for new system drives", 74 " rescan <controller> [<controller>...]\n" 75 " Rescan <controller> for system drives.\n" 76 " rescan -a\n" 77 " Rescan all controllers for system drives."}, 78 {"detach", cmd_detach, 79 "detach system drives", 80 " detach <drive> [<drive>...]\n" 81 " Detaches <drive> from the controller.\n" 82 " detach -a <controller>\n" 83 " Detaches all drives on <controller>."}, 84 {"check", cmd_check, 85 "consistency-check a system drive", 86 " check <drive>\n" 87 " Requests a check and rebuild of the parity information on <drive>.\n" 88 " Note that each controller can only check one system drive at a time."}, 89 {"rebuild", cmd_rebuild, 90 "initiate a rebuild of a dead physical drive", 91 " rebuild <controller> <physdrive>\n" 92 " All system drives using space on the physical drive <physdrive>\n" 93 " are rebuilt, reconstructing all data on the drive.\n" 94 " Note that each controller can only perform one rebuild at a time."}, 95 #ifdef SUPPORT_PAUSE 96 {"pause", cmd_pause, 97 "pauses controller channels", 98 " pause [-t <howlong>] [-d <delay>] <controller> [<channel>...]\n" 99 " Pauses SCSI I/O on <channel> and <controller>. If no channel is specified,\n" 100 " all channels are paused.\n" 101 " <howlong> How long (seconds) to pause for (default 30).\n" 102 " <delay> How long (seconds) to wait before pausing (default 30).\n" 103 " pause <controller> -c\n" 104 " Cancels any pending pause operation on <controller>."}, 105 #endif 106 {"config", cmd_config, 107 "examine and update controller configuration", 108 " config <controller>\n" 109 " Print configuration for <controller>."}, 110 {"help", cmd_help, 111 "give help on usage", 112 ""}, 113 {NULL, NULL, NULL, NULL} 114 }; 115 116 /******************************************************************************** 117 * Command dispatch and global options parsing. 118 */ 119 120 int 121 main(int argc, char *argv[]) 122 { 123 int ch, i, oargc; 124 char **oargv; 125 126 oargc = argc; 127 oargv = argv; 128 while ((ch = getopt(argc, argv, "")) != -1) 129 switch(ch) { 130 default: 131 return(cmd_help(0, NULL)); 132 } 133 134 argc -= optind; 135 argv += optind; 136 137 if (argc > 0) 138 for (i = 0; commands[i].cmd != NULL; i++) 139 if (!strcmp(argv[0], commands[i].cmd)) 140 return(commands[i].func(argc, argv)); 141 142 return(cmd_help(oargc, oargv)); 143 } 144 145 /******************************************************************************** 146 * Helptext output 147 */ 148 static int 149 cmd_help(int argc, char *argv[]) 150 { 151 int i; 152 153 if (argc > 1) 154 for (i = 0; commands[i].cmd != NULL; i++) 155 if (!strcmp(argv[1], commands[i].cmd)) { 156 fprintf(stderr, "%s\n", commands[i].text); 157 fflush(stderr); 158 return(0); 159 } 160 161 if (argv != NULL) 162 fprintf(stderr, "Unknown command '%s'.\n", argv[1]); 163 fprintf(stderr, "Valid commands are:\n"); 164 for (i = 0; commands[i].cmd != NULL; i++) 165 fprintf(stderr, " %-20s %s\n", commands[i].cmd, commands[i].desc); 166 fflush(stderr); 167 return(0); 168 } 169 170 /******************************************************************************** 171 * Status output 172 * 173 * status [-qv] [<device> ...] 174 * Prints status for <device>, or all if none listed. 175 * 176 * -q Suppresses output, command returns 0 if devices are OK, 1 if one or 177 * more devices are critical, 2 if one or more devices are offline. 178 */ 179 static struct mlx_rebuild_status rs; 180 static int rs_ctrlr = -1; 181 static int status_result = 0; 182 183 /* XXX more verbosity! */ 184 static void 185 status_print(int unit, void *arg) 186 { 187 int verbosity = *(int *)arg; 188 int fd, result, ctrlr, sysdrive, statvalid; 189 190 /* Find which controller and what system drive we are */ 191 statvalid = 0; 192 if (mlxd_find_ctrlr(unit, &ctrlr, &sysdrive)) { 193 warnx("couldn't get controller/drive for %s", drivepath(unit)); 194 } else { 195 /* If we don't have rebuild stats for this controller, get them */ 196 if (rs_ctrlr == ctrlr) { 197 statvalid = 1; 198 } else { 199 if ((fd = open(ctrlrpath(ctrlr), 0)) < 0) { 200 warn("can't open %s", ctrlrpath(ctrlr)); 201 } else { 202 if (ioctl(fd, MLX_REBUILDSTAT, &rs) < 0) { 203 warn("ioctl MLX_REBUILDSTAT"); 204 } else { 205 rs_ctrlr = ctrlr; 206 statvalid = 1; 207 } 208 close(fd); 209 } 210 } 211 } 212 213 /* Get the device */ 214 if ((fd = open(drivepath(unit), 0)) < 0) { 215 warn("can't open %s", drivepath(unit)); 216 return; 217 } 218 219 /* Get its status */ 220 if (ioctl(fd, MLXD_STATUS, &result) < 0) { 221 warn("ioctl MLXD_STATUS"); 222 } else { 223 switch(result) { 224 case MLX_SYSD_ONLINE: 225 if (verbosity > 0) 226 printf("%s: online", drivename(unit)); 227 break; 228 case MLX_SYSD_CRITICAL: 229 if (verbosity > 0) 230 printf("%s: critical", drivename(unit)); 231 if (status_result < 1) 232 status_result = 1; 233 break; 234 case MLX_SYSD_OFFLINE: 235 if (verbosity > 0) 236 printf("%s: offline", drivename(unit)); 237 if (status_result < 2) 238 status_result = 2; 239 break; 240 default: 241 if (verbosity > 0) { 242 printf("%s: unknown status 0x%x", drivename(unit), result); 243 } 244 } 245 if (verbosity > 0) { 246 /* rebuild/check in progress on this drive? */ 247 if (statvalid && (rs_ctrlr == ctrlr) && 248 (rs.rs_drive == sysdrive) && (rs.rs_code != MLX_REBUILDSTAT_IDLE)) { 249 switch(rs.rs_code) { 250 case MLX_REBUILDSTAT_REBUILDCHECK: 251 printf(" [consistency check"); 252 break; 253 case MLX_REBUILDSTAT_ADDCAPACITY: 254 printf(" [add capacity"); 255 break; 256 case MLX_REBUILDSTAT_ADDCAPACITYINIT: 257 printf(" [add capacity init"); 258 break; 259 default: 260 printf(" [unknown operation"); 261 } 262 printf(": %d/%d, %d%% complete]", 263 rs.rs_remaining, rs.rs_size, 264 ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100))); 265 } 266 printf("\n"); 267 } 268 } 269 close(fd); 270 } 271 272 /******************************************************************************** 273 * Print details for the system drive (drvno) in a format that we will be 274 * able to parse later. 275 * 276 * drive?? <raidlevel> <writemode> 277 * span? 0x????????-0x???????? ????MB on <disk> [...] 278 * ... 279 */ 280 static void 281 print_span(struct mlx_sys_drv_span *span, int arms) 282 { 283 int i; 284 285 printf("0x%08x-0x%08x %uMB on", span->sp_start_lba, span->sp_start_lba + span->sp_nblks, span->sp_nblks / 2048); 286 for (i = 0; i < arms; i++) 287 printf(" disk%02d%02d", span->sp_arm[i] >> 4, span->sp_arm[i] & 0x0f); 288 printf("\n"); 289 } 290 291 static void 292 print_sys_drive(struct conf_config *conf, int drvno) 293 { 294 struct mlx_sys_drv *drv = &conf->cc_cfg.cc_sys_drives[drvno]; 295 int i; 296 297 printf("drive%02d ", drvno); 298 switch(drv->sd_raidlevel & 0xf) { 299 case MLX_SYS_DRV_RAID0: 300 printf("RAID0"); 301 break; 302 case MLX_SYS_DRV_RAID1: 303 printf("RAID1"); 304 break; 305 case MLX_SYS_DRV_RAID3: 306 printf("RAID3"); 307 break; 308 case MLX_SYS_DRV_RAID5: 309 printf("RAID5"); 310 break; 311 case MLX_SYS_DRV_RAID6: 312 printf("RAID6"); 313 break; 314 case MLX_SYS_DRV_JBOD: 315 printf("JBOD"); 316 break; 317 default: 318 printf("RAID?"); 319 } 320 printf(" write%s\n", drv->sd_raidlevel & MLX_SYS_DRV_WRITEBACK ? "back" : "through"); 321 322 for (i = 0; i < drv->sd_valid_spans; i++) { 323 printf(" span%d ", i); 324 print_span(&drv->sd_span[i], drv->sd_valid_arms); 325 } 326 } 327 328 /******************************************************************************** 329 * Print details for the physical drive at chn/targ in a format suitable for 330 * human consumption. 331 * 332 * <type>CCTT (<state>) "<vendor>/<model>" 333 * ????MB <features> 334 * 335 */ 336 static void 337 print_phys_drive(struct conf_config *conf, int chn, int targ) 338 { 339 struct mlx_phys_drv *drv = &conf->cc_cfg.cc_phys_drives[chn * 16 + targ]; 340 341 /* if the drive isn't present, don't print it */ 342 if (!(drv->pd_flags1 & MLX_PHYS_DRV_PRESENT)) 343 return; 344 345 mlx_print_phys_drv(drv, chn, targ, "# ", 1); 346 } 347 348 static struct 349 { 350 int hwid; 351 const char *name; 352 } mlx_controller_names[] = { 353 {0x01, "960P/PD"}, 354 {0x02, "960PL"}, 355 {0x10, "960PG"}, 356 {0x11, "960PJ"}, 357 {0x12, "960PR"}, 358 {0x13, "960PT"}, 359 {0x14, "960PTL0"}, 360 {0x15, "960PRL"}, 361 {0x16, "960PTL1"}, 362 {0x20, "1100PVX"}, 363 {-1, NULL} 364 }; 365 366 static void 367 controller_print(int unit, void *arg) 368 { 369 struct mlx_enquiry2 enq; 370 struct mlx_phys_drv pd; 371 int verbosity = *(int *)arg; 372 static char buf[80]; 373 const char *model; 374 int i, channel, target; 375 376 if (verbosity == 0) 377 return; 378 379 /* fetch and print controller data */ 380 if (mlx_enquiry(unit, &enq)) { 381 printf("mlx%d: error submitting ENQUIRY2\n", unit); 382 } else { 383 384 for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) { 385 if ((int)(enq.me_hardware_id & 0xff) == mlx_controller_names[i].hwid) { 386 model = mlx_controller_names[i].name; 387 break; 388 } 389 } 390 if (model == NULL) { 391 sprintf(buf, " model 0x%x", enq.me_hardware_id & 0xff); 392 model = buf; 393 } 394 395 printf("mlx%d: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n", 396 unit, model, 397 enq.me_actual_channels, 398 enq.me_actual_channels > 1 ? "s" : "", 399 enq.me_firmware_id & 0xff, 400 (enq.me_firmware_id >> 8) & 0xff, 401 (enq.me_firmware_id >> 16), 402 (enq.me_firmware_id >> 24) & 0xff, 403 enq.me_mem_size / (1024 * 1024)); 404 405 if (verbosity > 1) { 406 printf(" Hardware ID 0x%08x\n", enq.me_hardware_id); 407 printf(" Firmware ID 0x%08x\n", enq.me_firmware_id); 408 printf(" Configured/Actual channels %d/%d\n", enq.me_configured_channels, 409 enq.me_actual_channels); 410 printf(" Max Targets %d\n", enq.me_max_targets); 411 printf(" Max Tags %d\n", enq.me_max_tags); 412 printf(" Max System Drives %d\n", enq.me_max_sys_drives); 413 printf(" Max Arms %d\n", enq.me_max_arms); 414 printf(" Max Spans %d\n", enq.me_max_spans); 415 printf(" DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", enq.me_mem_size, 416 enq.me_cache_size, enq.me_flash_size, enq.me_nvram_size); 417 printf(" DRAM type %d\n", enq.me_mem_type); 418 printf(" Clock Speed %dns\n", enq.me_clock_speed); 419 printf(" Hardware Speed %dns\n", enq.me_hardware_speed); 420 printf(" Max Commands %d\n", enq.me_max_commands); 421 printf(" Max SG Entries %d\n", enq.me_max_sg); 422 printf(" Max DP %d\n", enq.me_max_dp); 423 printf(" Max IOD %d\n", enq.me_max_iod); 424 printf(" Max Comb %d\n", enq.me_max_comb); 425 printf(" Latency %ds\n", enq.me_latency); 426 printf(" SCSI Timeout %ds\n", enq.me_scsi_timeout); 427 printf(" Min Free Lines %d\n", enq.me_min_freelines); 428 printf(" Rate Constant %d\n", enq.me_rate_const); 429 printf(" MAXBLK %d\n", enq.me_maxblk); 430 printf(" Blocking Factor %d sectors\n", enq.me_blocking_factor); 431 printf(" Cache Line Size %d blocks\n", enq.me_cacheline); 432 printf(" SCSI Capability %s%dMHz, %d bit\n", 433 enq.me_scsi_cap & (1<<4) ? "differential " : "", 434 (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10, 435 8 << (enq.me_scsi_cap & 0x3)); 436 printf(" Firmware Build Number %d\n", enq.me_firmware_build); 437 printf(" Fault Management Type %d\n", enq.me_fault_mgmt_type); 438 #if 0 439 printf(" Features %b\n", enq.me_firmware_features, 440 "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n"); 441 #endif 442 } 443 444 /* fetch and print physical drive data */ 445 for (channel = 0; channel < enq.me_configured_channels; channel++) { 446 for (target = 0; target < enq.me_max_targets; target++) { 447 if ((mlx_get_device_state(unit, channel, target, &pd) == 0) && 448 (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT)) { 449 mlx_print_phys_drv(&pd, channel, target, " ", verbosity - 1); 450 if (verbosity > 1) { 451 /* XXX print device statistics? */ 452 } 453 } 454 } 455 } 456 } 457 } 458 459 static int 460 cmd_status(int argc, char *argv[]) 461 { 462 int ch, verbosity = 1, i, unit; 463 464 optreset = 1; 465 optind = 1; 466 while ((ch = getopt(argc, argv, "qv")) != -1) 467 switch(ch) { 468 case 'q': 469 verbosity = 0; 470 break; 471 case 'v': 472 verbosity = 2; 473 break; 474 default: 475 return(cmd_help(argc, argv)); 476 } 477 argc -= optind; 478 argv += optind; 479 480 if (argc < 1) { 481 mlx_foreach(controller_print, &verbosity); 482 mlxd_foreach(status_print, &verbosity); 483 } else { 484 for (i = 0; i < argc; i++) { 485 if ((unit = driveunit(argv[i])) == -1) { 486 warnx("'%s' is not a valid drive", argv[i]); 487 } else { 488 status_print(unit, &verbosity); 489 } 490 } 491 } 492 return(status_result); 493 } 494 495 /******************************************************************************** 496 * Recscan for system drives on one or more controllers. 497 * 498 * rescan <controller> [<controller>...] 499 * rescan -a 500 */ 501 static void 502 rescan_ctrlr(int unit, void *junk __unused) 503 { 504 int fd; 505 506 /* Get the device */ 507 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 508 warn("can't open %s", ctrlrpath(unit)); 509 return; 510 } 511 512 if (ioctl(fd, MLX_RESCAN_DRIVES) < 0) 513 warn("can't rescan %s", ctrlrname(unit)); 514 close(fd); 515 } 516 517 static int 518 cmd_rescan(int argc, char *argv[]) 519 { 520 int all = 0, i, ch, unit; 521 522 optreset = 1; 523 optind = 1; 524 while ((ch = getopt(argc, argv, "a")) != -1) 525 switch(ch) { 526 case 'a': 527 all = 1; 528 break; 529 default: 530 return(cmd_help(argc, argv)); 531 } 532 argc -= optind; 533 argv += optind; 534 535 if (all) { 536 mlx_foreach(rescan_ctrlr, NULL); 537 } else { 538 for (i = 0; i < argc; i++) { 539 if ((unit = ctrlrunit(argv[i])) == -1) { 540 warnx("'%s' is not a valid controller", argv[i]); 541 } else { 542 rescan_ctrlr(unit, NULL); 543 } 544 } 545 } 546 return(0); 547 } 548 549 /******************************************************************************** 550 * Detach one or more system drives from a controller. 551 * 552 * detach <drive> [<drive>...] 553 * Detach <drive>. 554 * 555 * detach -a <controller> [<controller>...] 556 * Detach all drives on <controller>. 557 * 558 */ 559 static void 560 detach_drive(int unit, void *arg __unused) 561 { 562 int fd; 563 564 /* Get the device */ 565 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 566 warn("can't open %s", ctrlrpath(unit)); 567 return; 568 } 569 570 if (ioctl(fd, MLX_DETACH_DRIVE, &unit) < 0) 571 warn("can't detach %s", drivename(unit)); 572 close(fd); 573 } 574 575 static int 576 cmd_detach(int argc, char *argv[]) 577 { 578 struct mlxd_foreach_action ma; 579 int all = 0, i, ch, unit; 580 581 optreset = 1; 582 optind = 1; 583 while ((ch = getopt(argc, argv, "a")) != -1) 584 switch(ch) { 585 case 'a': 586 all = 1; 587 break; 588 default: 589 return(cmd_help(argc, argv)); 590 } 591 argc -= optind; 592 argv += optind; 593 594 if (all) { 595 ma.func = detach_drive; 596 ma.arg = &unit; 597 for (i = 0; i < argc; i++) { 598 if ((unit = ctrlrunit(argv[i])) == -1) { 599 warnx("'%s' is not a valid controller", argv[i]); 600 } else { 601 mlxd_foreach_ctrlr(unit, &ma); 602 } 603 } 604 } else { 605 for (i = 0; i < argc; i++) { 606 if ((unit = driveunit(argv[i])) == -1) { 607 warnx("'%s' is not a valid drive", argv[i]); 608 } else { 609 /* run across all controllers to find this drive */ 610 mlx_foreach(detach_drive, &unit); 611 } 612 } 613 } 614 return(0); 615 } 616 617 /******************************************************************************** 618 * Initiate a consistency check on a system drive. 619 * 620 * check [<drive>] 621 * Start a check of <drive> 622 * 623 */ 624 static int 625 cmd_check(int argc, char *argv[]) 626 { 627 int unit, fd, result; 628 629 if (argc != 2) 630 return(cmd_help(argc, argv)); 631 632 if ((unit = driveunit(argv[1])) == -1) { 633 warnx("'%s' is not a valid drive", argv[1]); 634 } else { 635 636 /* Get the device */ 637 if ((fd = open(drivepath(unit), 0)) < 0) { 638 warn("can't open %s", drivepath(unit)); 639 } else { 640 /* Try to start the check */ 641 if ((ioctl(fd, MLXD_CHECKASYNC, &result)) < 0) { 642 switch(result) { 643 case 0x0002: 644 warnx("one or more of the SCSI disks on which the drive '%s' depends is DEAD", argv[1]); 645 break; 646 case 0x0105: 647 warnx("drive %s is invalid, or not a drive which can be checked", argv[1]); 648 break; 649 case 0x0106: 650 warnx("drive rebuild or consistency check is already in progress on this controller"); 651 break; 652 default: 653 warn("ioctl MLXD_CHECKASYNC"); 654 } 655 } 656 } 657 } 658 return(0); 659 } 660 661 /******************************************************************************** 662 * Initiate a physical drive rebuild 663 * 664 * rebuild <controller> <channel>:<target> 665 * Start a rebuild of <controller>:<channel>:<target> 666 * 667 */ 668 static int 669 cmd_rebuild(int argc, char *argv[]) 670 { 671 struct mlx_rebuild_request rb; 672 int unit, fd; 673 674 if (argc != 3) 675 return(cmd_help(argc, argv)); 676 677 /* parse arguments */ 678 if ((unit = ctrlrunit(argv[1])) == -1) { 679 warnx("'%s' is not a valid controller", argv[1]); 680 return(1); 681 } 682 /* try diskXXXX and unknownXXXX as we report the latter for a dead drive ... */ 683 if ((sscanf(argv[2], "disk%2d%2d", &rb.rr_channel, &rb.rr_target) != 2) && 684 (sscanf(argv[2], "unknown%2d%2d", &rb.rr_channel, &rb.rr_target) != 2)) { 685 warnx("'%s' is not a valid physical drive", argv[2]); 686 return(1); 687 } 688 /* get the device */ 689 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 690 warn("can't open %s", ctrlrpath(unit)); 691 return(1); 692 } 693 /* try to start the rebuild */ 694 if ((ioctl(fd, MLX_REBUILDASYNC, &rb)) < 0) { 695 switch(rb.rr_status) { 696 case 0x0002: 697 warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, rb.rr_target); 698 break; 699 case 0x0004: 700 warnx("drive failed during rebuild"); 701 break; 702 case 0x0105: 703 warnx("there is no drive at channel %d, target %d", rb.rr_channel, rb.rr_target); 704 break; 705 case 0x0106: 706 warnx("drive rebuild or consistency check is already in progress on this controller"); 707 break; 708 default: 709 warn("ioctl MLXD_REBUILDASYNC"); 710 } 711 } 712 return(0); 713 } 714 715 /******************************************************************************** 716 * Get the configuration from the selected controller. 717 * 718 * config <controller> 719 * Print the configuration for <controller> 720 * 721 * XXX update to support adding/deleting drives. 722 */ 723 724 int 725 cmd_config(int argc __unused, char *argv[] __unused) 726 { 727 struct conf_config conf; 728 int unit = 0; /* XXX */ 729 int i, j; 730 731 bzero(&conf.cc_cfg, sizeof(conf.cc_cfg)); 732 if (mlx_read_configuration(unit, &conf.cc_cfg)) { 733 printf("mlx%d: error submitting READ CONFIGURATION\n", unit); 734 } else { 735 736 printf("# Controller <INSERT DETAILS HERE>\n"); 737 printf("#\n# Physical devices connected:\n"); 738 for (i = 0; i < 5; i++) 739 for (j = 0; j < 16; j++) 740 print_phys_drive(&conf, i, j); 741 printf("#\n# System Drives defined:\n"); 742 743 for (i = 0; i < conf.cc_cfg.cc_num_sys_drives; i++) 744 print_sys_drive(&conf, i); 745 } 746 return(0); 747 } 748 749 #ifdef SUPPORT_PAUSE 750 /******************************************************************************** 751 * Pause one or more channels on a controller 752 * 753 * pause [-d <delay>] [-t <time>] <controller> [<channel>...] 754 * Pauses <channel> (or all channels) for <time> seconds after a 755 * delay of <delay> seconds. 756 * pause <controller> -c 757 * Cancels pending pause 758 */ 759 static int 760 cmd_pause(int argc, char *argv[]) 761 { 762 struct mlx_pause mp; 763 int unit, i, ch, fd, cancel = 0; 764 char *cp; 765 int oargc = argc; 766 char **oargv = argv; 767 768 mp.mp_which = 0; 769 mp.mp_when = 30; 770 mp.mp_howlong = 30; 771 optreset = 1; 772 optind = 1; 773 while ((ch = getopt(argc, argv, "cd:t:")) != -1) 774 switch(ch) { 775 case 'c': 776 cancel = 1; 777 break; 778 case 'd': 779 mp.mp_when = strtol(optarg, &cp, 0); 780 if (*cp != 0) 781 return(cmd_help(argc, argv)); 782 break; 783 case 't': 784 mp.mp_howlong = strtol(optarg, &cp, 0); 785 if (*cp != 0) 786 return(cmd_help(argc, argv)); 787 break; 788 default: 789 return(cmd_help(argc, argv)); 790 } 791 argc -= optind; 792 argv += optind; 793 794 /* get controller unit number that we're working on */ 795 if ((argc < 1) || ((unit = ctrlrunit(argv[0])) == -1)) 796 return(cmd_help(oargc, oargv)); 797 798 /* Get the device */ 799 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 800 warn("can't open %s", ctrlrpath(unit)); 801 return(1); 802 } 803 804 if (argc == 1) { 805 /* controller-wide pause/cancel */ 806 mp.mp_which = cancel ? MLX_PAUSE_CANCEL : MLX_PAUSE_ALL; 807 } else { 808 for (i = 1; i < argc; i++) { 809 ch = strtol(argv[i], &cp, 0); 810 if (*cp != 0) { 811 warnx("bad channel number '%s'", argv[i]); 812 continue; 813 } else { 814 mp.mp_which |= (1 << ch); 815 } 816 } 817 } 818 if ((ioctl(fd, MLX_PAUSE_CHANNEL, &mp)) < 0) 819 warn("couldn't %s %s", cancel ? "cancel pause on" : "pause", ctrlrname(unit)); 820 close(fd); 821 return(0); 822 } 823 #endif /* SUPPORT_PAUSE */ 824 825