static int foreign_show_cfg(int fd, uint32_t opcode, uint8_t cfgidx, int diagnostic) { struct mfi_config_data *config; char prefix[26]; int error; uint8_t mbox[4]; bzero(mbox, sizeof(mbox)); mbox[0] = cfgidx; if (mfi_config_read_opcode(fd, opcode, &config, mbox, sizeof(mbox)) < 0) { error = errno; warn("Failed to get foreign config %d", error); close(fd); return (error); } if (opcode == MFI_DCMD_CFG_FOREIGN_PREVIEW) sprintf(prefix, "Foreign configuration preview %d", cfgidx); else sprintf(prefix, "Foreign configuration %d", cfgidx); /* * MegaCli uses DCMD opcodes: 0x03100200 (which fails) followed by * 0x1a721880 which returns what looks to be drive / volume info * but we have no real information on what these are or what they do * so we're currently relying solely on the config returned above */ if (diagnostic) dump_config(fd, config, prefix); else { char *ld_list; int i; ld_list = (char *)(config->array); printf("%s: %d arrays, %d volumes, %d spares\n", prefix, config->array_count, config->log_drv_count, config->spares_count); for (i = 0; i < config->array_count; i++) ld_list += config->array_size; for (i = 0; i < config->log_drv_count; i++) { const char *level; char size[6], stripe[5]; struct mfi_ld_config *ld; ld = (struct mfi_ld_config *)ld_list; format_stripe(stripe, sizeof(stripe), ld->params.stripe_size); /* * foreign configs don't seem to have a secondary raid level * but, we can use span depth here as if a LD spans multiple * arrays of disks (2 raid 1 sets for example), we will have an * indication based on the spam depth. swb */ level = mfi_raid_level(ld->params.primary_raid_level, (ld->params.span_depth - 1)); humanize_number(size, sizeof(size), ld->span[0].num_blocks * 512, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); printf(" ID%d ", i); printf("(%6s) %-8s |", size, level); printf("volume spans %d %s\n", ld->params.span_depth, (ld->params.span_depth > 1) ? "arrays" : "array"); for (int j = 0; j < ld->params.span_depth; j++) { char *ar_list; struct mfi_array *ar; uint16_t device_id; printf(" array %u @ ", ld->span[j].array_ref); humanize_number(size, sizeof(size), ld->span[j].num_blocks * 512, "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); printf("(%6s)\n",size); ar_list = (char *)config->array + (ld->span[j].array_ref * config->array_size); ar = (struct mfi_array *)ar_list; for (int k = 0; k < ar->num_drives; k++) { device_id = ar->pd[k].ref.v.device_id; if (device_id == 0xffff) printf(" drive MISSING\n"); else { printf(" drive %u %s\n", device_id, mfi_pdstate(ar->pd[k].fw_state)); } } } ld_list += config->log_drv_size; } } free(config); return (0); }
/* Display raw data about a config. */ static void dump_config(int fd, struct mfi_config_data *config) { struct mfi_array *ar; struct mfi_ld_config *ld; struct mfi_spare *sp; struct mfi_pd_info pinfo; uint16_t device_id; char *p; int i, j; printf( "mfi%d Configuration (Debug): %d arrays, %d volumes, %d spares\n", mfi_unit, config->array_count, config->log_drv_count, config->spares_count); printf(" array size: %u\n", config->array_size); printf(" volume size: %u\n", config->log_drv_size); printf(" spare size: %u\n", config->spares_size); p = (char *)config->array; for (i = 0; i < config->array_count; i++) { ar = (struct mfi_array *)p; printf(" array %u of %u drives:\n", ar->array_ref, ar->num_drives); printf(" size = %ju\n", (uintmax_t)ar->size); for (j = 0; j < ar->num_drives; j++) { device_id = ar->pd[j].ref.v.device_id; if (device_id == 0xffff) printf(" drive MISSING\n"); else { printf(" drive %u %s\n", device_id, mfi_pdstate(ar->pd[j].fw_state)); if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) >= 0) { printf(" raw size: %ju\n", (uintmax_t)pinfo.raw_size); printf(" non-coerced size: %ju\n", (uintmax_t)pinfo.non_coerced_size); printf(" coerced size: %ju\n", (uintmax_t)pinfo.coerced_size); } } } p += config->array_size; } for (i = 0; i < config->log_drv_count; i++) { ld = (struct mfi_ld_config *)p; printf(" volume %s ", mfi_volume_name(fd, ld->properties.ld.v.target_id)); printf("%s %s", mfi_raid_level(ld->params.primary_raid_level, ld->params.secondary_raid_level), mfi_ldstate(ld->params.state)); if (ld->properties.name[0] != '\0') printf(" <%s>", ld->properties.name); printf("\n"); printf(" primary raid level: %u\n", ld->params.primary_raid_level); printf(" raid level qualifier: %u\n", ld->params.raid_level_qualifier); printf(" secondary raid level: %u\n", ld->params.secondary_raid_level); printf(" stripe size: %u\n", ld->params.stripe_size); printf(" num drives: %u\n", ld->params.num_drives); printf(" init state: %u\n", ld->params.init_state); printf(" consistent: %u\n", ld->params.is_consistent); printf(" no bgi: %u\n", ld->properties.no_bgi); printf(" spans:\n"); for (j = 0; j < ld->params.span_depth; j++) { printf(" array %u @ ", ld->span[j].array_ref); printf("%ju : %ju\n", (uintmax_t)ld->span[j].start_block, (uintmax_t)ld->span[j].num_blocks); } p += config->log_drv_size; } for (i = 0; i < config->spares_count; i++) { sp = (struct mfi_spare *)p; printf(" %s spare %u ", sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : "global", sp->ref.v.device_id); printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); printf(" backs:\n"); for (j = 0; j < sp->array_count; j++) printf(" array %u\n", sp->array_ref[j]); p += config->spares_size; } }