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