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 int fw_name_width, fw_version_width, fw_date_width, fw_time_width; 560 561 static void 562 scan_firmware(struct mfi_info_component *comp) 563 { 564 int len; 565 566 len = strlen(comp->name); 567 if (fw_name_width < len) 568 fw_name_width = len; 569 len = strlen(comp->version); 570 if (fw_version_width < len) 571 fw_version_width = len; 572 len = strlen(comp->build_date); 573 if (fw_date_width < len) 574 fw_date_width = len; 575 len = strlen(comp->build_time); 576 if (fw_time_width < len) 577 fw_time_width = len; 578 } 579 580 static void 581 display_firmware(struct mfi_info_component *comp, const char *tag) 582 { 583 584 printf("%-*s %-*s %-*s %-*s %s\n", fw_name_width, comp->name, 585 fw_version_width, comp->version, fw_date_width, comp->build_date, 586 fw_time_width, comp->build_time, tag); 587 } 588 589 static int 590 show_firmware(int ac, __unused char **av) 591 { 592 struct mfi_ctrl_info info; 593 struct mfi_info_component header; 594 int error, fd; 595 u_int i; 596 597 if (ac != 1) { 598 warnx("show firmware: extra arguments"); 599 return (EINVAL); 600 } 601 602 fd = mfi_open(mfi_unit); 603 if (fd < 0) { 604 error = errno; 605 warn("mfi_open"); 606 return (error); 607 } 608 609 if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 610 error = errno; 611 warn("Failed to get controller info"); 612 close(fd); 613 return (error); 614 } 615 616 if (info.package_version[0] != '\0') 617 printf("mfi%d Firmware Package Version: %s\n", mfi_unit, 618 info.package_version); 619 printf("mfi%d Firmware Images:\n", mfi_unit); 620 strcpy(header.name, "Name"); 621 strcpy(header.version, "Version"); 622 strcpy(header.build_date, "Date"); 623 strcpy(header.build_time, "Time"); 624 scan_firmware(&header); 625 if (info.image_component_count > 8) 626 info.image_component_count = 8; 627 for (i = 0; i < info.image_component_count; i++) 628 scan_firmware(&info.image_component[i]); 629 if (info.pending_image_component_count > 8) 630 info.pending_image_component_count = 8; 631 for (i = 0; i < info.pending_image_component_count; i++) 632 scan_firmware(&info.pending_image_component[i]); 633 display_firmware(&header, "Status"); 634 for (i = 0; i < info.image_component_count; i++) 635 display_firmware(&info.image_component[i], "active"); 636 for (i = 0; i < info.pending_image_component_count; i++) 637 display_firmware(&info.pending_image_component[i], "pending"); 638 639 close(fd); 640 641 return (0); 642 } 643 MFI_COMMAND(show, firmware, show_firmware); 644 645 static int 646 show_progress(int ac, __unused char **av) 647 { 648 struct mfi_ld_list llist; 649 struct mfi_pd_list *plist; 650 struct mfi_ld_info linfo; 651 struct mfi_pd_info pinfo; 652 int busy, error, fd; 653 u_int i; 654 uint16_t device_id; 655 uint8_t target_id; 656 657 if (ac != 1) { 658 warnx("show progress: extra arguments"); 659 return (EINVAL); 660 } 661 662 fd = mfi_open(mfi_unit); 663 if (fd < 0) { 664 error = errno; 665 warn("mfi_open"); 666 return (error); 667 } 668 669 if (mfi_ld_get_list(fd, &llist, NULL) < 0) { 670 error = errno; 671 warn("Failed to get volume list"); 672 close(fd); 673 return (error); 674 } 675 if (mfi_pd_get_list(fd, &plist, NULL) < 0) { 676 error = errno; 677 warn("Failed to get drive list"); 678 close(fd); 679 return (error); 680 } 681 682 busy = 0; 683 for (i = 0; i < llist.ld_count; i++) { 684 target_id = llist.ld_list[i].ld.v.target_id; 685 if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) { 686 error = errno; 687 warn("Failed to get info for volume %s", 688 mfi_volume_name(fd, target_id)); 689 free(plist); 690 close(fd); 691 return (error); 692 } 693 if (linfo.progress.active & MFI_LD_PROGRESS_CC) { 694 printf("volume %s ", mfi_volume_name(fd, target_id)); 695 mfi_display_progress("Consistency Check", 696 &linfo.progress.cc); 697 busy = 1; 698 } 699 if (linfo.progress.active & MFI_LD_PROGRESS_BGI) { 700 printf("volume %s ", mfi_volume_name(fd, target_id)); 701 mfi_display_progress("Background Init", 702 &linfo.progress.bgi); 703 busy = 1; 704 } 705 if (linfo.progress.active & MFI_LD_PROGRESS_FGI) { 706 printf("volume %s ", mfi_volume_name(fd, target_id)); 707 mfi_display_progress("Foreground Init", 708 &linfo.progress.fgi); 709 busy = 1; 710 } 711 if (linfo.progress.active & MFI_LD_PROGRESS_RECON) { 712 printf("volume %s ", mfi_volume_name(fd, target_id)); 713 mfi_display_progress("Reconstruction", 714 &linfo.progress.recon); 715 busy = 1; 716 } 717 } 718 719 for (i = 0; i < plist->count; i++) { 720 if (plist->addr[i].scsi_dev_type != 0) 721 continue; 722 723 device_id = plist->addr[i].device_id; 724 if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) { 725 error = errno; 726 warn("Failed to fetch info for drive %u", device_id); 727 free(plist); 728 close(fd); 729 return (error); 730 } 731 732 if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) { 733 printf("drive %s ", mfi_drive_name(NULL, device_id, 734 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 735 mfi_display_progress("Rebuild", &pinfo.prog_info.rbld); 736 busy = 1; 737 } 738 if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) { 739 printf("drive %s ", mfi_drive_name(NULL, device_id, 740 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 741 mfi_display_progress("Patrol Read", 742 &pinfo.prog_info.patrol); 743 busy = 1; 744 } 745 if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) { 746 printf("drive %s ", mfi_drive_name(NULL, device_id, 747 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 748 mfi_display_progress("Clear", &pinfo.prog_info.clear); 749 busy = 1; 750 } 751 } 752 753 free(plist); 754 close(fd); 755 756 if (!busy) 757 printf("No activity in progress for adapter mfi%d\n", mfi_unit); 758 759 return (0); 760 } 761 MFI_COMMAND(show, progress, show_progress); 762