mfi_show.c revision 223345
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: head/usr.sbin/mfiutil/mfi_show.c 223345 2011-06-20 21:28:50Z bz $ 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 42MFI_TABLE(top, show); 43 44static void 45format_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 52static int 53show_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} 135MFI_COMMAND(show, adapter, show_adapter); 136 137static int 138show_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} 237MFI_COMMAND(show, battery, show_battery); 238 239static void 240print_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 260static void 261print_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 278static int 279show_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} 382MFI_COMMAND(show, config, show_config); 383 384static int 385show_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} 465MFI_COMMAND(show, volumes, show_volumes); 466 467static int 468show_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 } 536error: 537 free(list); 538 close(fd); 539 540 return (error); 541} 542MFI_COMMAND(show, drives, show_drives); 543 544int fw_name_width, fw_version_width, fw_date_width, fw_time_width; 545 546static void 547scan_firmware(struct mfi_info_component *comp) 548{ 549 int len; 550 551 len = strlen(comp->name); 552 if (fw_name_width < len) 553 fw_name_width = len; 554 len = strlen(comp->version); 555 if (fw_version_width < len) 556 fw_version_width = len; 557 len = strlen(comp->build_date); 558 if (fw_date_width < len) 559 fw_date_width = len; 560 len = strlen(comp->build_time); 561 if (fw_time_width < len) 562 fw_time_width = len; 563} 564 565static void 566display_firmware(struct mfi_info_component *comp, const char *tag) 567{ 568 569 printf("%-*s %-*s %-*s %-*s %s\n", fw_name_width, comp->name, 570 fw_version_width, comp->version, fw_date_width, comp->build_date, 571 fw_time_width, comp->build_time, tag); 572} 573 574static int 575show_firmware(int ac, char **av) 576{ 577 struct mfi_ctrl_info info; 578 struct mfi_info_component header; 579 int error, fd; 580 u_int i; 581 582 if (ac != 1) { 583 warnx("show firmware: extra arguments"); 584 return (EINVAL); 585 } 586 587 fd = mfi_open(mfi_unit); 588 if (fd < 0) { 589 error = errno; 590 warn("mfi_open"); 591 return (error); 592 } 593 594 if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 595 error = errno; 596 warn("Failed to get controller info"); 597 close(fd); 598 return (error); 599 } 600 601 if (info.package_version[0] != '\0') 602 printf("mfi%d Firmware Package Version: %s\n", mfi_unit, 603 info.package_version); 604 printf("mfi%d Firmware Images:\n", mfi_unit); 605 strcpy(header.name, "Name"); 606 strcpy(header.version, "Version"); 607 strcpy(header.build_date, "Date"); 608 strcpy(header.build_time, "Time"); 609 scan_firmware(&header); 610 if (info.image_component_count > 8) 611 info.image_component_count = 8; 612 for (i = 0; i < info.image_component_count; i++) 613 scan_firmware(&info.image_component[i]); 614 if (info.pending_image_component_count > 8) 615 info.pending_image_component_count = 8; 616 for (i = 0; i < info.pending_image_component_count; i++) 617 scan_firmware(&info.pending_image_component[i]); 618 display_firmware(&header, "Status"); 619 for (i = 0; i < info.image_component_count; i++) 620 display_firmware(&info.image_component[i], "active"); 621 for (i = 0; i < info.pending_image_component_count; i++) 622 display_firmware(&info.pending_image_component[i], "pending"); 623 624 close(fd); 625 626 return (0); 627} 628MFI_COMMAND(show, firmware, show_firmware); 629 630static int 631show_progress(int ac, char **av) 632{ 633 struct mfi_ld_list llist; 634 struct mfi_pd_list *plist; 635 struct mfi_ld_info linfo; 636 struct mfi_pd_info pinfo; 637 int busy, error, fd; 638 u_int i; 639 uint16_t device_id; 640 uint8_t target_id; 641 642 if (ac != 1) { 643 warnx("show progress: extra arguments"); 644 return (EINVAL); 645 } 646 647 fd = mfi_open(mfi_unit); 648 if (fd < 0) { 649 error = errno; 650 warn("mfi_open"); 651 return (error); 652 } 653 654 if (mfi_ld_get_list(fd, &llist, NULL) < 0) { 655 error = errno; 656 warn("Failed to get volume list"); 657 close(fd); 658 return (error); 659 } 660 if (mfi_pd_get_list(fd, &plist, NULL) < 0) { 661 error = errno; 662 warn("Failed to get drive list"); 663 close(fd); 664 return (error); 665 } 666 667 busy = 0; 668 for (i = 0; i < llist.ld_count; i++) { 669 target_id = llist.ld_list[i].ld.v.target_id; 670 if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) { 671 error = errno; 672 warn("Failed to get info for volume %s", 673 mfi_volume_name(fd, target_id)); 674 free(plist); 675 close(fd); 676 return (error); 677 } 678 if (linfo.progress.active & MFI_LD_PROGRESS_CC) { 679 printf("volume %s ", mfi_volume_name(fd, target_id)); 680 mfi_display_progress("Consistency Check", 681 &linfo.progress.cc); 682 busy = 1; 683 } 684 if (linfo.progress.active & MFI_LD_PROGRESS_BGI) { 685 printf("volume %s ", mfi_volume_name(fd, target_id)); 686 mfi_display_progress("Background Init", 687 &linfo.progress.bgi); 688 busy = 1; 689 } 690 if (linfo.progress.active & MFI_LD_PROGRESS_FGI) { 691 printf("volume %s ", mfi_volume_name(fd, target_id)); 692 mfi_display_progress("Foreground Init", 693 &linfo.progress.fgi); 694 busy = 1; 695 } 696 if (linfo.progress.active & MFI_LD_PROGRESS_RECON) { 697 printf("volume %s ", mfi_volume_name(fd, target_id)); 698 mfi_display_progress("Reconstruction", 699 &linfo.progress.recon); 700 busy = 1; 701 } 702 } 703 704 for (i = 0; i < plist->count; i++) { 705 if (plist->addr[i].scsi_dev_type != 0) 706 continue; 707 708 device_id = plist->addr[i].device_id; 709 if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) { 710 error = errno; 711 warn("Failed to fetch info for drive %u", device_id); 712 free(plist); 713 close(fd); 714 return (error); 715 } 716 717 if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) { 718 printf("drive %s ", mfi_drive_name(NULL, device_id, 719 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 720 mfi_display_progress("Rebuild", &pinfo.prog_info.rbld); 721 busy = 1; 722 } 723 if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) { 724 printf("drive %s ", mfi_drive_name(NULL, device_id, 725 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 726 mfi_display_progress("Patrol Read", 727 &pinfo.prog_info.patrol); 728 busy = 1; 729 } 730 if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) { 731 printf("drive %s ", mfi_drive_name(NULL, device_id, 732 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 733 mfi_display_progress("Clear", &pinfo.prog_info.clear); 734 busy = 1; 735 } 736 } 737 738 free(plist); 739 close(fd); 740 741 if (!busy) 742 printf("No activity in progress for adapter mfi%d\n", mfi_unit); 743 744 return (0); 745} 746MFI_COMMAND(show, progress, show_progress); 747