1763fae79SScott Long /*- 2763fae79SScott Long * Copyright (c) 2008, 2009 Yahoo!, Inc. 3763fae79SScott Long * All rights reserved. 4763fae79SScott Long * 5763fae79SScott Long * Redistribution and use in source and binary forms, with or without 6763fae79SScott Long * modification, are permitted provided that the following conditions 7763fae79SScott Long * are met: 8763fae79SScott Long * 1. Redistributions of source code must retain the above copyright 9763fae79SScott Long * notice, this list of conditions and the following disclaimer. 10763fae79SScott Long * 2. Redistributions in binary form must reproduce the above copyright 11763fae79SScott Long * notice, this list of conditions and the following disclaimer in the 12763fae79SScott Long * documentation and/or other materials provided with the distribution. 13763fae79SScott Long * 3. The names of the authors may not be used to endorse or promote 14763fae79SScott Long * products derived from this software without specific prior written 15763fae79SScott Long * permission. 16763fae79SScott Long * 17763fae79SScott Long * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18763fae79SScott Long * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19763fae79SScott Long * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20763fae79SScott Long * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21763fae79SScott Long * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22763fae79SScott Long * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23763fae79SScott Long * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24763fae79SScott Long * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25763fae79SScott Long * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26763fae79SScott Long * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27763fae79SScott Long * SUCH DAMAGE. 28763fae79SScott Long * 29763fae79SScott Long * $FreeBSD$ 30763fae79SScott Long */ 31763fae79SScott Long 32763fae79SScott Long #include <sys/types.h> 33763fae79SScott Long #include <sys/errno.h> 34763fae79SScott Long #include <err.h> 35763fae79SScott Long #include <libutil.h> 36763fae79SScott Long #include <stdio.h> 37763fae79SScott Long #include <stdlib.h> 38763fae79SScott Long #include <string.h> 39763fae79SScott Long #include <unistd.h> 40763fae79SScott Long #include "mfiutil.h" 41763fae79SScott Long 42763fae79SScott Long MFI_TABLE(top, show); 43763fae79SScott Long 44763fae79SScott Long static void 45763fae79SScott Long format_stripe(char *buf, size_t buflen, uint8_t stripe) 46763fae79SScott Long { 47763fae79SScott Long 48763fae79SScott Long humanize_number(buf, buflen, (1 << stripe) * 512, "", HN_AUTOSCALE, 49763fae79SScott Long HN_B | HN_NOSPACE); 50763fae79SScott Long } 51763fae79SScott Long 52763fae79SScott Long static int 53763fae79SScott Long show_adapter(int ac, char **av) 54763fae79SScott Long { 55763fae79SScott Long struct mfi_ctrl_info info; 56763fae79SScott Long char stripe[5]; 57c02999d9SJohn Baldwin int error, fd, comma; 58763fae79SScott Long 59763fae79SScott Long if (ac != 1) { 60763fae79SScott Long warnx("show adapter: extra arguments"); 61763fae79SScott Long return (EINVAL); 62763fae79SScott Long } 63763fae79SScott Long 64763fae79SScott Long fd = mfi_open(mfi_unit); 65763fae79SScott Long if (fd < 0) { 66c02999d9SJohn Baldwin error = errno; 67763fae79SScott Long warn("mfi_open"); 68c02999d9SJohn Baldwin return (error); 69763fae79SScott Long } 70763fae79SScott Long 71763fae79SScott Long if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 72c02999d9SJohn Baldwin error = errno; 73763fae79SScott Long warn("Failed to get controller info"); 74c02999d9SJohn Baldwin return (error); 75763fae79SScott Long } 76763fae79SScott Long printf("mfi%d Adapter:\n", mfi_unit); 77763fae79SScott Long printf(" Product Name: %.80s\n", info.product_name); 78763fae79SScott Long printf(" Serial Number: %.32s\n", info.serial_number); 79763fae79SScott Long if (info.package_version[0] != '\0') 80763fae79SScott Long printf(" Firmware: %s\n", info.package_version); 81763fae79SScott Long printf(" RAID Levels:"); 82763fae79SScott Long #ifdef DEBUG 83763fae79SScott Long printf(" (%#x)", info.raid_levels); 84763fae79SScott Long #endif 85763fae79SScott Long comma = 0; 86763fae79SScott Long if (info.raid_levels & MFI_INFO_RAID_0) { 87763fae79SScott Long printf(" JBOD, RAID0"); 88763fae79SScott Long comma = 1; 89763fae79SScott Long } 90763fae79SScott Long if (info.raid_levels & MFI_INFO_RAID_1) { 91763fae79SScott Long printf("%s RAID1", comma ? "," : ""); 92763fae79SScott Long comma = 1; 93763fae79SScott Long } 94763fae79SScott Long if (info.raid_levels & MFI_INFO_RAID_5) { 95763fae79SScott Long printf("%s RAID5", comma ? "," : ""); 96763fae79SScott Long comma = 1; 97763fae79SScott Long } 98763fae79SScott Long if (info.raid_levels & MFI_INFO_RAID_1E) { 99763fae79SScott Long printf("%s RAID1E", comma ? "," : ""); 100763fae79SScott Long comma = 1; 101763fae79SScott Long } 102763fae79SScott Long if (info.raid_levels & MFI_INFO_RAID_6) { 103763fae79SScott Long printf("%s RAID6", comma ? "," : ""); 104763fae79SScott Long comma = 1; 105763fae79SScott Long } 106763fae79SScott Long if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) == 107763fae79SScott Long (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) { 108763fae79SScott Long printf("%s RAID10", comma ? "," : ""); 109763fae79SScott Long comma = 1; 110763fae79SScott Long } 111763fae79SScott Long if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) == 112763fae79SScott Long (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) { 113763fae79SScott Long printf("%s RAID50", comma ? "," : ""); 114763fae79SScott Long comma = 1; 115763fae79SScott Long } 116763fae79SScott Long printf("\n"); 117763fae79SScott Long printf(" Battery Backup: "); 118763fae79SScott Long if (info.hw_present & MFI_INFO_HW_BBU) 119763fae79SScott Long printf("present\n"); 120763fae79SScott Long else 121763fae79SScott Long printf("not present\n"); 122763fae79SScott Long if (info.hw_present & MFI_INFO_HW_NVRAM) 123763fae79SScott Long printf(" NVRAM: %uK\n", info.nvram_size); 124763fae79SScott Long printf(" Onboard Memory: %uM\n", info.memory_size); 125763fae79SScott Long format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.min); 126763fae79SScott Long printf(" Minimum Stripe: %s\n", stripe); 127763fae79SScott Long format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.max); 128763fae79SScott Long printf(" Maximum Stripe: %s\n", stripe); 129763fae79SScott Long 130763fae79SScott Long close(fd); 131763fae79SScott Long 132763fae79SScott Long return (0); 133763fae79SScott Long } 134763fae79SScott Long MFI_COMMAND(show, adapter, show_adapter); 135763fae79SScott Long 136763fae79SScott Long static int 137763fae79SScott Long show_battery(int ac, char **av) 138763fae79SScott Long { 139763fae79SScott Long struct mfi_bbu_capacity_info cap; 140763fae79SScott Long struct mfi_bbu_design_info design; 141100ec05aSJohn Baldwin struct mfi_bbu_status stat; 142763fae79SScott Long uint8_t status; 143100ec05aSJohn Baldwin int comma, error, fd; 144763fae79SScott Long 145763fae79SScott Long if (ac != 1) { 146763fae79SScott Long warnx("show battery: extra arguments"); 147763fae79SScott Long return (EINVAL); 148763fae79SScott Long } 149763fae79SScott Long 150763fae79SScott Long fd = mfi_open(mfi_unit); 151763fae79SScott Long if (fd < 0) { 152c02999d9SJohn Baldwin error = errno; 153763fae79SScott Long warn("mfi_open"); 154c02999d9SJohn Baldwin return (error); 155763fae79SScott Long } 156763fae79SScott Long 157763fae79SScott Long if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_CAPACITY_INFO, &cap, 158763fae79SScott Long sizeof(cap), NULL, 0, &status) < 0) { 159763fae79SScott Long if (status == MFI_STAT_NO_HW_PRESENT) { 160763fae79SScott Long printf("mfi%d: No battery present\n", mfi_unit); 161763fae79SScott Long return (0); 162763fae79SScott Long } 163c02999d9SJohn Baldwin error = errno; 164763fae79SScott Long warn("Failed to get capacity info"); 165c02999d9SJohn Baldwin return (error); 166763fae79SScott Long } 167763fae79SScott Long 168763fae79SScott Long if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_DESIGN_INFO, &design, 169763fae79SScott Long sizeof(design), NULL, 0, NULL) < 0) { 170c02999d9SJohn Baldwin error = errno; 171763fae79SScott Long warn("Failed to get design info"); 172c02999d9SJohn Baldwin return (error); 173763fae79SScott Long } 174763fae79SScott Long 175100ec05aSJohn Baldwin if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_STATUS, &stat, sizeof(stat), 176100ec05aSJohn Baldwin NULL, 0, NULL) < 0) { 177100ec05aSJohn Baldwin warn("Failed to get status"); 178100ec05aSJohn Baldwin return (errno); 179100ec05aSJohn Baldwin } 180100ec05aSJohn Baldwin 181763fae79SScott Long printf("mfi%d: Battery State:\n", mfi_unit); 182763fae79SScott Long printf(" Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f, 183763fae79SScott Long design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff); 184763fae79SScott Long printf(" Serial Number: %d\n", design.serial_number); 185763fae79SScott Long printf(" Manufacturer: %s\n", design.mfg_name); 186763fae79SScott Long printf(" Model: %s\n", design.device_name); 187763fae79SScott Long printf(" Chemistry: %s\n", design.device_chemistry); 188763fae79SScott Long printf(" Design Capacity: %d mAh\n", design.design_capacity); 189100ec05aSJohn Baldwin printf(" Full Charge Capacity: %d mAh\n", cap.full_charge_capacity); 190100ec05aSJohn Baldwin printf(" Current Capacity: %d mAh\n", cap.remaining_capacity); 191100ec05aSJohn Baldwin printf(" Charge Cycles: %d\n", cap.cycle_count); 192763fae79SScott Long printf(" Current Charge: %d%%\n", cap.relative_charge); 193100ec05aSJohn Baldwin printf(" Design Voltage: %d mV\n", design.design_voltage); 194100ec05aSJohn Baldwin printf(" Current Voltage: %d mV\n", stat.voltage); 195100ec05aSJohn Baldwin printf(" Temperature: %d C\n", stat.temperature); 196100ec05aSJohn Baldwin printf(" Status:"); 197100ec05aSJohn Baldwin comma = 0; 198100ec05aSJohn Baldwin if (stat.fw_status & MFI_BBU_STATE_PACK_MISSING) { 199100ec05aSJohn Baldwin printf(" PACK_MISSING"); 200100ec05aSJohn Baldwin comma = 1; 201100ec05aSJohn Baldwin } 202100ec05aSJohn Baldwin if (stat.fw_status & MFI_BBU_STATE_VOLTAGE_LOW) { 203100ec05aSJohn Baldwin printf("%s VOLTAGE_LOW", comma ? "," : ""); 204100ec05aSJohn Baldwin comma = 1; 205100ec05aSJohn Baldwin } 206100ec05aSJohn Baldwin if (stat.fw_status & MFI_BBU_STATE_TEMPERATURE_HIGH) { 207100ec05aSJohn Baldwin printf("%s TEMPERATURE_HIGH", comma ? "," : ""); 208100ec05aSJohn Baldwin comma = 1; 209100ec05aSJohn Baldwin } 210100ec05aSJohn Baldwin if (stat.fw_status & MFI_BBU_STATE_CHARGE_ACTIVE) { 211100ec05aSJohn Baldwin printf("%s CHARGING", comma ? "," : ""); 212100ec05aSJohn Baldwin comma = 1; 213100ec05aSJohn Baldwin } 214100ec05aSJohn Baldwin if (stat.fw_status & MFI_BBU_STATE_DISCHARGE_ACTIVE) { 215100ec05aSJohn Baldwin printf("%s DISCHARGING", comma ? "," : ""); 216100ec05aSJohn Baldwin } 217100ec05aSJohn Baldwin if (!comma) 218100ec05aSJohn Baldwin printf(" normal"); 219100ec05aSJohn Baldwin printf("\n"); 220100ec05aSJohn Baldwin switch (stat.battery_type) { 221100ec05aSJohn Baldwin case MFI_BBU_TYPE_BBU: 222100ec05aSJohn Baldwin printf(" State of Health: %s\n", 223100ec05aSJohn Baldwin stat.detail.bbu.is_SOH_good ? "good" : "bad"); 224100ec05aSJohn Baldwin break; 225100ec05aSJohn Baldwin } 226763fae79SScott Long 227763fae79SScott Long close(fd); 228763fae79SScott Long 229763fae79SScott Long return (0); 230763fae79SScott Long } 231763fae79SScott Long MFI_COMMAND(show, battery, show_battery); 232763fae79SScott Long 233763fae79SScott Long static void 234763fae79SScott Long print_ld(struct mfi_ld_info *info, int state_len) 235763fae79SScott Long { 236763fae79SScott Long struct mfi_ld_params *params = &info->ld_config.params; 237763fae79SScott Long const char *level; 238763fae79SScott Long char size[6], stripe[5]; 239763fae79SScott Long 240763fae79SScott Long humanize_number(size, sizeof(size), info->size * 512, 241763fae79SScott Long "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 242763fae79SScott Long format_stripe(stripe, sizeof(stripe), 243763fae79SScott Long info->ld_config.params.stripe_size); 244763fae79SScott Long level = mfi_raid_level(params->primary_raid_level, 245763fae79SScott Long params->secondary_raid_level); 246763fae79SScott Long if (state_len > 0) 247763fae79SScott Long printf("(%6s) %-8s %6s %-*s", size, level, stripe, state_len, 248763fae79SScott Long mfi_ldstate(params->state)); 249763fae79SScott Long else 250763fae79SScott Long printf("(%s) %s %s %s", size, level, stripe, 251763fae79SScott Long mfi_ldstate(params->state)); 252763fae79SScott Long } 253763fae79SScott Long 254763fae79SScott Long static void 255763fae79SScott Long print_pd(struct mfi_pd_info *info, int state_len, int location) 256763fae79SScott Long { 257763fae79SScott Long const char *s; 258763fae79SScott Long char buf[6]; 259763fae79SScott Long 260763fae79SScott Long humanize_number(buf, sizeof(buf), info->raw_size * 512, "", 261763fae79SScott Long HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL); 262763fae79SScott Long printf("(%6s) ", buf); 263763fae79SScott Long if (state_len > 0) 264763fae79SScott Long printf("%-*s", state_len, mfi_pdstate(info->fw_state)); 265763fae79SScott Long else 266763fae79SScott Long printf("%s", mfi_pdstate(info->fw_state)); 267763fae79SScott Long s = mfi_pd_inq_string(info); 268763fae79SScott Long if (s != NULL) 269763fae79SScott Long printf(" %s", s); 270763fae79SScott Long if (!location) 271763fae79SScott Long return; 272763fae79SScott Long if (info->encl_device_id == 0xffff) 273763fae79SScott Long printf(" slot %d", info->slot_number); 274763fae79SScott Long else if (info->encl_device_id == info->ref.v.device_id) 275763fae79SScott Long printf(" enclosure %d", info->encl_index); 276763fae79SScott Long else 277763fae79SScott Long printf(" enclosure %d, slot %d", info->encl_index, 278763fae79SScott Long info->slot_number); 279763fae79SScott Long } 280763fae79SScott Long 281763fae79SScott Long static int 282763fae79SScott Long show_config(int ac, char **av) 283763fae79SScott Long { 284763fae79SScott Long struct mfi_config_data *config; 285763fae79SScott Long struct mfi_array *ar; 286763fae79SScott Long struct mfi_ld_config *ld; 287763fae79SScott Long struct mfi_spare *sp; 288763fae79SScott Long struct mfi_ld_info linfo; 289763fae79SScott Long struct mfi_pd_info pinfo; 290763fae79SScott Long uint16_t device_id; 291763fae79SScott Long char *p; 292c02999d9SJohn Baldwin int error, fd, i, j; 293763fae79SScott Long 294763fae79SScott Long if (ac != 1) { 295763fae79SScott Long warnx("show config: extra arguments"); 296763fae79SScott Long return (EINVAL); 297763fae79SScott Long } 298763fae79SScott Long 299763fae79SScott Long fd = mfi_open(mfi_unit); 300763fae79SScott Long if (fd < 0) { 301c02999d9SJohn Baldwin error = errno; 302763fae79SScott Long warn("mfi_open"); 303c02999d9SJohn Baldwin return (error); 304763fae79SScott Long } 305763fae79SScott Long 306763fae79SScott Long /* Get the config from the controller. */ 307763fae79SScott Long if (mfi_config_read(fd, &config) < 0) { 308c02999d9SJohn Baldwin error = errno; 309763fae79SScott Long warn("Failed to get config"); 310c02999d9SJohn Baldwin return (error); 311763fae79SScott Long } 312763fae79SScott Long 313763fae79SScott Long /* Dump out the configuration. */ 314763fae79SScott Long printf("mfi%d Configuration: %d arrays, %d volumes, %d spares\n", 315763fae79SScott Long mfi_unit, config->array_count, config->log_drv_count, 316763fae79SScott Long config->spares_count); 317763fae79SScott Long p = (char *)config->array; 318763fae79SScott Long 319763fae79SScott Long for (i = 0; i < config->array_count; i++) { 320763fae79SScott Long ar = (struct mfi_array *)p; 321763fae79SScott Long printf(" array %u of %u drives:\n", ar->array_ref, 322763fae79SScott Long ar->num_drives); 323763fae79SScott Long for (j = 0; j < ar->num_drives; j++) { 324763fae79SScott Long device_id = ar->pd[j].ref.v.device_id; 325763fae79SScott Long if (device_id == 0xffff) 326763fae79SScott Long printf(" drive MISSING\n"); 327763fae79SScott Long else { 328763fae79SScott Long printf(" drive %u ", device_id); 329763fae79SScott Long if (mfi_pd_get_info(fd, device_id, &pinfo, 330763fae79SScott Long NULL) < 0) 331763fae79SScott Long printf("%s", 332763fae79SScott Long mfi_pdstate(ar->pd[j].fw_state)); 333763fae79SScott Long else 334763fae79SScott Long print_pd(&pinfo, -1, 1); 335763fae79SScott Long printf("\n"); 336763fae79SScott Long } 337763fae79SScott Long } 338763fae79SScott Long p += config->array_size; 339763fae79SScott Long } 340763fae79SScott Long 341763fae79SScott Long for (i = 0; i < config->log_drv_count; i++) { 342763fae79SScott Long ld = (struct mfi_ld_config *)p; 343763fae79SScott Long printf(" volume %s ", 344763fae79SScott Long mfi_volume_name(fd, ld->properties.ld.v.target_id)); 345763fae79SScott Long if (mfi_ld_get_info(fd, ld->properties.ld.v.target_id, &linfo, 346763fae79SScott Long NULL) < 0) { 347763fae79SScott Long printf("%s %s", 348763fae79SScott Long mfi_raid_level(ld->params.primary_raid_level, 349763fae79SScott Long ld->params.secondary_raid_level), 350763fae79SScott Long mfi_ldstate(ld->params.state)); 351763fae79SScott Long } else 352763fae79SScott Long print_ld(&linfo, -1); 353763fae79SScott Long if (ld->properties.name[0] != '\0') 354763fae79SScott Long printf(" <%s>", ld->properties.name); 355763fae79SScott Long printf(" spans:\n"); 356763fae79SScott Long for (j = 0; j < ld->params.span_depth; j++) 357763fae79SScott Long printf(" array %u\n", ld->span[j].array_ref); 358763fae79SScott Long p += config->log_drv_size; 359763fae79SScott Long } 360763fae79SScott Long 361763fae79SScott Long for (i = 0; i < config->spares_count; i++) { 362763fae79SScott Long sp = (struct mfi_spare *)p; 363763fae79SScott Long printf(" %s spare %u ", 364763fae79SScott Long sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : 365763fae79SScott Long "global", sp->ref.v.device_id); 366763fae79SScott Long if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0) 367763fae79SScott Long printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); 368763fae79SScott Long else 369763fae79SScott Long print_pd(&pinfo, -1, 1); 370763fae79SScott Long if (sp->spare_type & MFI_SPARE_DEDICATED) { 371763fae79SScott Long printf(" backs:\n"); 372763fae79SScott Long for (j = 0; j < sp->array_count; j++) 373763fae79SScott Long printf(" array %u\n", sp->array_ref[j]); 374763fae79SScott Long } else 375763fae79SScott Long printf("\n"); 376763fae79SScott Long p += config->spares_size; 377763fae79SScott Long } 378763fae79SScott Long close(fd); 379763fae79SScott Long 380763fae79SScott Long return (0); 381763fae79SScott Long } 382763fae79SScott Long MFI_COMMAND(show, config, show_config); 383763fae79SScott Long 384763fae79SScott Long static int 385763fae79SScott Long show_volumes(int ac, char **av) 386763fae79SScott Long { 387763fae79SScott Long struct mfi_ld_list list; 388763fae79SScott Long struct mfi_ld_info info; 389c02999d9SJohn Baldwin int error, fd; 390763fae79SScott Long u_int i, len, state_len; 391763fae79SScott Long 392763fae79SScott Long if (ac != 1) { 393763fae79SScott Long warnx("show volumes: extra arguments"); 394763fae79SScott Long return (EINVAL); 395763fae79SScott Long } 396763fae79SScott Long 397763fae79SScott Long fd = mfi_open(mfi_unit); 398763fae79SScott Long if (fd < 0) { 399c02999d9SJohn Baldwin error = errno; 400763fae79SScott Long warn("mfi_open"); 401c02999d9SJohn Baldwin return (error); 402763fae79SScott Long } 403763fae79SScott Long 404763fae79SScott Long /* Get the logical drive list from the controller. */ 405763fae79SScott Long if (mfi_ld_get_list(fd, &list, NULL) < 0) { 406c02999d9SJohn Baldwin error = errno; 407763fae79SScott Long warn("Failed to get volume list"); 408c02999d9SJohn Baldwin return (error); 409763fae79SScott Long } 410763fae79SScott Long 411763fae79SScott Long /* List the volumes. */ 412763fae79SScott Long printf("mfi%d Volumes:\n", mfi_unit); 413763fae79SScott Long state_len = strlen("State"); 414763fae79SScott Long for (i = 0; i < list.ld_count; i++) { 415763fae79SScott Long len = strlen(mfi_ldstate(list.ld_list[i].state)); 416763fae79SScott Long if (len > state_len) 417763fae79SScott Long state_len = len; 418763fae79SScott Long } 419763fae79SScott Long printf(" Id Size Level Stripe "); 420763fae79SScott Long len = state_len - strlen("State"); 421763fae79SScott Long for (i = 0; i < (len + 1) / 2; i++) 422763fae79SScott Long printf(" "); 423763fae79SScott Long printf("State"); 424763fae79SScott Long for (i = 0; i < len / 2; i++) 425763fae79SScott Long printf(" "); 426763fae79SScott Long printf(" Cache Name\n"); 427763fae79SScott Long for (i = 0; i < list.ld_count; i++) { 428763fae79SScott Long if (mfi_ld_get_info(fd, list.ld_list[i].ld.v.target_id, &info, 429763fae79SScott Long NULL) < 0) { 430c02999d9SJohn Baldwin error = errno; 431763fae79SScott Long warn("Failed to get info for volume %d", 432763fae79SScott Long list.ld_list[i].ld.v.target_id); 433c02999d9SJohn Baldwin return (error); 434763fae79SScott Long } 435763fae79SScott Long printf("%6s ", 436763fae79SScott Long mfi_volume_name(fd, list.ld_list[i].ld.v.target_id)); 437763fae79SScott Long print_ld(&info, state_len); 438763fae79SScott Long switch (info.ld_config.properties.current_cache_policy & 439763fae79SScott Long (MR_LD_CACHE_ALLOW_WRITE_CACHE | 440763fae79SScott Long MR_LD_CACHE_ALLOW_READ_CACHE)) { 441763fae79SScott Long case 0: 442763fae79SScott Long printf(" Disabled"); 443763fae79SScott Long break; 444763fae79SScott Long case MR_LD_CACHE_ALLOW_READ_CACHE: 445763fae79SScott Long printf(" Reads "); 446763fae79SScott Long break; 447763fae79SScott Long case MR_LD_CACHE_ALLOW_WRITE_CACHE: 448763fae79SScott Long printf(" Writes "); 449763fae79SScott Long break; 450763fae79SScott Long case MR_LD_CACHE_ALLOW_WRITE_CACHE | 451763fae79SScott Long MR_LD_CACHE_ALLOW_READ_CACHE: 452763fae79SScott Long printf(" Enabled "); 453763fae79SScott Long break; 454763fae79SScott Long } 455763fae79SScott Long if (info.ld_config.properties.name[0] != '\0') 456763fae79SScott Long printf(" <%s>", info.ld_config.properties.name); 457763fae79SScott Long printf("\n"); 458763fae79SScott Long } 459763fae79SScott Long close(fd); 460763fae79SScott Long 461763fae79SScott Long return (0); 462763fae79SScott Long } 463763fae79SScott Long MFI_COMMAND(show, volumes, show_volumes); 464763fae79SScott Long 465763fae79SScott Long static int 466763fae79SScott Long show_drives(int ac, char **av) 467763fae79SScott Long { 468763fae79SScott Long struct mfi_pd_list *list; 469763fae79SScott Long struct mfi_pd_info info; 470763fae79SScott Long u_int i, len, state_len; 471c02999d9SJohn Baldwin int error, fd; 472763fae79SScott Long 473763fae79SScott Long if (ac != 1) { 474763fae79SScott Long warnx("show drives: extra arguments"); 475763fae79SScott Long return (EINVAL); 476763fae79SScott Long } 477763fae79SScott Long 478763fae79SScott Long fd = mfi_open(mfi_unit); 479763fae79SScott Long if (fd < 0) { 480c02999d9SJohn Baldwin error = errno; 481763fae79SScott Long warn("mfi_open"); 482c02999d9SJohn Baldwin return (error); 483763fae79SScott Long } 484763fae79SScott Long 485763fae79SScott Long if (mfi_pd_get_list(fd, &list, NULL) < 0) { 486c02999d9SJohn Baldwin error = errno; 487763fae79SScott Long warn("Failed to get drive list"); 488c02999d9SJohn Baldwin return (error); 489763fae79SScott Long } 490763fae79SScott Long 491763fae79SScott Long /* Walk the list of drives to determine width of state column. */ 492763fae79SScott Long state_len = 0; 493763fae79SScott Long for (i = 0; i < list->count; i++) { 494763fae79SScott Long if (list->addr[i].scsi_dev_type != 0) 495763fae79SScott Long continue; 496763fae79SScott Long 497763fae79SScott Long if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 498763fae79SScott Long NULL) < 0) { 499c02999d9SJohn Baldwin error = errno; 500763fae79SScott Long warn("Failed to fetch info for drive %u", 501763fae79SScott Long list->addr[i].device_id); 502c02999d9SJohn Baldwin return (error); 503763fae79SScott Long } 504763fae79SScott Long len = strlen(mfi_pdstate(info.fw_state)); 505763fae79SScott Long if (len > state_len) 506763fae79SScott Long state_len = len; 507763fae79SScott Long } 508763fae79SScott Long 509763fae79SScott Long /* List the drives. */ 510763fae79SScott Long printf("mfi%d Physical Drives:\n", mfi_unit); 511763fae79SScott Long for (i = 0; i < list->count; i++) { 512763fae79SScott Long 513763fae79SScott Long /* Skip non-hard disks. */ 514763fae79SScott Long if (list->addr[i].scsi_dev_type != 0) 515763fae79SScott Long continue; 516763fae79SScott Long 517763fae79SScott Long /* Fetch details for this drive. */ 518763fae79SScott Long if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 519763fae79SScott Long NULL) < 0) { 520c02999d9SJohn Baldwin error = errno; 521763fae79SScott Long warn("Failed to fetch info for drive %u", 522763fae79SScott Long list->addr[i].device_id); 523c02999d9SJohn Baldwin return (error); 524763fae79SScott Long } 525763fae79SScott Long 526763fae79SScott Long print_pd(&info, state_len, 1); 527763fae79SScott Long printf("\n"); 528763fae79SScott Long } 529763fae79SScott Long close(fd); 530763fae79SScott Long 531763fae79SScott Long return (0); 532763fae79SScott Long } 533763fae79SScott Long MFI_COMMAND(show, drives, show_drives); 534763fae79SScott Long 535763fae79SScott Long int fw_name_width, fw_version_width, fw_date_width, fw_time_width; 536763fae79SScott Long 537763fae79SScott Long static void 538763fae79SScott Long scan_firmware(struct mfi_info_component *comp) 539763fae79SScott Long { 540763fae79SScott Long int len; 541763fae79SScott Long 542763fae79SScott Long len = strlen(comp->name); 543763fae79SScott Long if (fw_name_width < len) 544763fae79SScott Long fw_name_width = len; 545763fae79SScott Long len = strlen(comp->version); 546763fae79SScott Long if (fw_version_width < len) 547763fae79SScott Long fw_version_width = len; 548763fae79SScott Long len = strlen(comp->build_date); 549763fae79SScott Long if (fw_date_width < len) 550763fae79SScott Long fw_date_width = len; 551763fae79SScott Long len = strlen(comp->build_time); 552763fae79SScott Long if (fw_time_width < len) 553763fae79SScott Long fw_time_width = len; 554763fae79SScott Long } 555763fae79SScott Long 556763fae79SScott Long static void 557763fae79SScott Long display_firmware(struct mfi_info_component *comp, const char *tag) 558763fae79SScott Long { 559763fae79SScott Long 560763fae79SScott Long printf("%-*s %-*s %-*s %-*s %s\n", fw_name_width, comp->name, 561763fae79SScott Long fw_version_width, comp->version, fw_date_width, comp->build_date, 562763fae79SScott Long fw_time_width, comp->build_time, tag); 563763fae79SScott Long } 564763fae79SScott Long 565763fae79SScott Long static int 566763fae79SScott Long show_firmware(int ac, char **av) 567763fae79SScott Long { 568763fae79SScott Long struct mfi_ctrl_info info; 569763fae79SScott Long struct mfi_info_component header; 570c02999d9SJohn Baldwin int error, fd; 571763fae79SScott Long u_int i; 572763fae79SScott Long 573763fae79SScott Long if (ac != 1) { 574763fae79SScott Long warnx("show drives: extra arguments"); 575763fae79SScott Long return (EINVAL); 576763fae79SScott Long } 577763fae79SScott Long 578763fae79SScott Long fd = mfi_open(mfi_unit); 579763fae79SScott Long if (fd < 0) { 580c02999d9SJohn Baldwin error = errno; 581763fae79SScott Long warn("mfi_open"); 582c02999d9SJohn Baldwin return (error); 583763fae79SScott Long } 584763fae79SScott Long 585763fae79SScott Long if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 586c02999d9SJohn Baldwin error = errno; 587763fae79SScott Long warn("Failed to get controller info"); 588c02999d9SJohn Baldwin return (error); 589763fae79SScott Long } 590763fae79SScott Long 591763fae79SScott Long if (info.package_version[0] != '\0') 592763fae79SScott Long printf("mfi%d Firmware Package Version: %s\n", mfi_unit, 593763fae79SScott Long info.package_version); 594763fae79SScott Long printf("mfi%d Firmware Images:\n", mfi_unit); 595763fae79SScott Long strcpy(header.name, "Name"); 596763fae79SScott Long strcpy(header.version, "Version"); 597763fae79SScott Long strcpy(header.build_date, "Date"); 598763fae79SScott Long strcpy(header.build_time, "Time"); 599763fae79SScott Long scan_firmware(&header); 600763fae79SScott Long if (info.image_component_count > 8) 601763fae79SScott Long info.image_component_count = 8; 602763fae79SScott Long for (i = 0; i < info.image_component_count; i++) 603763fae79SScott Long scan_firmware(&info.image_component[i]); 604763fae79SScott Long if (info.pending_image_component_count > 8) 605763fae79SScott Long info.pending_image_component_count = 8; 606763fae79SScott Long for (i = 0; i < info.pending_image_component_count; i++) 607763fae79SScott Long scan_firmware(&info.pending_image_component[i]); 608763fae79SScott Long display_firmware(&header, "Status"); 609763fae79SScott Long for (i = 0; i < info.image_component_count; i++) 610763fae79SScott Long display_firmware(&info.image_component[i], "active"); 611763fae79SScott Long for (i = 0; i < info.pending_image_component_count; i++) 612763fae79SScott Long display_firmware(&info.pending_image_component[i], "pending"); 613763fae79SScott Long 614763fae79SScott Long close(fd); 615763fae79SScott Long 616763fae79SScott Long return (0); 617763fae79SScott Long } 618763fae79SScott Long MFI_COMMAND(show, firmware, show_firmware); 619