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