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