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 %pb%i\n", 441 "\20\4Background Init\3Read Ahead\2MORE\1Cluster\n", 442 enq.me_firmware_features); 443 #endif 444 } 445 446 /* fetch and print physical drive data */ 447 for (channel = 0; channel < enq.me_configured_channels; channel++) { 448 for (target = 0; target < enq.me_max_targets; target++) { 449 if ((mlx_get_device_state(unit, channel, target, &pd) == 0) && 450 (pd.pd_flags1 & MLX_PHYS_DRV_PRESENT)) { 451 mlx_print_phys_drv(&pd, channel, target, " ", verbosity - 1); 452 if (verbosity > 1) { 453 /* XXX print device statistics? */ 454 } 455 } 456 } 457 } 458 } 459 } 460 461 static int 462 cmd_status(int argc, char *argv[]) 463 { 464 int ch, verbosity = 1, i, unit; 465 466 optreset = 1; 467 optind = 1; 468 while ((ch = getopt(argc, argv, "qv")) != -1) 469 switch(ch) { 470 case 'q': 471 verbosity = 0; 472 break; 473 case 'v': 474 verbosity = 2; 475 break; 476 default: 477 return(cmd_help(argc, argv)); 478 } 479 argc -= optind; 480 argv += optind; 481 482 if (argc < 1) { 483 mlx_foreach(controller_print, &verbosity); 484 mlxd_foreach(status_print, &verbosity); 485 } else { 486 for (i = 0; i < argc; i++) { 487 if ((unit = driveunit(argv[i])) == -1) { 488 warnx("'%s' is not a valid drive", argv[i]); 489 } else { 490 status_print(unit, &verbosity); 491 } 492 } 493 } 494 return(status_result); 495 } 496 497 /******************************************************************************** 498 * Recscan for system drives on one or more controllers. 499 * 500 * rescan <controller> [<controller>...] 501 * rescan -a 502 */ 503 static void 504 rescan_ctrlr(int unit, void *junk __unused) 505 { 506 int fd; 507 508 /* Get the device */ 509 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 510 warn("can't open %s", ctrlrpath(unit)); 511 return; 512 } 513 514 if (ioctl(fd, MLX_RESCAN_DRIVES) < 0) 515 warn("can't rescan %s", ctrlrname(unit)); 516 close(fd); 517 } 518 519 static int 520 cmd_rescan(int argc, char *argv[]) 521 { 522 int all = 0, i, ch, unit; 523 524 optreset = 1; 525 optind = 1; 526 while ((ch = getopt(argc, argv, "a")) != -1) 527 switch(ch) { 528 case 'a': 529 all = 1; 530 break; 531 default: 532 return(cmd_help(argc, argv)); 533 } 534 argc -= optind; 535 argv += optind; 536 537 if (all) { 538 mlx_foreach(rescan_ctrlr, NULL); 539 } else { 540 for (i = 0; i < argc; i++) { 541 if ((unit = ctrlrunit(argv[i])) == -1) { 542 warnx("'%s' is not a valid controller", argv[i]); 543 } else { 544 rescan_ctrlr(unit, NULL); 545 } 546 } 547 } 548 return(0); 549 } 550 551 /******************************************************************************** 552 * Detach one or more system drives from a controller. 553 * 554 * detach <drive> [<drive>...] 555 * Detach <drive>. 556 * 557 * detach -a <controller> [<controller>...] 558 * Detach all drives on <controller>. 559 * 560 */ 561 static void 562 detach_drive(int unit, void *arg __unused) 563 { 564 int fd; 565 566 /* Get the device */ 567 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 568 warn("can't open %s", ctrlrpath(unit)); 569 return; 570 } 571 572 if (ioctl(fd, MLX_DETACH_DRIVE, &unit) < 0) 573 warn("can't detach %s", drivename(unit)); 574 close(fd); 575 } 576 577 static int 578 cmd_detach(int argc, char *argv[]) 579 { 580 struct mlxd_foreach_action ma; 581 int all = 0, i, ch, unit; 582 583 optreset = 1; 584 optind = 1; 585 while ((ch = getopt(argc, argv, "a")) != -1) 586 switch(ch) { 587 case 'a': 588 all = 1; 589 break; 590 default: 591 return(cmd_help(argc, argv)); 592 } 593 argc -= optind; 594 argv += optind; 595 596 if (all) { 597 ma.func = detach_drive; 598 ma.arg = &unit; 599 for (i = 0; i < argc; i++) { 600 if ((unit = ctrlrunit(argv[i])) == -1) { 601 warnx("'%s' is not a valid controller", argv[i]); 602 } else { 603 mlxd_foreach_ctrlr(unit, &ma); 604 } 605 } 606 } else { 607 for (i = 0; i < argc; i++) { 608 if ((unit = driveunit(argv[i])) == -1) { 609 warnx("'%s' is not a valid drive", argv[i]); 610 } else { 611 /* run across all controllers to find this drive */ 612 mlx_foreach(detach_drive, &unit); 613 } 614 } 615 } 616 return(0); 617 } 618 619 /******************************************************************************** 620 * Initiate a consistency check on a system drive. 621 * 622 * check [<drive>] 623 * Start a check of <drive> 624 * 625 */ 626 static int 627 cmd_check(int argc, char *argv[]) 628 { 629 int unit, fd, result; 630 631 if (argc != 2) 632 return(cmd_help(argc, argv)); 633 634 if ((unit = driveunit(argv[1])) == -1) { 635 warnx("'%s' is not a valid drive", argv[1]); 636 } else { 637 638 /* Get the device */ 639 if ((fd = open(drivepath(unit), 0)) < 0) { 640 warn("can't open %s", drivepath(unit)); 641 } else { 642 /* Try to start the check */ 643 if ((ioctl(fd, MLXD_CHECKASYNC, &result)) < 0) { 644 switch(result) { 645 case 0x0002: 646 warnx("one or more of the SCSI disks on which the drive '%s' depends is DEAD", argv[1]); 647 break; 648 case 0x0105: 649 warnx("drive %s is invalid, or not a drive which can be checked", argv[1]); 650 break; 651 case 0x0106: 652 warnx("drive rebuild or consistency check is already in progress on this controller"); 653 break; 654 default: 655 warn("ioctl MLXD_CHECKASYNC"); 656 } 657 } 658 } 659 } 660 return(0); 661 } 662 663 /******************************************************************************** 664 * Initiate a physical drive rebuild 665 * 666 * rebuild <controller> <channel>:<target> 667 * Start a rebuild of <controller>:<channel>:<target> 668 * 669 */ 670 static int 671 cmd_rebuild(int argc, char *argv[]) 672 { 673 struct mlx_rebuild_request rb; 674 int unit, fd; 675 676 if (argc != 3) 677 return(cmd_help(argc, argv)); 678 679 /* parse arguments */ 680 if ((unit = ctrlrunit(argv[1])) == -1) { 681 warnx("'%s' is not a valid controller", argv[1]); 682 return(1); 683 } 684 /* try diskXXXX and unknownXXXX as we report the latter for a dead drive ... */ 685 if ((sscanf(argv[2], "disk%2d%2d", &rb.rr_channel, &rb.rr_target) != 2) && 686 (sscanf(argv[2], "unknown%2d%2d", &rb.rr_channel, &rb.rr_target) != 2)) { 687 warnx("'%s' is not a valid physical drive", argv[2]); 688 return(1); 689 } 690 /* get the device */ 691 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 692 warn("can't open %s", ctrlrpath(unit)); 693 return(1); 694 } 695 /* try to start the rebuild */ 696 if ((ioctl(fd, MLX_REBUILDASYNC, &rb)) < 0) { 697 switch(rb.rr_status) { 698 case 0x0002: 699 warnx("the drive at %d:%d is already ONLINE", rb.rr_channel, rb.rr_target); 700 break; 701 case 0x0004: 702 warnx("drive failed during rebuild"); 703 break; 704 case 0x0105: 705 warnx("there is no drive at channel %d, target %d", rb.rr_channel, rb.rr_target); 706 break; 707 case 0x0106: 708 warnx("drive rebuild or consistency check is already in progress on this controller"); 709 break; 710 default: 711 warn("ioctl MLXD_REBUILDASYNC"); 712 } 713 } 714 return(0); 715 } 716 717 /******************************************************************************** 718 * Get the configuration from the selected controller. 719 * 720 * config <controller> 721 * Print the configuration for <controller> 722 * 723 * XXX update to support adding/deleting drives. 724 */ 725 726 int 727 cmd_config(int argc __unused, char *argv[] __unused) 728 { 729 struct conf_config conf; 730 int unit = 0; /* XXX */ 731 int i, j; 732 733 bzero(&conf.cc_cfg, sizeof(conf.cc_cfg)); 734 if (mlx_read_configuration(unit, &conf.cc_cfg)) { 735 printf("mlx%d: error submitting READ CONFIGURATION\n", unit); 736 } else { 737 738 printf("# Controller <INSERT DETAILS HERE>\n"); 739 printf("#\n# Physical devices connected:\n"); 740 for (i = 0; i < 5; i++) 741 for (j = 0; j < 16; j++) 742 print_phys_drive(&conf, i, j); 743 printf("#\n# System Drives defined:\n"); 744 745 for (i = 0; i < conf.cc_cfg.cc_num_sys_drives; i++) 746 print_sys_drive(&conf, i); 747 } 748 return(0); 749 } 750 751 #ifdef SUPPORT_PAUSE 752 /******************************************************************************** 753 * Pause one or more channels on a controller 754 * 755 * pause [-d <delay>] [-t <time>] <controller> [<channel>...] 756 * Pauses <channel> (or all channels) for <time> seconds after a 757 * delay of <delay> seconds. 758 * pause <controller> -c 759 * Cancels pending pause 760 */ 761 static int 762 cmd_pause(int argc, char *argv[]) 763 { 764 struct mlx_pause mp; 765 int unit, i, ch, fd, cancel = 0; 766 char *cp; 767 int oargc = argc; 768 char **oargv = argv; 769 770 mp.mp_which = 0; 771 mp.mp_when = 30; 772 mp.mp_howlong = 30; 773 optreset = 1; 774 optind = 1; 775 while ((ch = getopt(argc, argv, "cd:t:")) != -1) 776 switch(ch) { 777 case 'c': 778 cancel = 1; 779 break; 780 case 'd': 781 mp.mp_when = strtol(optarg, &cp, 0); 782 if (*cp != 0) 783 return(cmd_help(argc, argv)); 784 break; 785 case 't': 786 mp.mp_howlong = strtol(optarg, &cp, 0); 787 if (*cp != 0) 788 return(cmd_help(argc, argv)); 789 break; 790 default: 791 return(cmd_help(argc, argv)); 792 } 793 argc -= optind; 794 argv += optind; 795 796 /* get controller unit number that we're working on */ 797 if ((argc < 1) || ((unit = ctrlrunit(argv[0])) == -1)) 798 return(cmd_help(oargc, oargv)); 799 800 /* Get the device */ 801 if ((fd = open(ctrlrpath(unit), 0)) < 0) { 802 warn("can't open %s", ctrlrpath(unit)); 803 return(1); 804 } 805 806 if (argc == 1) { 807 /* controller-wide pause/cancel */ 808 mp.mp_which = cancel ? MLX_PAUSE_CANCEL : MLX_PAUSE_ALL; 809 } else { 810 for (i = 1; i < argc; i++) { 811 ch = strtol(argv[i], &cp, 0); 812 if (*cp != 0) { 813 warnx("bad channel number '%s'", argv[i]); 814 continue; 815 } else { 816 mp.mp_which |= (1 << ch); 817 } 818 } 819 } 820 if ((ioctl(fd, MLX_PAUSE_CHANNEL, &mp)) < 0) 821 warn("couldn't %s %s", cancel ? "cancel pause on" : "pause", ctrlrname(unit)); 822 close(fd); 823 return(0); 824 } 825 #endif /* SUPPORT_PAUSE */ 826 827