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