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, statvalid; 189 int ctrlr = -1, sysdrive = -1; 190 191 /* Find which controller and what system drive we are */ 192 statvalid = 0; 193 if (mlxd_find_ctrlr(unit, &ctrlr, &sysdrive)) { 194 warnx("couldn't get controller/drive for %s", drivepath(unit)); 195 } else { 196 /* If we don't have rebuild stats for this controller, get them */ 197 if (rs_ctrlr == ctrlr) { 198 statvalid = 1; 199 } else { 200 if ((fd = open(ctrlrpath(ctrlr), 0)) < 0) { 201 warn("can't open %s", ctrlrpath(ctrlr)); 202 } else { 203 if (ioctl(fd, MLX_REBUILDSTAT, &rs) < 0) { 204 warn("ioctl MLX_REBUILDSTAT"); 205 } else { 206 rs_ctrlr = ctrlr; 207 statvalid = 1; 208 } 209 close(fd); 210 } 211 } 212 } 213 214 /* Get the device */ 215 if ((fd = open(drivepath(unit), 0)) < 0) { 216 warn("can't open %s", drivepath(unit)); 217 return; 218 } 219 220 /* Get its status */ 221 if (ioctl(fd, MLXD_STATUS, &result) < 0) { 222 warn("ioctl MLXD_STATUS"); 223 } else { 224 switch(result) { 225 case MLX_SYSD_ONLINE: 226 if (verbosity > 0) 227 printf("%s: online", drivename(unit)); 228 break; 229 case MLX_SYSD_CRITICAL: 230 if (verbosity > 0) 231 printf("%s: critical", drivename(unit)); 232 if (status_result < 1) 233 status_result = 1; 234 break; 235 case MLX_SYSD_OFFLINE: 236 if (verbosity > 0) 237 printf("%s: offline", drivename(unit)); 238 if (status_result < 2) 239 status_result = 2; 240 break; 241 default: 242 if (verbosity > 0) { 243 printf("%s: unknown status 0x%x", drivename(unit), result); 244 } 245 } 246 if (verbosity > 0) { 247 /* rebuild/check in progress on this drive? */ 248 if (statvalid && (rs_ctrlr == ctrlr) && 249 (rs.rs_drive == sysdrive) && (rs.rs_code != MLX_REBUILDSTAT_IDLE)) { 250 switch(rs.rs_code) { 251 case MLX_REBUILDSTAT_REBUILDCHECK: 252 printf(" [consistency check"); 253 break; 254 case MLX_REBUILDSTAT_ADDCAPACITY: 255 printf(" [add capacity"); 256 break; 257 case MLX_REBUILDSTAT_ADDCAPACITYINIT: 258 printf(" [add capacity init"); 259 break; 260 default: 261 printf(" [unknown operation"); 262 } 263 printf(": %d/%d, %d%% complete]", 264 rs.rs_remaining, rs.rs_size, 265 ((rs.rs_size - rs.rs_remaining) / (rs.rs_size / 100))); 266 } 267 printf("\n"); 268 } 269 } 270 close(fd); 271 } 272 273 /******************************************************************************** 274 * Print details for the system drive (drvno) in a format that we will be 275 * able to parse later. 276 * 277 * drive?? <raidlevel> <writemode> 278 * span? 0x????????-0x???????? ????MB on <disk> [...] 279 * ... 280 */ 281 static void 282 print_span(struct mlx_sys_drv_span *span, int arms) 283 { 284 int i; 285 286 printf("0x%08x-0x%08x %uMB on", span->sp_start_lba, span->sp_start_lba + span->sp_nblks, span->sp_nblks / 2048); 287 for (i = 0; i < arms; i++) 288 printf(" disk%02d%02d", span->sp_arm[i] >> 4, span->sp_arm[i] & 0x0f); 289 printf("\n"); 290 } 291 292 static void 293 print_sys_drive(struct conf_config *conf, int drvno) 294 { 295 struct mlx_sys_drv *drv = &conf->cc_cfg.cc_sys_drives[drvno]; 296 int i; 297 298 printf("drive%02d ", drvno); 299 switch(drv->sd_raidlevel & 0xf) { 300 case MLX_SYS_DRV_RAID0: 301 printf("RAID0"); 302 break; 303 case MLX_SYS_DRV_RAID1: 304 printf("RAID1"); 305 break; 306 case MLX_SYS_DRV_RAID3: 307 printf("RAID3"); 308 break; 309 case MLX_SYS_DRV_RAID5: 310 printf("RAID5"); 311 break; 312 case MLX_SYS_DRV_RAID6: 313 printf("RAID6"); 314 break; 315 case MLX_SYS_DRV_JBOD: 316 printf("JBOD"); 317 break; 318 default: 319 printf("RAID?"); 320 } 321 printf(" write%s\n", drv->sd_raidlevel & MLX_SYS_DRV_WRITEBACK ? "back" : "through"); 322 323 for (i = 0; i < drv->sd_valid_spans; i++) { 324 printf(" span%d ", i); 325 print_span(&drv->sd_span[i], drv->sd_valid_arms); 326 } 327 } 328 329 /******************************************************************************** 330 * Print details for the physical drive at chn/targ in a format suitable for 331 * human consumption. 332 * 333 * <type>CCTT (<state>) "<vendor>/<model>" 334 * ????MB <features> 335 * 336 */ 337 static void 338 print_phys_drive(struct conf_config *conf, int chn, int targ) 339 { 340 struct mlx_phys_drv *drv = &conf->cc_cfg.cc_phys_drives[chn * 16 + targ]; 341 342 /* if the drive isn't present, don't print it */ 343 if (!(drv->pd_flags1 & MLX_PHYS_DRV_PRESENT)) 344 return; 345 346 mlx_print_phys_drv(drv, chn, targ, "# ", 1); 347 } 348 349 static struct 350 { 351 int hwid; 352 const char *name; 353 } mlx_controller_names[] = { 354 {0x01, "960P/PD"}, 355 {0x02, "960PL"}, 356 {0x10, "960PG"}, 357 {0x11, "960PJ"}, 358 {0x12, "960PR"}, 359 {0x13, "960PT"}, 360 {0x14, "960PTL0"}, 361 {0x15, "960PRL"}, 362 {0x16, "960PTL1"}, 363 {0x20, "1100PVX"}, 364 {-1, NULL} 365 }; 366 367 static void 368 controller_print(int unit, void *arg) 369 { 370 struct mlx_enquiry2 enq; 371 struct mlx_phys_drv pd; 372 int verbosity = *(int *)arg; 373 static char buf[80]; 374 const char *model; 375 int i, channel, target; 376 377 if (verbosity == 0) 378 return; 379 380 /* fetch and print controller data */ 381 if (mlx_enquiry(unit, &enq)) { 382 printf("mlx%d: error submitting ENQUIRY2\n", unit); 383 } else { 384 385 for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) { 386 if ((int)(enq.me_hardware_id & 0xff) == mlx_controller_names[i].hwid) { 387 model = mlx_controller_names[i].name; 388 break; 389 } 390 } 391 if (model == NULL) { 392 sprintf(buf, " model 0x%x", enq.me_hardware_id & 0xff); 393 model = buf; 394 } 395 396 printf("mlx%d: DAC%s, %d channel%s, firmware %d.%02d-%c-%02d, %dMB RAM\n", 397 unit, model, 398 enq.me_actual_channels, 399 enq.me_actual_channels > 1 ? "s" : "", 400 enq.me_firmware_id & 0xff, 401 (enq.me_firmware_id >> 8) & 0xff, 402 (enq.me_firmware_id >> 16), 403 (enq.me_firmware_id >> 24) & 0xff, 404 enq.me_mem_size / (1024 * 1024)); 405 406 if (verbosity > 1) { 407 printf(" Hardware ID 0x%08x\n", enq.me_hardware_id); 408 printf(" Firmware ID 0x%08x\n", enq.me_firmware_id); 409 printf(" Configured/Actual channels %d/%d\n", enq.me_configured_channels, 410 enq.me_actual_channels); 411 printf(" Max Targets %d\n", enq.me_max_targets); 412 printf(" Max Tags %d\n", enq.me_max_tags); 413 printf(" Max System Drives %d\n", enq.me_max_sys_drives); 414 printf(" Max Arms %d\n", enq.me_max_arms); 415 printf(" Max Spans %d\n", enq.me_max_spans); 416 printf(" DRAM/cache/flash/NVRAM size %d/%d/%d/%d\n", enq.me_mem_size, 417 enq.me_cache_size, enq.me_flash_size, enq.me_nvram_size); 418 printf(" DRAM type %d\n", enq.me_mem_type); 419 printf(" Clock Speed %dns\n", enq.me_clock_speed); 420 printf(" Hardware Speed %dns\n", enq.me_hardware_speed); 421 printf(" Max Commands %d\n", enq.me_max_commands); 422 printf(" Max SG Entries %d\n", enq.me_max_sg); 423 printf(" Max DP %d\n", enq.me_max_dp); 424 printf(" Max IOD %d\n", enq.me_max_iod); 425 printf(" Max Comb %d\n", enq.me_max_comb); 426 printf(" Latency %ds\n", enq.me_latency); 427 printf(" SCSI Timeout %ds\n", enq.me_scsi_timeout); 428 printf(" Min Free Lines %d\n", enq.me_min_freelines); 429 printf(" Rate Constant %d\n", enq.me_rate_const); 430 printf(" MAXBLK %d\n", enq.me_maxblk); 431 printf(" Blocking Factor %d sectors\n", enq.me_blocking_factor); 432 printf(" Cache Line Size %d blocks\n", enq.me_cacheline); 433 printf(" SCSI Capability %s%dMHz, %d bit\n", 434 enq.me_scsi_cap & (1<<4) ? "differential " : "", 435 (1 << ((enq.me_scsi_cap >> 2) & 3)) * 10, 436 8 << (enq.me_scsi_cap & 0x3)); 437 printf(" Firmware Build Number %d\n", enq.me_firmware_build); 438 printf(" Fault Management Type %d\n", enq.me_fault_mgmt_type); 439 #if 0 440 printf(" Features %b\n", enq.me_firmware_features, 441 "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n"); 442 #endif 443 } 444 445 /* fetch and print physical drive data */ 446 for (channel = 0; channel < enq.me_configured_channels; channel++) { 447 for (target = 0; target < enq.me_max_targets; target++) { 448 if ((mlx_get_device_state(unit, channel, target, &pd) == 0) && 449 (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT)) { 450 mlx_print_phys_drv(&pd, channel, target, " ", verbosity - 1); 451 if (verbosity > 1) { 452 /* XXX print device statistics? */ 453 } 454 } 455 } 456 } 457 } 458 } 459 460 static int 461 cmd_status(int argc, char *argv[]) 462 { 463 int ch, verbosity = 1, i, unit; 464 465 optreset = 1; 466 optind = 1; 467 while ((ch = getopt(argc, argv, "qv")) != -1) 468 switch(ch) { 469 case 'q': 470 verbosity = 0; 471 break; 472 case 'v': 473 verbosity = 2; 474 break; 475 default: 476 return(cmd_help(argc, argv)); 477 } 478 argc -= optind; 479 argv += optind; 480 481 if (argc < 1) { 482 mlx_foreach(controller_print, &verbosity); 483 mlxd_foreach(status_print, &verbosity); 484 } else { 485 for (i = 0; i < argc; i++) { 486 if ((unit = driveunit(argv[i])) == -1) { 487 warnx("'%s' is not a valid drive", argv[i]); 488 } else { 489 status_print(unit, &verbosity); 490 } 491 } 492 } 493 return(status_result); 494 } 495 496 /******************************************************************************** 497 * Recscan for system drives on one or more controllers. 498 * 499 * rescan <controller> [<controller>...] 500 * rescan -a 501 */ 502 static void 503 rescan_ctrlr(int unit, void *junk __unused) 504 { 505 int fd; 506 507 /* Get the device */ 508 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 509 warn("can't open %s", ctrlrpath(unit)); 510 return; 511 } 512 513 if (ioctl(fd, MLX_RESCAN_DRIVES) < 0) 514 warn("can't rescan %s", ctrlrname(unit)); 515 close(fd); 516 } 517 518 static int 519 cmd_rescan(int argc, char *argv[]) 520 { 521 int all = 0, i, ch, unit; 522 523 optreset = 1; 524 optind = 1; 525 while ((ch = getopt(argc, argv, "a")) != -1) 526 switch(ch) { 527 case 'a': 528 all = 1; 529 break; 530 default: 531 return(cmd_help(argc, argv)); 532 } 533 argc -= optind; 534 argv += optind; 535 536 if (all) { 537 mlx_foreach(rescan_ctrlr, NULL); 538 } else { 539 for (i = 0; i < argc; i++) { 540 if ((unit = ctrlrunit(argv[i])) == -1) { 541 warnx("'%s' is not a valid controller", argv[i]); 542 } else { 543 rescan_ctrlr(unit, NULL); 544 } 545 } 546 } 547 return(0); 548 } 549 550 /******************************************************************************** 551 * Detach one or more system drives from a controller. 552 * 553 * detach <drive> [<drive>...] 554 * Detach <drive>. 555 * 556 * detach -a <controller> [<controller>...] 557 * Detach all drives on <controller>. 558 * 559 */ 560 static void 561 detach_drive(int unit, void *arg __unused) 562 { 563 int fd; 564 565 /* Get the device */ 566 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 567 warn("can't open %s", ctrlrpath(unit)); 568 return; 569 } 570 571 if (ioctl(fd, MLX_DETACH_DRIVE, &unit) < 0) 572 warn("can't detach %s", drivename(unit)); 573 close(fd); 574 } 575 576 static int 577 cmd_detach(int argc, char *argv[]) 578 { 579 struct mlxd_foreach_action ma; 580 int all = 0, i, ch, unit; 581 582 optreset = 1; 583 optind = 1; 584 while ((ch = getopt(argc, argv, "a")) != -1) 585 switch(ch) { 586 case 'a': 587 all = 1; 588 break; 589 default: 590 return(cmd_help(argc, argv)); 591 } 592 argc -= optind; 593 argv += optind; 594 595 if (all) { 596 ma.func = detach_drive; 597 ma.arg = &unit; 598 for (i = 0; i < argc; i++) { 599 if ((unit = ctrlrunit(argv[i])) == -1) { 600 warnx("'%s' is not a valid controller", argv[i]); 601 } else { 602 mlxd_foreach_ctrlr(unit, &ma); 603 } 604 } 605 } else { 606 for (i = 0; i < argc; i++) { 607 if ((unit = driveunit(argv[i])) == -1) { 608 warnx("'%s' is not a valid drive", argv[i]); 609 } else { 610 /* run across all controllers to find this drive */ 611 mlx_foreach(detach_drive, &unit); 612 } 613 } 614 } 615 return(0); 616 } 617 618 /******************************************************************************** 619 * Initiate a consistency check on a system drive. 620 * 621 * check [<drive>] 622 * Start a check of <drive> 623 * 624 */ 625 static int 626 cmd_check(int argc, char *argv[]) 627 { 628 int unit, fd, result; 629 630 if (argc != 2) 631 return(cmd_help(argc, argv)); 632 633 if ((unit = driveunit(argv[1])) == -1) { 634 warnx("'%s' is not a valid drive", argv[1]); 635 } else { 636 637 /* Get the device */ 638 if ((fd = open(drivepath(unit), 0)) < 0) { 639 warn("can't open %s", drivepath(unit)); 640 } else { 641 /* Try to start the check */ 642 if ((ioctl(fd, MLXD_CHECKASYNC, &result)) < 0) { 643 switch(result) { 644 case 0x0002: 645 warnx("one or more of the SCSI disks on which the drive '%s' depends is DEAD", argv[1]); 646 break; 647 case 0x0105: 648 warnx("drive %s is invalid, or not a drive which can be checked", argv[1]); 649 break; 650 case 0x0106: 651 warnx("drive rebuild or consistency check is already in progress on this controller"); 652 break; 653 default: 654 warn("ioctl MLXD_CHECKASYNC"); 655 } 656 } 657 } 658 } 659 return(0); 660 } 661 662 /******************************************************************************** 663 * Initiate a physical drive rebuild 664 * 665 * rebuild <controller> <channel>:<target> 666 * Start a rebuild of <controller>:<channel>:<target> 667 * 668 */ 669 static int 670 cmd_rebuild(int argc, char *argv[]) 671 { 672 struct mlx_rebuild_request rb; 673 int unit, fd; 674 675 if (argc != 3) 676 return(cmd_help(argc, argv)); 677 678 /* parse arguments */ 679 if ((unit = ctrlrunit(argv[1])) == -1) { 680 warnx("'%s' is not a valid controller", argv[1]); 681 return(1); 682 } 683 /* try diskXXXX and unknownXXXX as we report the latter for a dead drive ... */ 684 if ((sscanf(argv[2], "disk%2d%2d", &rb.rr_channel, &rb.rr_target) != 2) && 685 (sscanf(argv[2], "unknown%2d%2d", &rb.rr_channel, &rb.rr_target) != 2)) { 686 warnx("'%s' is not a valid physical drive", argv[2]); 687 return(1); 688 } 689 /* get the device */ 690 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 691 warn("can't open %s", ctrlrpath(unit)); 692 return(1); 693 } 694 /* try to start the rebuild */ 695 if ((ioctl(fd, MLX_REBUILDASYNC, &rb)) < 0) { 696 switch(rb.rr_status) { 697 case 0x0002: 698 warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, rb.rr_target); 699 break; 700 case 0x0004: 701 warnx("drive failed during rebuild"); 702 break; 703 case 0x0105: 704 warnx("there is no drive at channel %d, target %d", rb.rr_channel, rb.rr_target); 705 break; 706 case 0x0106: 707 warnx("drive rebuild or consistency check is already in progress on this controller"); 708 break; 709 default: 710 warn("ioctl MLXD_REBUILDASYNC"); 711 } 712 } 713 return(0); 714 } 715 716 /******************************************************************************** 717 * Get the configuration from the selected controller. 718 * 719 * config <controller> 720 * Print the configuration for <controller> 721 * 722 * XXX update to support adding/deleting drives. 723 */ 724 725 int 726 cmd_config(int argc __unused, char *argv[] __unused) 727 { 728 struct conf_config conf; 729 int unit = 0; /* XXX */ 730 int i, j; 731 732 bzero(&conf.cc_cfg, sizeof(conf.cc_cfg)); 733 if (mlx_read_configuration(unit, &conf.cc_cfg)) { 734 printf("mlx%d: error submitting READ CONFIGURATION\n", unit); 735 } else { 736 737 printf("# Controller <INSERT DETAILS HERE>\n"); 738 printf("#\n# Physical devices connected:\n"); 739 for (i = 0; i < 5; i++) 740 for (j = 0; j < 16; j++) 741 print_phys_drive(&conf, i, j); 742 printf("#\n# System Drives defined:\n"); 743 744 for (i = 0; i < conf.cc_cfg.cc_num_sys_drives; i++) 745 print_sys_drive(&conf, i); 746 } 747 return(0); 748 } 749 750 #ifdef SUPPORT_PAUSE 751 /******************************************************************************** 752 * Pause one or more channels on a controller 753 * 754 * pause [-d <delay>] [-t <time>] <controller> [<channel>...] 755 * Pauses <channel> (or all channels) for <time> seconds after a 756 * delay of <delay> seconds. 757 * pause <controller> -c 758 * Cancels pending pause 759 */ 760 static int 761 cmd_pause(int argc, char *argv[]) 762 { 763 struct mlx_pause mp; 764 int unit, i, ch, fd, cancel = 0; 765 char *cp; 766 int oargc = argc; 767 char **oargv = argv; 768 769 mp.mp_which = 0; 770 mp.mp_when = 30; 771 mp.mp_howlong = 30; 772 optreset = 1; 773 optind = 1; 774 while ((ch = getopt(argc, argv, "cd:t:")) != -1) 775 switch(ch) { 776 case 'c': 777 cancel = 1; 778 break; 779 case 'd': 780 mp.mp_when = strtol(optarg, &cp, 0); 781 if (*cp != 0) 782 return(cmd_help(argc, argv)); 783 break; 784 case 't': 785 mp.mp_howlong = strtol(optarg, &cp, 0); 786 if (*cp != 0) 787 return(cmd_help(argc, argv)); 788 break; 789 default: 790 return(cmd_help(argc, argv)); 791 } 792 argc -= optind; 793 argv += optind; 794 795 /* get controller unit number that we're working on */ 796 if ((argc < 1) || ((unit = ctrlrunit(argv[0])) == -1)) 797 return(cmd_help(oargc, oargv)); 798 799 /* Get the device */ 800 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 801 warn("can't open %s", ctrlrpath(unit)); 802 return(1); 803 } 804 805 if (argc == 1) { 806 /* controller-wide pause/cancel */ 807 mp.mp_which = cancel ? MLX_PAUSE_CANCEL : MLX_PAUSE_ALL; 808 } else { 809 for (i = 1; i < argc; i++) { 810 ch = strtol(argv[i], &cp, 0); 811 if (*cp != 0) { 812 warnx("bad channel number '%s'", argv[i]); 813 continue; 814 } else { 815 mp.mp_which |= (1 << ch); 816 } 817 } 818 } 819 if ((ioctl(fd, MLX_PAUSE_CHANNEL, &mp)) < 0) 820 warn("couldn't %s %s", cancel ? "cancel pause on" : "pause", ctrlrname(unit)); 821 close(fd); 822 return(0); 823 } 824 #endif /* SUPPORT_PAUSE */ 825 826