1 /*- 2 * Copyright (c) 2008, 2009 Yahoo!, Inc. 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 * 3. The names of the authors may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/errno.h> 34 #include <err.h> 35 #include <libutil.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include "mfiutil.h" 41 42 MFI_TABLE(top, show); 43 44 static void 45 format_stripe(char *buf, size_t buflen, uint8_t stripe) 46 { 47 48 humanize_number(buf, buflen, (1 << stripe) * 512, "", HN_AUTOSCALE, 49 HN_B | HN_NOSPACE); 50 } 51 52 static int 53 show_adapter(int ac, char **av) 54 { 55 struct mfi_ctrl_info info; 56 char stripe[5]; 57 int error, fd, comma; 58 59 if (ac != 1) { 60 warnx("show adapter: extra arguments"); 61 return (EINVAL); 62 } 63 64 fd = mfi_open(mfi_unit); 65 if (fd < 0) { 66 error = errno; 67 warn("mfi_open"); 68 return (error); 69 } 70 71 if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 72 error = errno; 73 warn("Failed to get controller info"); 74 close(fd); 75 return (error); 76 } 77 printf("mfi%d Adapter:\n", mfi_unit); 78 printf(" Product Name: %.80s\n", info.product_name); 79 printf(" Serial Number: %.32s\n", info.serial_number); 80 if (info.package_version[0] != '\0') 81 printf(" Firmware: %s\n", info.package_version); 82 printf(" RAID Levels:"); 83 #ifdef DEBUG 84 printf(" (%#x)", info.raid_levels); 85 #endif 86 comma = 0; 87 if (info.raid_levels & MFI_INFO_RAID_0) { 88 printf(" JBOD, RAID0"); 89 comma = 1; 90 } 91 if (info.raid_levels & MFI_INFO_RAID_1) { 92 printf("%s RAID1", comma ? "," : ""); 93 comma = 1; 94 } 95 if (info.raid_levels & MFI_INFO_RAID_5) { 96 printf("%s RAID5", comma ? "," : ""); 97 comma = 1; 98 } 99 if (info.raid_levels & MFI_INFO_RAID_1E) { 100 printf("%s RAID1E", comma ? "," : ""); 101 comma = 1; 102 } 103 if (info.raid_levels & MFI_INFO_RAID_6) { 104 printf("%s RAID6", comma ? "," : ""); 105 comma = 1; 106 } 107 if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) == 108 (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) { 109 printf("%s RAID10", comma ? "," : ""); 110 comma = 1; 111 } 112 if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) == 113 (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) { 114 printf("%s RAID50", comma ? "," : ""); 115 comma = 1; 116 } 117 printf("\n"); 118 printf(" Battery Backup: "); 119 if (info.hw_present & MFI_INFO_HW_BBU) 120 printf("present\n"); 121 else 122 printf("not present\n"); 123 if (info.hw_present & MFI_INFO_HW_NVRAM) 124 printf(" NVRAM: %uK\n", info.nvram_size); 125 printf(" Onboard Memory: %uM\n", info.memory_size); 126 format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.min); 127 printf(" Minimum Stripe: %s\n", stripe); 128 format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.max); 129 printf(" Maximum Stripe: %s\n", stripe); 130 131 close(fd); 132 133 return (0); 134 } 135 MFI_COMMAND(show, adapter, show_adapter); 136 137 static int 138 show_battery(int ac, char **av) 139 { 140 struct mfi_bbu_capacity_info cap; 141 struct mfi_bbu_design_info design; 142 struct mfi_bbu_status stat; 143 uint8_t status; 144 int comma, error, fd; 145 146 if (ac != 1) { 147 warnx("show battery: extra arguments"); 148 return (EINVAL); 149 } 150 151 fd = mfi_open(mfi_unit); 152 if (fd < 0) { 153 error = errno; 154 warn("mfi_open"); 155 return (error); 156 } 157 158 if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_CAPACITY_INFO, &cap, 159 sizeof(cap), NULL, 0, &status) < 0) { 160 if (status == MFI_STAT_NO_HW_PRESENT) { 161 printf("mfi%d: No battery present\n", mfi_unit); 162 close(fd); 163 return (0); 164 } 165 error = errno; 166 warn("Failed to get capacity info"); 167 close(fd); 168 return (error); 169 } 170 171 if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_DESIGN_INFO, &design, 172 sizeof(design), NULL, 0, NULL) < 0) { 173 error = errno; 174 warn("Failed to get design info"); 175 close(fd); 176 return (error); 177 } 178 179 if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_STATUS, &stat, sizeof(stat), 180 NULL, 0, NULL) < 0) { 181 error = errno; 182 warn("Failed to get status"); 183 close(fd); 184 return (error); 185 } 186 187 printf("mfi%d: Battery State:\n", mfi_unit); 188 printf(" Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f, 189 design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff); 190 printf(" Serial Number: %d\n", design.serial_number); 191 printf(" Manufacturer: %s\n", design.mfg_name); 192 printf(" Model: %s\n", design.device_name); 193 printf(" Chemistry: %s\n", design.device_chemistry); 194 printf(" Design Capacity: %d mAh\n", design.design_capacity); 195 printf(" Full Charge Capacity: %d mAh\n", cap.full_charge_capacity); 196 printf(" Current Capacity: %d mAh\n", cap.remaining_capacity); 197 printf(" Charge Cycles: %d\n", cap.cycle_count); 198 printf(" Current Charge: %d%%\n", cap.relative_charge); 199 printf(" Design Voltage: %d mV\n", design.design_voltage); 200 printf(" Current Voltage: %d mV\n", stat.voltage); 201 printf(" Temperature: %d C\n", stat.temperature); 202 printf(" Status:"); 203 comma = 0; 204 if (stat.fw_status & MFI_BBU_STATE_PACK_MISSING) { 205 printf(" PACK_MISSING"); 206 comma = 1; 207 } 208 if (stat.fw_status & MFI_BBU_STATE_VOLTAGE_LOW) { 209 printf("%s VOLTAGE_LOW", comma ? "," : ""); 210 comma = 1; 211 } 212 if (stat.fw_status & MFI_BBU_STATE_TEMPERATURE_HIGH) { 213 printf("%s TEMPERATURE_HIGH", comma ? "," : ""); 214 comma = 1; 215 } 216 if (stat.fw_status & MFI_BBU_STATE_CHARGE_ACTIVE) { 217 printf("%s CHARGING", comma ? "," : ""); 218 comma = 1; 219 } 220 if (stat.fw_status & MFI_BBU_STATE_DISCHARGE_ACTIVE) { 221 printf("%s DISCHARGING", comma ? "," : ""); 222 } 223 if (!comma) 224 printf(" normal"); 225 printf("\n"); 226 switch (stat.battery_type) { 227 case MFI_BBU_TYPE_BBU: 228 printf(" State of Health: %s\n", 229 stat.detail.bbu.is_SOH_good ? "good" : "bad"); 230 break; 231 } 232 233 close(fd); 234 235 return (0); 236 } 237 MFI_COMMAND(show, battery, show_battery); 238 239 static void 240 print_ld(struct mfi_ld_info *info, int state_len) 241 { 242 struct mfi_ld_params *params = &info->ld_config.params; 243 const char *level; 244 char size[6], stripe[5]; 245 246 humanize_number(size, sizeof(size), info->size * 512, 247 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 248 format_stripe(stripe, sizeof(stripe), 249 info->ld_config.params.stripe_size); 250 level = mfi_raid_level(params->primary_raid_level, 251 params->secondary_raid_level); 252 if (state_len > 0) 253 printf("(%6s) %-8s %6s %-*s", size, level, stripe, state_len, 254 mfi_ldstate(params->state)); 255 else 256 printf("(%s) %s %s %s", size, level, stripe, 257 mfi_ldstate(params->state)); 258 } 259 260 static void 261 print_pd(struct mfi_pd_info *info, int state_len, int location) 262 { 263 const char *s; 264 char buf[6]; 265 266 humanize_number(buf, sizeof(buf), info->raw_size * 512, "", 267 HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL); 268 printf("(%6s) ", buf); 269 if (state_len > 0) 270 printf("%-*s", state_len, mfi_pdstate(info->fw_state)); 271 else 272 printf("%s", mfi_pdstate(info->fw_state)); 273 s = mfi_pd_inq_string(info); 274 if (s != NULL) 275 printf(" %s", s); 276 if (!location) 277 return; 278 if (info->encl_device_id == 0xffff) 279 printf(" slot %d", info->slot_number); 280 else if (info->encl_device_id == info->ref.v.device_id) 281 printf(" enclosure %d", info->encl_index); 282 else 283 printf(" enclosure %d, slot %d", info->encl_index, 284 info->slot_number); 285 } 286 287 static int 288 show_config(int ac, char **av) 289 { 290 struct mfi_config_data *config; 291 struct mfi_array *ar; 292 struct mfi_ld_config *ld; 293 struct mfi_spare *sp; 294 struct mfi_ld_info linfo; 295 struct mfi_pd_info pinfo; 296 uint16_t device_id; 297 char *p; 298 int error, fd, i, j; 299 300 if (ac != 1) { 301 warnx("show config: extra arguments"); 302 return (EINVAL); 303 } 304 305 fd = mfi_open(mfi_unit); 306 if (fd < 0) { 307 error = errno; 308 warn("mfi_open"); 309 return (error); 310 } 311 312 /* Get the config from the controller. */ 313 if (mfi_config_read(fd, &config) < 0) { 314 error = errno; 315 warn("Failed to get config"); 316 close(fd); 317 return (error); 318 } 319 320 /* Dump out the configuration. */ 321 printf("mfi%d Configuration: %d arrays, %d volumes, %d spares\n", 322 mfi_unit, config->array_count, config->log_drv_count, 323 config->spares_count); 324 p = (char *)config->array; 325 326 for (i = 0; i < config->array_count; i++) { 327 ar = (struct mfi_array *)p; 328 printf(" array %u of %u drives:\n", ar->array_ref, 329 ar->num_drives); 330 for (j = 0; j < ar->num_drives; j++) { 331 device_id = ar->pd[j].ref.v.device_id; 332 if (device_id == 0xffff) 333 printf(" drive MISSING\n"); 334 else { 335 printf(" drive %u ", device_id); 336 if (mfi_pd_get_info(fd, device_id, &pinfo, 337 NULL) < 0) 338 printf("%s", 339 mfi_pdstate(ar->pd[j].fw_state)); 340 else 341 print_pd(&pinfo, -1, 1); 342 printf("\n"); 343 } 344 } 345 p += config->array_size; 346 } 347 348 for (i = 0; i < config->log_drv_count; i++) { 349 ld = (struct mfi_ld_config *)p; 350 printf(" volume %s ", 351 mfi_volume_name(fd, ld->properties.ld.v.target_id)); 352 if (mfi_ld_get_info(fd, ld->properties.ld.v.target_id, &linfo, 353 NULL) < 0) { 354 printf("%s %s", 355 mfi_raid_level(ld->params.primary_raid_level, 356 ld->params.secondary_raid_level), 357 mfi_ldstate(ld->params.state)); 358 } else 359 print_ld(&linfo, -1); 360 if (ld->properties.name[0] != '\0') 361 printf(" <%s>", ld->properties.name); 362 printf(" spans:\n"); 363 for (j = 0; j < ld->params.span_depth; j++) 364 printf(" array %u\n", ld->span[j].array_ref); 365 p += config->log_drv_size; 366 } 367 368 for (i = 0; i < config->spares_count; i++) { 369 sp = (struct mfi_spare *)p; 370 printf(" %s spare %u ", 371 sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : 372 "global", sp->ref.v.device_id); 373 if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0) 374 printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); 375 else 376 print_pd(&pinfo, -1, 1); 377 if (sp->spare_type & MFI_SPARE_DEDICATED) { 378 printf(" backs:\n"); 379 for (j = 0; j < sp->array_count; j++) 380 printf(" array %u\n", sp->array_ref[j]); 381 } else 382 printf("\n"); 383 p += config->spares_size; 384 } 385 free(config); 386 close(fd); 387 388 return (0); 389 } 390 MFI_COMMAND(show, config, show_config); 391 392 static int 393 show_volumes(int ac, char **av) 394 { 395 struct mfi_ld_list list; 396 struct mfi_ld_info info; 397 int error, fd; 398 u_int i, len, state_len; 399 400 if (ac != 1) { 401 warnx("show volumes: extra arguments"); 402 return (EINVAL); 403 } 404 405 fd = mfi_open(mfi_unit); 406 if (fd < 0) { 407 error = errno; 408 warn("mfi_open"); 409 return (error); 410 } 411 412 /* Get the logical drive list from the controller. */ 413 if (mfi_ld_get_list(fd, &list, NULL) < 0) { 414 error = errno; 415 warn("Failed to get volume list"); 416 close(fd); 417 return (error); 418 } 419 420 /* List the volumes. */ 421 printf("mfi%d Volumes:\n", mfi_unit); 422 state_len = strlen("State"); 423 for (i = 0; i < list.ld_count; i++) { 424 len = strlen(mfi_ldstate(list.ld_list[i].state)); 425 if (len > state_len) 426 state_len = len; 427 } 428 printf(" Id Size Level Stripe "); 429 len = state_len - strlen("State"); 430 for (i = 0; i < (len + 1) / 2; i++) 431 printf(" "); 432 printf("State"); 433 for (i = 0; i < len / 2; i++) 434 printf(" "); 435 printf(" Cache Name\n"); 436 for (i = 0; i < list.ld_count; i++) { 437 if (mfi_ld_get_info(fd, list.ld_list[i].ld.v.target_id, &info, 438 NULL) < 0) { 439 error = errno; 440 warn("Failed to get info for volume %d", 441 list.ld_list[i].ld.v.target_id); 442 close(fd); 443 return (error); 444 } 445 printf("%6s ", 446 mfi_volume_name(fd, list.ld_list[i].ld.v.target_id)); 447 print_ld(&info, state_len); 448 switch (info.ld_config.properties.current_cache_policy & 449 (MR_LD_CACHE_ALLOW_WRITE_CACHE | 450 MR_LD_CACHE_ALLOW_READ_CACHE)) { 451 case 0: 452 printf(" Disabled"); 453 break; 454 case MR_LD_CACHE_ALLOW_READ_CACHE: 455 printf(" Reads "); 456 break; 457 case MR_LD_CACHE_ALLOW_WRITE_CACHE: 458 printf(" Writes "); 459 break; 460 case MR_LD_CACHE_ALLOW_WRITE_CACHE | 461 MR_LD_CACHE_ALLOW_READ_CACHE: 462 printf(" Enabled "); 463 break; 464 } 465 if (info.ld_config.properties.name[0] != '\0') 466 printf(" <%s>", info.ld_config.properties.name); 467 printf("\n"); 468 } 469 close(fd); 470 471 return (0); 472 } 473 MFI_COMMAND(show, volumes, show_volumes); 474 475 static int 476 show_drives(int ac, char **av) 477 { 478 struct mfi_pd_list *list; 479 struct mfi_pd_info info; 480 u_int i, len, state_len; 481 int error, fd; 482 483 if (ac != 1) { 484 warnx("show drives: extra arguments"); 485 return (EINVAL); 486 } 487 488 fd = mfi_open(mfi_unit); 489 if (fd < 0) { 490 error = errno; 491 warn("mfi_open"); 492 return (error); 493 } 494 495 list = NULL; 496 if (mfi_pd_get_list(fd, &list, NULL) < 0) { 497 error = errno; 498 warn("Failed to get drive list"); 499 goto error; 500 } 501 502 /* Walk the list of drives to determine width of state column. */ 503 state_len = 0; 504 for (i = 0; i < list->count; i++) { 505 if (list->addr[i].scsi_dev_type != 0) 506 continue; 507 508 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 509 NULL) < 0) { 510 error = errno; 511 warn("Failed to fetch info for drive %u", 512 list->addr[i].device_id); 513 goto error; 514 } 515 len = strlen(mfi_pdstate(info.fw_state)); 516 if (len > state_len) 517 state_len = len; 518 } 519 520 /* List the drives. */ 521 printf("mfi%d Physical Drives:\n", mfi_unit); 522 for (i = 0; i < list->count; i++) { 523 524 /* Skip non-hard disks. */ 525 if (list->addr[i].scsi_dev_type != 0) 526 continue; 527 528 /* Fetch details for this drive. */ 529 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 530 NULL) < 0) { 531 error = errno; 532 warn("Failed to fetch info for drive %u", 533 list->addr[i].device_id); 534 goto error; 535 } 536 537 print_pd(&info, state_len, 1); 538 printf("\n"); 539 } 540 error: 541 free(list); 542 close(fd); 543 544 return (error); 545 } 546 MFI_COMMAND(show, drives, show_drives); 547 548 int fw_name_width, fw_version_width, fw_date_width, fw_time_width; 549 550 static void 551 scan_firmware(struct mfi_info_component *comp) 552 { 553 int len; 554 555 len = strlen(comp->name); 556 if (fw_name_width < len) 557 fw_name_width = len; 558 len = strlen(comp->version); 559 if (fw_version_width < len) 560 fw_version_width = len; 561 len = strlen(comp->build_date); 562 if (fw_date_width < len) 563 fw_date_width = len; 564 len = strlen(comp->build_time); 565 if (fw_time_width < len) 566 fw_time_width = len; 567 } 568 569 static void 570 display_firmware(struct mfi_info_component *comp, const char *tag) 571 { 572 573 printf("%-*s %-*s %-*s %-*s %s\n", fw_name_width, comp->name, 574 fw_version_width, comp->version, fw_date_width, comp->build_date, 575 fw_time_width, comp->build_time, tag); 576 } 577 578 static int 579 show_firmware(int ac, char **av) 580 { 581 struct mfi_ctrl_info info; 582 struct mfi_info_component header; 583 int error, fd; 584 u_int i; 585 586 if (ac != 1) { 587 warnx("show firmware: extra arguments"); 588 return (EINVAL); 589 } 590 591 fd = mfi_open(mfi_unit); 592 if (fd < 0) { 593 error = errno; 594 warn("mfi_open"); 595 return (error); 596 } 597 598 if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 599 error = errno; 600 warn("Failed to get controller info"); 601 close(fd); 602 return (error); 603 } 604 605 if (info.package_version[0] != '\0') 606 printf("mfi%d Firmware Package Version: %s\n", mfi_unit, 607 info.package_version); 608 printf("mfi%d Firmware Images:\n", mfi_unit); 609 strcpy(header.name, "Name"); 610 strcpy(header.version, "Version"); 611 strcpy(header.build_date, "Date"); 612 strcpy(header.build_time, "Time"); 613 scan_firmware(&header); 614 if (info.image_component_count > 8) 615 info.image_component_count = 8; 616 for (i = 0; i < info.image_component_count; i++) 617 scan_firmware(&info.image_component[i]); 618 if (info.pending_image_component_count > 8) 619 info.pending_image_component_count = 8; 620 for (i = 0; i < info.pending_image_component_count; i++) 621 scan_firmware(&info.pending_image_component[i]); 622 display_firmware(&header, "Status"); 623 for (i = 0; i < info.image_component_count; i++) 624 display_firmware(&info.image_component[i], "active"); 625 for (i = 0; i < info.pending_image_component_count; i++) 626 display_firmware(&info.pending_image_component[i], "pending"); 627 628 close(fd); 629 630 return (0); 631 } 632 MFI_COMMAND(show, firmware, show_firmware); 633 634 static int 635 show_progress(int ac, char **av) 636 { 637 struct mfi_ld_list llist; 638 struct mfi_pd_list *plist; 639 struct mfi_ld_info linfo; 640 struct mfi_pd_info pinfo; 641 int busy, error, fd; 642 u_int i; 643 uint16_t device_id; 644 uint8_t target_id; 645 646 if (ac != 1) { 647 warnx("show progress: extra arguments"); 648 return (EINVAL); 649 } 650 651 fd = mfi_open(mfi_unit); 652 if (fd < 0) { 653 error = errno; 654 warn("mfi_open"); 655 return (error); 656 } 657 658 if (mfi_ld_get_list(fd, &llist, NULL) < 0) { 659 error = errno; 660 warn("Failed to get volume list"); 661 close(fd); 662 return (error); 663 } 664 if (mfi_pd_get_list(fd, &plist, NULL) < 0) { 665 error = errno; 666 warn("Failed to get drive list"); 667 close(fd); 668 return (error); 669 } 670 671 busy = 0; 672 for (i = 0; i < llist.ld_count; i++) { 673 target_id = llist.ld_list[i].ld.v.target_id; 674 if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) { 675 error = errno; 676 warn("Failed to get info for volume %s", 677 mfi_volume_name(fd, target_id)); 678 free(plist); 679 close(fd); 680 return (error); 681 } 682 if (linfo.progress.active & MFI_LD_PROGRESS_CC) { 683 printf("volume %s ", mfi_volume_name(fd, target_id)); 684 mfi_display_progress("Consistency Check", 685 &linfo.progress.cc); 686 busy = 1; 687 } 688 if (linfo.progress.active & MFI_LD_PROGRESS_BGI) { 689 printf("volume %s ", mfi_volume_name(fd, target_id)); 690 mfi_display_progress("Background Init", 691 &linfo.progress.bgi); 692 busy = 1; 693 } 694 if (linfo.progress.active & MFI_LD_PROGRESS_FGI) { 695 printf("volume %s ", mfi_volume_name(fd, target_id)); 696 mfi_display_progress("Foreground Init", 697 &linfo.progress.fgi); 698 busy = 1; 699 } 700 if (linfo.progress.active & MFI_LD_PROGRESS_RECON) { 701 printf("volume %s ", mfi_volume_name(fd, target_id)); 702 mfi_display_progress("Reconstruction", 703 &linfo.progress.recon); 704 busy = 1; 705 } 706 } 707 708 for (i = 0; i < plist->count; i++) { 709 if (plist->addr[i].scsi_dev_type != 0) 710 continue; 711 712 device_id = plist->addr[i].device_id; 713 if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) { 714 error = errno; 715 warn("Failed to fetch info for drive %u", device_id); 716 free(plist); 717 close(fd); 718 return (error); 719 } 720 721 if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) { 722 printf("drive %u ", device_id); 723 mfi_display_progress("Rebuild", &pinfo.prog_info.rbld); 724 busy = 1; 725 } 726 if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) { 727 printf("drive %u ", device_id); 728 mfi_display_progress("Patrol Read", 729 &pinfo.prog_info.patrol); 730 busy = 1; 731 } 732 if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) { 733 printf("drive %u ", device_id); 734 mfi_display_progress("Clear", &pinfo.prog_info.clear); 735 busy = 1; 736 } 737 } 738 739 free(plist); 740 close(fd); 741 742 if (!busy) 743 printf("No activity in progress for adapter mfi%d\n", mfi_unit); 744 745 return (0); 746 } 747 MFI_COMMAND(show, progress, show_progress); 748