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: src/usr.sbin/mfiutil/mfi_show.c,v 1.8 2011/07/29 20:24:04 jhb Exp $ 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) 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 } 277 278 static int 279 show_config(int ac, char **av) 280 { 281 struct mfi_config_data *config; 282 struct mfi_array *ar; 283 struct mfi_ld_config *ld; 284 struct mfi_spare *sp; 285 struct mfi_ld_info linfo; 286 struct mfi_pd_info pinfo; 287 uint16_t device_id; 288 char *p; 289 int error, fd, i, j; 290 291 if (ac != 1) { 292 warnx("show config: extra arguments"); 293 return (EINVAL); 294 } 295 296 fd = mfi_open(mfi_unit); 297 if (fd < 0) { 298 error = errno; 299 warn("mfi_open"); 300 return (error); 301 } 302 303 /* Get the config from the controller. */ 304 if (mfi_config_read(fd, &config) < 0) { 305 error = errno; 306 warn("Failed to get config"); 307 close(fd); 308 return (error); 309 } 310 311 /* Dump out the configuration. */ 312 printf("mfi%d Configuration: %d arrays, %d volumes, %d spares\n", 313 mfi_unit, config->array_count, config->log_drv_count, 314 config->spares_count); 315 p = (char *)config->array; 316 317 for (i = 0; i < config->array_count; i++) { 318 ar = (struct mfi_array *)p; 319 printf(" array %u of %u drives:\n", ar->array_ref, 320 ar->num_drives); 321 for (j = 0; j < ar->num_drives; j++) { 322 device_id = ar->pd[j].ref.v.device_id; 323 printf(" drive %s ", mfi_drive_name(NULL, 324 device_id, 325 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 326 if (device_id != 0xffff) { 327 if (mfi_pd_get_info(fd, device_id, &pinfo, 328 NULL) < 0) 329 printf("%s", 330 mfi_pdstate(ar->pd[j].fw_state)); 331 else 332 print_pd(&pinfo, -1); 333 printf("\n"); 334 } 335 } 336 p += config->array_size; 337 } 338 339 for (i = 0; i < config->log_drv_count; i++) { 340 ld = (struct mfi_ld_config *)p; 341 printf(" volume %s ", 342 mfi_volume_name(fd, ld->properties.ld.v.target_id)); 343 if (mfi_ld_get_info(fd, ld->properties.ld.v.target_id, &linfo, 344 NULL) < 0) { 345 printf("%s %s", 346 mfi_raid_level(ld->params.primary_raid_level, 347 ld->params.secondary_raid_level), 348 mfi_ldstate(ld->params.state)); 349 } else 350 print_ld(&linfo, -1); 351 if (ld->properties.name[0] != '\0') 352 printf(" <%s>", ld->properties.name); 353 printf(" spans:\n"); 354 for (j = 0; j < ld->params.span_depth; j++) 355 printf(" array %u\n", ld->span[j].array_ref); 356 p += config->log_drv_size; 357 } 358 359 for (i = 0; i < config->spares_count; i++) { 360 sp = (struct mfi_spare *)p; 361 printf(" %s spare %s ", 362 sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : 363 "global", mfi_drive_name(NULL, sp->ref.v.device_id, 364 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 365 if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0) 366 printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); 367 else 368 print_pd(&pinfo, -1); 369 if (sp->spare_type & MFI_SPARE_DEDICATED) { 370 printf(" backs:\n"); 371 for (j = 0; j < sp->array_count; j++) 372 printf(" array %u\n", sp->array_ref[j]); 373 } else 374 printf("\n"); 375 p += config->spares_size; 376 } 377 free(config); 378 close(fd); 379 380 return (0); 381 } 382 MFI_COMMAND(show, config, show_config); 383 384 static int 385 show_volumes(int ac, char **av) 386 { 387 struct mfi_ld_list list; 388 struct mfi_ld_info info; 389 int error, fd; 390 u_int i, len, state_len; 391 392 if (ac != 1) { 393 warnx("show volumes: extra arguments"); 394 return (EINVAL); 395 } 396 397 fd = mfi_open(mfi_unit); 398 if (fd < 0) { 399 error = errno; 400 warn("mfi_open"); 401 return (error); 402 } 403 404 /* Get the logical drive list from the controller. */ 405 if (mfi_ld_get_list(fd, &list, NULL) < 0) { 406 error = errno; 407 warn("Failed to get volume list"); 408 close(fd); 409 return (error); 410 } 411 412 /* List the volumes. */ 413 printf("mfi%d Volumes:\n", mfi_unit); 414 state_len = strlen("State"); 415 for (i = 0; i < list.ld_count; i++) { 416 len = strlen(mfi_ldstate(list.ld_list[i].state)); 417 if (len > state_len) 418 state_len = len; 419 } 420 printf(" Id Size Level Stripe "); 421 len = state_len - strlen("State"); 422 for (i = 0; i < (len + 1) / 2; i++) 423 printf(" "); 424 printf("State"); 425 for (i = 0; i < len / 2; i++) 426 printf(" "); 427 printf(" Cache Name\n"); 428 for (i = 0; i < list.ld_count; i++) { 429 if (mfi_ld_get_info(fd, list.ld_list[i].ld.v.target_id, &info, 430 NULL) < 0) { 431 error = errno; 432 warn("Failed to get info for volume %d", 433 list.ld_list[i].ld.v.target_id); 434 close(fd); 435 return (error); 436 } 437 printf("%6s ", 438 mfi_volume_name(fd, list.ld_list[i].ld.v.target_id)); 439 print_ld(&info, state_len); 440 switch (info.ld_config.properties.current_cache_policy & 441 (MR_LD_CACHE_ALLOW_WRITE_CACHE | 442 MR_LD_CACHE_ALLOW_READ_CACHE)) { 443 case 0: 444 printf(" Disabled"); 445 break; 446 case MR_LD_CACHE_ALLOW_READ_CACHE: 447 printf(" Reads "); 448 break; 449 case MR_LD_CACHE_ALLOW_WRITE_CACHE: 450 printf(" Writes "); 451 break; 452 case MR_LD_CACHE_ALLOW_WRITE_CACHE | 453 MR_LD_CACHE_ALLOW_READ_CACHE: 454 printf(" Enabled "); 455 break; 456 } 457 if (info.ld_config.properties.name[0] != '\0') 458 printf(" <%s>", info.ld_config.properties.name); 459 printf("\n"); 460 } 461 close(fd); 462 463 return (0); 464 } 465 MFI_COMMAND(show, volumes, show_volumes); 466 467 static int 468 show_drives(int ac, char **av) 469 { 470 struct mfi_pd_list *list; 471 struct mfi_pd_info info; 472 u_int i, len, state_len; 473 int error, fd; 474 475 if (ac != 1) { 476 warnx("show drives: extra arguments"); 477 return (EINVAL); 478 } 479 480 fd = mfi_open(mfi_unit); 481 if (fd < 0) { 482 error = errno; 483 warn("mfi_open"); 484 return (error); 485 } 486 487 list = NULL; 488 if (mfi_pd_get_list(fd, &list, NULL) < 0) { 489 error = errno; 490 warn("Failed to get drive list"); 491 goto error; 492 } 493 494 /* Walk the list of drives to determine width of state column. */ 495 state_len = 0; 496 for (i = 0; i < list->count; i++) { 497 if (list->addr[i].scsi_dev_type != 0) 498 continue; 499 500 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 501 NULL) < 0) { 502 error = errno; 503 warn("Failed to fetch info for drive %u", 504 list->addr[i].device_id); 505 goto error; 506 } 507 len = strlen(mfi_pdstate(info.fw_state)); 508 if (len > state_len) 509 state_len = len; 510 } 511 512 /* List the drives. */ 513 printf("mfi%d Physical Drives:\n", mfi_unit); 514 for (i = 0; i < list->count; i++) { 515 516 /* Skip non-hard disks. */ 517 if (list->addr[i].scsi_dev_type != 0) 518 continue; 519 520 /* Fetch details for this drive. */ 521 if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 522 NULL) < 0) { 523 error = errno; 524 warn("Failed to fetch info for drive %u", 525 list->addr[i].device_id); 526 goto error; 527 } 528 529 printf("%s ", mfi_drive_name(&info, list->addr[i].device_id, 530 MFI_DNAME_DEVICE_ID)); 531 print_pd(&info, state_len); 532 printf(" %s", mfi_drive_name(&info, list->addr[i].device_id, 533 MFI_DNAME_ES)); 534 printf("\n"); 535 } 536 error = 0; 537 error: 538 free(list); 539 close(fd); 540 541 return (error); 542 } 543 MFI_COMMAND(show, drives, show_drives); 544 545 int fw_name_width, fw_version_width, fw_date_width, fw_time_width; 546 547 static void 548 scan_firmware(struct mfi_info_component *comp) 549 { 550 int len; 551 552 len = strlen(comp->name); 553 if (fw_name_width < len) 554 fw_name_width = len; 555 len = strlen(comp->version); 556 if (fw_version_width < len) 557 fw_version_width = len; 558 len = strlen(comp->build_date); 559 if (fw_date_width < len) 560 fw_date_width = len; 561 len = strlen(comp->build_time); 562 if (fw_time_width < len) 563 fw_time_width = len; 564 } 565 566 static void 567 display_firmware(struct mfi_info_component *comp, const char *tag) 568 { 569 570 printf("%-*s %-*s %-*s %-*s %s\n", fw_name_width, comp->name, 571 fw_version_width, comp->version, fw_date_width, comp->build_date, 572 fw_time_width, comp->build_time, tag); 573 } 574 575 static int 576 show_firmware(int ac, char **av) 577 { 578 struct mfi_ctrl_info info; 579 struct mfi_info_component header; 580 int error, fd; 581 u_int i; 582 583 if (ac != 1) { 584 warnx("show firmware: extra arguments"); 585 return (EINVAL); 586 } 587 588 fd = mfi_open(mfi_unit); 589 if (fd < 0) { 590 error = errno; 591 warn("mfi_open"); 592 return (error); 593 } 594 595 if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 596 error = errno; 597 warn("Failed to get controller info"); 598 close(fd); 599 return (error); 600 } 601 602 if (info.package_version[0] != '\0') 603 printf("mfi%d Firmware Package Version: %s\n", mfi_unit, 604 info.package_version); 605 printf("mfi%d Firmware Images:\n", mfi_unit); 606 strcpy(header.name, "Name"); 607 strcpy(header.version, "Version"); 608 strcpy(header.build_date, "Date"); 609 strcpy(header.build_time, "Time"); 610 scan_firmware(&header); 611 if (info.image_component_count > 8) 612 info.image_component_count = 8; 613 for (i = 0; i < info.image_component_count; i++) 614 scan_firmware(&info.image_component[i]); 615 if (info.pending_image_component_count > 8) 616 info.pending_image_component_count = 8; 617 for (i = 0; i < info.pending_image_component_count; i++) 618 scan_firmware(&info.pending_image_component[i]); 619 display_firmware(&header, "Status"); 620 for (i = 0; i < info.image_component_count; i++) 621 display_firmware(&info.image_component[i], "active"); 622 for (i = 0; i < info.pending_image_component_count; i++) 623 display_firmware(&info.pending_image_component[i], "pending"); 624 625 close(fd); 626 627 return (0); 628 } 629 MFI_COMMAND(show, firmware, show_firmware); 630 631 static int 632 show_progress(int ac, char **av) 633 { 634 struct mfi_ld_list llist; 635 struct mfi_pd_list *plist; 636 struct mfi_ld_info linfo; 637 struct mfi_pd_info pinfo; 638 int busy, error, fd; 639 u_int i; 640 uint16_t device_id; 641 uint8_t target_id; 642 643 if (ac != 1) { 644 warnx("show progress: extra arguments"); 645 return (EINVAL); 646 } 647 648 fd = mfi_open(mfi_unit); 649 if (fd < 0) { 650 error = errno; 651 warn("mfi_open"); 652 return (error); 653 } 654 655 if (mfi_ld_get_list(fd, &llist, NULL) < 0) { 656 error = errno; 657 warn("Failed to get volume list"); 658 close(fd); 659 return (error); 660 } 661 if (mfi_pd_get_list(fd, &plist, NULL) < 0) { 662 error = errno; 663 warn("Failed to get drive list"); 664 close(fd); 665 return (error); 666 } 667 668 busy = 0; 669 for (i = 0; i < llist.ld_count; i++) { 670 target_id = llist.ld_list[i].ld.v.target_id; 671 if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) { 672 error = errno; 673 warn("Failed to get info for volume %s", 674 mfi_volume_name(fd, target_id)); 675 free(plist); 676 close(fd); 677 return (error); 678 } 679 if (linfo.progress.active & MFI_LD_PROGRESS_CC) { 680 printf("volume %s ", mfi_volume_name(fd, target_id)); 681 mfi_display_progress("Consistency Check", 682 &linfo.progress.cc); 683 busy = 1; 684 } 685 if (linfo.progress.active & MFI_LD_PROGRESS_BGI) { 686 printf("volume %s ", mfi_volume_name(fd, target_id)); 687 mfi_display_progress("Background Init", 688 &linfo.progress.bgi); 689 busy = 1; 690 } 691 if (linfo.progress.active & MFI_LD_PROGRESS_FGI) { 692 printf("volume %s ", mfi_volume_name(fd, target_id)); 693 mfi_display_progress("Foreground Init", 694 &linfo.progress.fgi); 695 busy = 1; 696 } 697 if (linfo.progress.active & MFI_LD_PROGRESS_RECON) { 698 printf("volume %s ", mfi_volume_name(fd, target_id)); 699 mfi_display_progress("Reconstruction", 700 &linfo.progress.recon); 701 busy = 1; 702 } 703 } 704 705 for (i = 0; i < plist->count; i++) { 706 if (plist->addr[i].scsi_dev_type != 0) 707 continue; 708 709 device_id = plist->addr[i].device_id; 710 if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) { 711 error = errno; 712 warn("Failed to fetch info for drive %u", device_id); 713 free(plist); 714 close(fd); 715 return (error); 716 } 717 718 if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) { 719 printf("drive %s ", mfi_drive_name(NULL, device_id, 720 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 721 mfi_display_progress("Rebuild", &pinfo.prog_info.rbld); 722 busy = 1; 723 } 724 if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) { 725 printf("drive %s ", mfi_drive_name(NULL, device_id, 726 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 727 mfi_display_progress("Patrol Read", 728 &pinfo.prog_info.patrol); 729 busy = 1; 730 } 731 if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) { 732 printf("drive %s ", mfi_drive_name(NULL, device_id, 733 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 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