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