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, show_capacity; 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 error = errno; 161 warn("Failed to get capacity info"); 162 close(fd); 163 return (error); 164 } 165 if (status == MFI_STAT_NO_HW_PRESENT) { 166 printf("mfi%d: No battery present\n", mfi_unit); 167 close(fd); 168 return (0); 169 } 170 show_capacity = (status == MFI_STAT_OK); 171 172 if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_DESIGN_INFO, &design, 173 sizeof(design), NULL, 0, NULL) < 0) { 174 error = errno; 175 warn("Failed to get design info"); 176 close(fd); 177 return (error); 178 } 179 180 if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_STATUS, &stat, sizeof(stat), 181 NULL, 0, NULL) < 0) { 182 error = errno; 183 warn("Failed to get status"); 184 close(fd); 185 return (error); 186 } 187 188 printf("mfi%d: Battery State:\n", mfi_unit); 189 printf(" Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f, 190 design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff); 191 printf(" Serial Number: %d\n", design.serial_number); 192 printf(" Manufacturer: %s\n", design.mfg_name); 193 printf(" Model: %s\n", design.device_name); 194 printf(" Chemistry: %s\n", design.device_chemistry); 195 printf(" Design Capacity: %d mAh\n", design.design_capacity); 196 if (show_capacity) { 197 printf(" Full Charge Capacity: %d mAh\n", 198 cap.full_charge_capacity); 199 printf(" Current Capacity: %d mAh\n", 200 cap.remaining_capacity); 201 printf(" Charge Cycles: %d\n", cap.cycle_count); 202 printf(" Current Charge: %d%%\n", cap.relative_charge); 203 } 204 printf(" Design Voltage: %d mV\n", design.design_voltage); 205 printf(" Current Voltage: %d mV\n", stat.voltage); 206 printf(" Temperature: %d C\n", stat.temperature); 207 printf(" Status:"); 208 comma = 0; 209 if (stat.fw_status & MFI_BBU_STATE_PACK_MISSING) { 210 printf(" PACK_MISSING"); 211 comma = 1; 212 } 213 if (stat.fw_status & MFI_BBU_STATE_VOLTAGE_LOW) { 214 printf("%s VOLTAGE_LOW", comma ? "," : ""); 215 comma = 1; 216 } 217 if (stat.fw_status & MFI_BBU_STATE_TEMPERATURE_HIGH) { 218 printf("%s TEMPERATURE_HIGH", comma ? "," : ""); 219 comma = 1; 220 } 221 if (stat.fw_status & MFI_BBU_STATE_CHARGE_ACTIVE) { 222 printf("%s CHARGING", comma ? "," : ""); 223 comma = 1; 224 } 225 if (stat.fw_status & MFI_BBU_STATE_DISCHARGE_ACTIVE) { 226 printf("%s DISCHARGING", comma ? "," : ""); 227 } 228 if (!comma) 229 printf(" normal"); 230 printf("\n"); 231 switch (stat.battery_type) { 232 case MFI_BBU_TYPE_BBU: 233 printf(" State of Health: %s\n", 234 stat.detail.bbu.is_SOH_good ? "good" : "bad"); 235 break; 236 } 237 238 close(fd); 239 240 return (0); 241 } 242 MFI_COMMAND(show, battery, show_battery); 243 244 static void 245 print_ld(struct mfi_ld_info *info, int state_len) 246 { 247 struct mfi_ld_params *params = &info->ld_config.params; 248 const char *level; 249 char size[6], stripe[5]; 250 251 humanize_number(size, sizeof(size), info->size * 512, 252 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 253 format_stripe(stripe, sizeof(stripe), 254 info->ld_config.params.stripe_size); 255 level = mfi_raid_level(params->primary_raid_level, 256 params->secondary_raid_level); 257 if (state_len > 0) 258 printf("(%6s) %-8s %6s %-*s", size, level, stripe, state_len, 259 mfi_ldstate(params->state)); 260 else 261 printf("(%s) %s %s %s", size, level, stripe, 262 mfi_ldstate(params->state)); 263 } 264 265 static void 266 print_pd(struct mfi_pd_info *info, int state_len) 267 { 268 const char *s; 269 char buf[6]; 270 271 humanize_number(buf, sizeof(buf), info->raw_size * 512, "", 272 HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL); 273 printf("(%6s) ", buf); 274 if (state_len > 0) 275 printf("%-*s", state_len, mfi_pdstate(info->fw_state)); 276 else 277 printf("%s", mfi_pdstate(info->fw_state)); 278 s = mfi_pd_inq_string(info); 279 if (s != NULL) 280 printf(" %s", s); 281 } 282 283 static int 284 show_config(int ac, char **av) 285 { 286 struct mfi_config_data *config; 287 struct mfi_array *ar; 288 struct mfi_ld_config *ld; 289 struct mfi_spare *sp; 290 struct mfi_ld_info linfo; 291 struct mfi_pd_info pinfo; 292 uint16_t device_id; 293 char *p; 294 int error, fd, i, j; 295 296 if (ac != 1) { 297 warnx("show config: extra arguments"); 298 return (EINVAL); 299 } 300 301 fd = mfi_open(mfi_unit); 302 if (fd < 0) { 303 error = errno; 304 warn("mfi_open"); 305 return (error); 306 } 307 308 /* Get the config from the controller. */ 309 if (mfi_config_read(fd, &config) < 0) { 310 error = errno; 311 warn("Failed to get config"); 312 close(fd); 313 return (error); 314 } 315 316 /* Dump out the configuration. */ 317 printf("mfi%d Configuration: %d arrays, %d volumes, %d spares\n", 318 mfi_unit, config->array_count, config->log_drv_count, 319 config->spares_count); 320 p = (char *)config->array; 321 322 for (i = 0; i < config->array_count; i++) { 323 ar = (struct mfi_array *)p; 324 printf(" array %u of %u drives:\n", ar->array_ref, 325 ar->num_drives); 326 for (j = 0; j < ar->num_drives; j++) { 327 device_id = ar->pd[j].ref.v.device_id; 328 printf(" drive %s ", mfi_drive_name(NULL, 329 device_id, 330 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 331 if (device_id != 0xffff) { 332 if (mfi_pd_get_info(fd, device_id, &pinfo, 333 NULL) < 0) 334 printf("%s", 335 mfi_pdstate(ar->pd[j].fw_state)); 336 else 337 print_pd(&pinfo, -1); 338 } 339 printf("\n"); 340 } 341 p += config->array_size; 342 } 343 344 for (i = 0; i < config->log_drv_count; i++) { 345 ld = (struct mfi_ld_config *)p; 346 printf(" volume %s ", 347 mfi_volume_name(fd, ld->properties.ld.v.target_id)); 348 if (mfi_ld_get_info(fd, ld->properties.ld.v.target_id, &linfo, 349 NULL) < 0) { 350 printf("%s %s", 351 mfi_raid_level(ld->params.primary_raid_level, 352 ld->params.secondary_raid_level), 353 mfi_ldstate(ld->params.state)); 354 } else 355 print_ld(&linfo, -1); 356 if (ld->properties.name[0] != '\0') 357 printf(" <%s>", ld->properties.name); 358 printf(" spans:\n"); 359 for (j = 0; j < ld->params.span_depth; j++) 360 printf(" array %u\n", ld->span[j].array_ref); 361 p += config->log_drv_size; 362 } 363 364 for (i = 0; i < config->spares_count; i++) { 365 sp = (struct mfi_spare *)p; 366 printf(" %s spare %s ", 367 sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : 368 "global", mfi_drive_name(NULL, sp->ref.v.device_id, 369 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 370 if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0) 371 printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); 372 else 373 print_pd(&pinfo, -1); 374 if (sp->spare_type & MFI_SPARE_DEDICATED) { 375 printf(" backs:\n"); 376 for (j = 0; j < sp->array_count; j++) 377 printf(" array %u\n", sp->array_ref[j]); 378 } else 379 printf("\n"); 380 p += config->spares_size; 381 } 382 free(config); 383 close(fd); 384 385 return (0); 386 } 387 MFI_COMMAND(show, config, show_config); 388 389 static int 390 show_volumes(int ac, char **av) 391 { 392 struct mfi_ld_list list; 393 struct mfi_ld_info info; 394 int error, fd; 395 u_int i, len, state_len; 396 397 if (ac != 1) { 398 warnx("show volumes: extra arguments"); 399 return (EINVAL); 400 } 401 402 fd = mfi_open(mfi_unit); 403 if (fd < 0) { 404 error = errno; 405 warn("mfi_open"); 406 return (error); 407 } 408 409 /* Get the logical drive list from the controller. */ 410 if (mfi_ld_get_list(fd, &list, NULL) < 0) { 411 error = errno; 412 warn("Failed to get volume list"); 413 close(fd); 414 return (error); 415 } 416 417 /* List the volumes. */ 418 printf("mfi%d Volumes:\n", mfi_unit); 419 state_len = strlen("State"); 420 for (i = 0; i < list.ld_count; i++) { 421 len = strlen(mfi_ldstate(list.ld_list[i].state)); 422 if (len > state_len) 423 state_len = len; 424 } 425 printf(" Id Size Level Stripe "); 426 len = state_len - strlen("State"); 427 for (i = 0; i < (len + 1) / 2; i++) 428 printf(" "); 429 printf("State"); 430 for (i = 0; i < len / 2; i++) 431 printf(" "); 432 printf(" Cache Name\n"); 433 for (i = 0; i < list.ld_count; i++) { 434 if (mfi_ld_get_info(fd, list.ld_list[i].ld.v.target_id, &info, 435 NULL) < 0) { 436 error = errno; 437 warn("Failed to get info for volume %d", 438 list.ld_list[i].ld.v.target_id); 439 close(fd); 440 return (error); 441 } 442 printf("%6s ", 443 mfi_volume_name(fd, list.ld_list[i].ld.v.target_id)); 444 print_ld(&info, state_len); 445 switch (info.ld_config.properties.current_cache_policy & 446 (MR_LD_CACHE_ALLOW_WRITE_CACHE | 447 MR_LD_CACHE_ALLOW_READ_CACHE)) { 448 case 0: 449 printf(" Disabled"); 450 break; 451 case MR_LD_CACHE_ALLOW_READ_CACHE: 452 printf(" Reads "); 453 break; 454 case MR_LD_CACHE_ALLOW_WRITE_CACHE: 455 printf(" Writes "); 456 break; 457 case MR_LD_CACHE_ALLOW_WRITE_CACHE | 458 MR_LD_CACHE_ALLOW_READ_CACHE: 459 printf(" Enabled "); 460 break; 461 } 462 if (info.ld_config.properties.name[0] != '\0') 463 printf(" <%s>", info.ld_config.properties.name); 464 printf("\n"); 465 } 466 close(fd); 467 468 return (0); 469 } 470 MFI_COMMAND(show, volumes, show_volumes); 471 472 static int 473 show_drives(int ac, char **av) 474 { 475 struct mfi_pd_list *list; 476 struct mfi_pd_info info; 477 u_int i, len, state_len; 478 int error, fd; 479 480 if (ac != 1) { 481 warnx("show drives: extra arguments"); 482 return (EINVAL); 483 } 484 485 fd = mfi_open(mfi_unit); 486 if (fd < 0) { 487 error = errno; 488 warn("mfi_open"); 489 return (error); 490 } 491 492 list = NULL; 493 if (mfi_pd_get_list(fd, &list, NULL) < 0) { 494 error = errno; 495 warn("Failed to get drive list"); 496 goto error; 497 } 498 499 /* Walk the list of drives to determine width of state column. */ 500 state_len = 0; 501 for (i = 0; i < list->count; i++) { 502 if (list->addr[i].scsi_dev_type != 0) 503 continue; 504 505 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 506 NULL) < 0) { 507 error = errno; 508 warn("Failed to fetch info for drive %u", 509 list->addr[i].device_id); 510 goto error; 511 } 512 len = strlen(mfi_pdstate(info.fw_state)); 513 if (len > state_len) 514 state_len = len; 515 } 516 517 /* List the drives. */ 518 printf("mfi%d Physical Drives:\n", mfi_unit); 519 for (i = 0; i < list->count; i++) { 520 521 /* Skip non-hard disks. */ 522 if (list->addr[i].scsi_dev_type != 0) 523 continue; 524 525 /* Fetch details for this drive. */ 526 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 527 NULL) < 0) { 528 error = errno; 529 warn("Failed to fetch info for drive %u", 530 list->addr[i].device_id); 531 goto error; 532 } 533 534 printf("%s ", mfi_drive_name(&info, list->addr[i].device_id, 535 MFI_DNAME_DEVICE_ID)); 536 print_pd(&info, state_len); 537 printf(" %s", mfi_drive_name(&info, list->addr[i].device_id, 538 MFI_DNAME_ES)); 539 printf("\n"); 540 } 541 error = 0; 542 error: 543 free(list); 544 close(fd); 545 546 return (error); 547 } 548 MFI_COMMAND(show, drives, show_drives); 549 550 int fw_name_width, fw_version_width, fw_date_width, fw_time_width; 551 552 static void 553 scan_firmware(struct mfi_info_component *comp) 554 { 555 int len; 556 557 len = strlen(comp->name); 558 if (fw_name_width < len) 559 fw_name_width = len; 560 len = strlen(comp->version); 561 if (fw_version_width < len) 562 fw_version_width = len; 563 len = strlen(comp->build_date); 564 if (fw_date_width < len) 565 fw_date_width = len; 566 len = strlen(comp->build_time); 567 if (fw_time_width < len) 568 fw_time_width = len; 569 } 570 571 static void 572 display_firmware(struct mfi_info_component *comp, const char *tag) 573 { 574 575 printf("%-*s %-*s %-*s %-*s %s\n", fw_name_width, comp->name, 576 fw_version_width, comp->version, fw_date_width, comp->build_date, 577 fw_time_width, comp->build_time, tag); 578 } 579 580 static int 581 show_firmware(int ac, char **av) 582 { 583 struct mfi_ctrl_info info; 584 struct mfi_info_component header; 585 int error, fd; 586 u_int i; 587 588 if (ac != 1) { 589 warnx("show firmware: extra arguments"); 590 return (EINVAL); 591 } 592 593 fd = mfi_open(mfi_unit); 594 if (fd < 0) { 595 error = errno; 596 warn("mfi_open"); 597 return (error); 598 } 599 600 if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 601 error = errno; 602 warn("Failed to get controller info"); 603 close(fd); 604 return (error); 605 } 606 607 if (info.package_version[0] != '\0') 608 printf("mfi%d Firmware Package Version: %s\n", mfi_unit, 609 info.package_version); 610 printf("mfi%d Firmware Images:\n", mfi_unit); 611 strcpy(header.name, "Name"); 612 strcpy(header.version, "Version"); 613 strcpy(header.build_date, "Date"); 614 strcpy(header.build_time, "Time"); 615 scan_firmware(&header); 616 if (info.image_component_count > 8) 617 info.image_component_count = 8; 618 for (i = 0; i < info.image_component_count; i++) 619 scan_firmware(&info.image_component[i]); 620 if (info.pending_image_component_count > 8) 621 info.pending_image_component_count = 8; 622 for (i = 0; i < info.pending_image_component_count; i++) 623 scan_firmware(&info.pending_image_component[i]); 624 display_firmware(&header, "Status"); 625 for (i = 0; i < info.image_component_count; i++) 626 display_firmware(&info.image_component[i], "active"); 627 for (i = 0; i < info.pending_image_component_count; i++) 628 display_firmware(&info.pending_image_component[i], "pending"); 629 630 close(fd); 631 632 return (0); 633 } 634 MFI_COMMAND(show, firmware, show_firmware); 635 636 static int 637 show_progress(int ac, char **av) 638 { 639 struct mfi_ld_list llist; 640 struct mfi_pd_list *plist; 641 struct mfi_ld_info linfo; 642 struct mfi_pd_info pinfo; 643 int busy, error, fd; 644 u_int i; 645 uint16_t device_id; 646 uint8_t target_id; 647 648 if (ac != 1) { 649 warnx("show progress: extra arguments"); 650 return (EINVAL); 651 } 652 653 fd = mfi_open(mfi_unit); 654 if (fd < 0) { 655 error = errno; 656 warn("mfi_open"); 657 return (error); 658 } 659 660 if (mfi_ld_get_list(fd, &llist, NULL) < 0) { 661 error = errno; 662 warn("Failed to get volume list"); 663 close(fd); 664 return (error); 665 } 666 if (mfi_pd_get_list(fd, &plist, NULL) < 0) { 667 error = errno; 668 warn("Failed to get drive list"); 669 close(fd); 670 return (error); 671 } 672 673 busy = 0; 674 for (i = 0; i < llist.ld_count; i++) { 675 target_id = llist.ld_list[i].ld.v.target_id; 676 if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) { 677 error = errno; 678 warn("Failed to get info for volume %s", 679 mfi_volume_name(fd, target_id)); 680 free(plist); 681 close(fd); 682 return (error); 683 } 684 if (linfo.progress.active & MFI_LD_PROGRESS_CC) { 685 printf("volume %s ", mfi_volume_name(fd, target_id)); 686 mfi_display_progress("Consistency Check", 687 &linfo.progress.cc); 688 busy = 1; 689 } 690 if (linfo.progress.active & MFI_LD_PROGRESS_BGI) { 691 printf("volume %s ", mfi_volume_name(fd, target_id)); 692 mfi_display_progress("Background Init", 693 &linfo.progress.bgi); 694 busy = 1; 695 } 696 if (linfo.progress.active & MFI_LD_PROGRESS_FGI) { 697 printf("volume %s ", mfi_volume_name(fd, target_id)); 698 mfi_display_progress("Foreground Init", 699 &linfo.progress.fgi); 700 busy = 1; 701 } 702 if (linfo.progress.active & MFI_LD_PROGRESS_RECON) { 703 printf("volume %s ", mfi_volume_name(fd, target_id)); 704 mfi_display_progress("Reconstruction", 705 &linfo.progress.recon); 706 busy = 1; 707 } 708 } 709 710 for (i = 0; i < plist->count; i++) { 711 if (plist->addr[i].scsi_dev_type != 0) 712 continue; 713 714 device_id = plist->addr[i].device_id; 715 if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) { 716 error = errno; 717 warn("Failed to fetch info for drive %u", device_id); 718 free(plist); 719 close(fd); 720 return (error); 721 } 722 723 if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) { 724 printf("drive %s ", mfi_drive_name(NULL, device_id, 725 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 726 mfi_display_progress("Rebuild", &pinfo.prog_info.rbld); 727 busy = 1; 728 } 729 if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) { 730 printf("drive %s ", mfi_drive_name(NULL, device_id, 731 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 732 mfi_display_progress("Patrol Read", 733 &pinfo.prog_info.patrol); 734 busy = 1; 735 } 736 if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) { 737 printf("drive %s ", mfi_drive_name(NULL, device_id, 738 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 739 mfi_display_progress("Clear", &pinfo.prog_info.clear); 740 busy = 1; 741 } 742 } 743 744 free(plist); 745 close(fd); 746 747 if (!busy) 748 printf("No activity in progress for adapter mfi%d\n", mfi_unit); 749 750 return (0); 751 } 752 MFI_COMMAND(show, progress, show_progress); 753