1196200Sscottl/*- 2196200Sscottl * Copyright (c) 2008, 2009 Yahoo!, Inc. 3196200Sscottl * All rights reserved. 4196200Sscottl * 5196200Sscottl * Redistribution and use in source and binary forms, with or without 6196200Sscottl * modification, are permitted provided that the following conditions 7196200Sscottl * are met: 8196200Sscottl * 1. Redistributions of source code must retain the above copyright 9196200Sscottl * notice, this list of conditions and the following disclaimer. 10196200Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11196200Sscottl * notice, this list of conditions and the following disclaimer in the 12196200Sscottl * documentation and/or other materials provided with the distribution. 13196200Sscottl * 3. The names of the authors may not be used to endorse or promote 14196200Sscottl * products derived from this software without specific prior written 15196200Sscottl * permission. 16196200Sscottl * 17196200Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18196200Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19196200Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20196200Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21196200Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22196200Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23196200Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24196200Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25196200Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26196200Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27196200Sscottl * SUCH DAMAGE. 28196200Sscottl * 29196200Sscottl * $FreeBSD$ 30196200Sscottl */ 31196200Sscottl 32196200Sscottl#include <sys/types.h> 33196200Sscottl#include <sys/errno.h> 34196200Sscottl#include <err.h> 35237589Seadler#include <fcntl.h> 36196200Sscottl#include <libutil.h> 37196200Sscottl#include <stdio.h> 38196200Sscottl#include <stdlib.h> 39196200Sscottl#include <string.h> 40196200Sscottl#include <unistd.h> 41196200Sscottl#include "mfiutil.h" 42196200Sscottl 43253244Ssbrunostatic const char* foreign_state = " (FOREIGN)"; 44253244Ssbruno 45196200SscottlMFI_TABLE(top, show); 46196200Sscottl 47253244Ssbrunovoid 48196200Sscottlformat_stripe(char *buf, size_t buflen, uint8_t stripe) 49196200Sscottl{ 50196200Sscottl 51196200Sscottl humanize_number(buf, buflen, (1 << stripe) * 512, "", HN_AUTOSCALE, 52196200Sscottl HN_B | HN_NOSPACE); 53196200Sscottl} 54196200Sscottl 55196200Sscottlstatic int 56237589Seadlershow_adapter(int ac, char **av __unused) 57196200Sscottl{ 58196200Sscottl struct mfi_ctrl_info info; 59196200Sscottl char stripe[5]; 60214396Sjhb int error, fd, comma; 61196200Sscottl 62196200Sscottl if (ac != 1) { 63196200Sscottl warnx("show adapter: extra arguments"); 64196200Sscottl return (EINVAL); 65196200Sscottl } 66196200Sscottl 67237589Seadler fd = mfi_open(mfi_unit, O_RDONLY); 68196200Sscottl if (fd < 0) { 69214396Sjhb error = errno; 70196200Sscottl warn("mfi_open"); 71214396Sjhb return (error); 72196200Sscottl } 73196200Sscottl 74196200Sscottl if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 75214396Sjhb error = errno; 76196200Sscottl warn("Failed to get controller info"); 77222899Sbz close(fd); 78214396Sjhb return (error); 79196200Sscottl } 80196200Sscottl printf("mfi%d Adapter:\n", mfi_unit); 81196200Sscottl printf(" Product Name: %.80s\n", info.product_name); 82196200Sscottl printf(" Serial Number: %.32s\n", info.serial_number); 83196200Sscottl if (info.package_version[0] != '\0') 84196200Sscottl printf(" Firmware: %s\n", info.package_version); 85196200Sscottl printf(" RAID Levels:"); 86196200Sscottl#ifdef DEBUG 87196200Sscottl printf(" (%#x)", info.raid_levels); 88196200Sscottl#endif 89196200Sscottl comma = 0; 90196200Sscottl if (info.raid_levels & MFI_INFO_RAID_0) { 91196200Sscottl printf(" JBOD, RAID0"); 92196200Sscottl comma = 1; 93196200Sscottl } 94196200Sscottl if (info.raid_levels & MFI_INFO_RAID_1) { 95196200Sscottl printf("%s RAID1", comma ? "," : ""); 96196200Sscottl comma = 1; 97196200Sscottl } 98196200Sscottl if (info.raid_levels & MFI_INFO_RAID_5) { 99196200Sscottl printf("%s RAID5", comma ? "," : ""); 100196200Sscottl comma = 1; 101196200Sscottl } 102196200Sscottl if (info.raid_levels & MFI_INFO_RAID_1E) { 103196200Sscottl printf("%s RAID1E", comma ? "," : ""); 104196200Sscottl comma = 1; 105196200Sscottl } 106196200Sscottl if (info.raid_levels & MFI_INFO_RAID_6) { 107196200Sscottl printf("%s RAID6", comma ? "," : ""); 108196200Sscottl comma = 1; 109196200Sscottl } 110196200Sscottl if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) == 111196200Sscottl (MFI_INFO_RAID_0 | MFI_INFO_RAID_1)) { 112196200Sscottl printf("%s RAID10", comma ? "," : ""); 113196200Sscottl comma = 1; 114196200Sscottl } 115196200Sscottl if ((info.raid_levels & (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) == 116196200Sscottl (MFI_INFO_RAID_0 | MFI_INFO_RAID_5)) { 117196200Sscottl printf("%s RAID50", comma ? "," : ""); 118196200Sscottl comma = 1; 119196200Sscottl } 120196200Sscottl printf("\n"); 121196200Sscottl printf(" Battery Backup: "); 122196200Sscottl if (info.hw_present & MFI_INFO_HW_BBU) 123196200Sscottl printf("present\n"); 124196200Sscottl else 125196200Sscottl printf("not present\n"); 126196200Sscottl if (info.hw_present & MFI_INFO_HW_NVRAM) 127196200Sscottl printf(" NVRAM: %uK\n", info.nvram_size); 128196200Sscottl printf(" Onboard Memory: %uM\n", info.memory_size); 129196200Sscottl format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.min); 130196200Sscottl printf(" Minimum Stripe: %s\n", stripe); 131196200Sscottl format_stripe(stripe, sizeof(stripe), info.stripe_sz_ops.max); 132196200Sscottl printf(" Maximum Stripe: %s\n", stripe); 133196200Sscottl 134196200Sscottl close(fd); 135196200Sscottl 136196200Sscottl return (0); 137196200Sscottl} 138196200SscottlMFI_COMMAND(show, adapter, show_adapter); 139196200Sscottl 140196200Sscottlstatic int 141237589Seadlershow_battery(int ac, char **av __unused) 142196200Sscottl{ 143196200Sscottl struct mfi_bbu_capacity_info cap; 144196200Sscottl struct mfi_bbu_design_info design; 145250482Smarkj struct mfi_bbu_properties props; 146219717Sjhb struct mfi_bbu_status stat; 147196200Sscottl uint8_t status; 148250482Smarkj int comma, error, fd, show_capacity, show_props; 149250482Smarkj char buf[32]; 150196200Sscottl 151196200Sscottl if (ac != 1) { 152196200Sscottl warnx("show battery: extra arguments"); 153196200Sscottl return (EINVAL); 154196200Sscottl } 155196200Sscottl 156237589Seadler fd = mfi_open(mfi_unit, O_RDONLY); 157196200Sscottl if (fd < 0) { 158214396Sjhb error = errno; 159196200Sscottl warn("mfi_open"); 160214396Sjhb return (error); 161196200Sscottl } 162196200Sscottl 163196200Sscottl if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_CAPACITY_INFO, &cap, 164196200Sscottl sizeof(cap), NULL, 0, &status) < 0) { 165214396Sjhb error = errno; 166196200Sscottl warn("Failed to get capacity info"); 167222899Sbz close(fd); 168214396Sjhb return (error); 169196200Sscottl } 170225804Semaste if (status == MFI_STAT_NO_HW_PRESENT) { 171225804Semaste printf("mfi%d: No battery present\n", mfi_unit); 172225804Semaste close(fd); 173225804Semaste return (0); 174225804Semaste } 175225804Semaste show_capacity = (status == MFI_STAT_OK); 176196200Sscottl 177196200Sscottl if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_DESIGN_INFO, &design, 178196200Sscottl sizeof(design), NULL, 0, NULL) < 0) { 179214396Sjhb error = errno; 180196200Sscottl warn("Failed to get design info"); 181222899Sbz close(fd); 182214396Sjhb return (error); 183196200Sscottl } 184196200Sscottl 185219717Sjhb if (mfi_dcmd_command(fd, MFI_DCMD_BBU_GET_STATUS, &stat, sizeof(stat), 186219717Sjhb NULL, 0, NULL) < 0) { 187219722Sjhb error = errno; 188219717Sjhb warn("Failed to get status"); 189222899Sbz close(fd); 190219722Sjhb return (error); 191219717Sjhb } 192219717Sjhb 193250482Smarkj if (mfi_bbu_get_props(fd, &props, &status) < 0) { 194250482Smarkj error = errno; 195250482Smarkj warn("Failed to get properties"); 196250482Smarkj close(fd); 197250482Smarkj return (error); 198250482Smarkj } 199250482Smarkj show_props = (status == MFI_STAT_OK); 200250482Smarkj 201196200Sscottl printf("mfi%d: Battery State:\n", mfi_unit); 202219717Sjhb printf(" Manufacture Date: %d/%d/%d\n", design.mfg_date >> 5 & 0x0f, 203196200Sscottl design.mfg_date & 0x1f, design.mfg_date >> 9 & 0xffff); 204219717Sjhb printf(" Serial Number: %d\n", design.serial_number); 205219717Sjhb printf(" Manufacturer: %s\n", design.mfg_name); 206219717Sjhb printf(" Model: %s\n", design.device_name); 207219717Sjhb printf(" Chemistry: %s\n", design.device_chemistry); 208219717Sjhb printf(" Design Capacity: %d mAh\n", design.design_capacity); 209225804Semaste if (show_capacity) { 210225804Semaste printf(" Full Charge Capacity: %d mAh\n", 211225804Semaste cap.full_charge_capacity); 212225804Semaste printf(" Current Capacity: %d mAh\n", 213225804Semaste cap.remaining_capacity); 214225804Semaste printf(" Charge Cycles: %d\n", cap.cycle_count); 215225804Semaste printf(" Current Charge: %d%%\n", cap.relative_charge); 216225804Semaste } 217219717Sjhb printf(" Design Voltage: %d mV\n", design.design_voltage); 218219717Sjhb printf(" Current Voltage: %d mV\n", stat.voltage); 219219717Sjhb printf(" Temperature: %d C\n", stat.temperature); 220250482Smarkj if (show_props) { 221250482Smarkj mfi_autolearn_period(props.auto_learn_period, buf, sizeof(buf)); 222250482Smarkj printf(" Autolearn period: %s\n", buf); 223250482Smarkj if (props.auto_learn_mode != 0) 224250482Smarkj snprintf(buf, sizeof(buf), "never"); 225250482Smarkj else 226250482Smarkj mfi_next_learn_time(props.next_learn_time, buf, 227250482Smarkj sizeof(buf)); 228250482Smarkj printf(" Next learn time: %s\n", buf); 229250482Smarkj printf(" Learn delay interval: %u hour%s\n", 230250482Smarkj props.learn_delay_interval, 231250482Smarkj props.learn_delay_interval != 1 ? "s" : ""); 232250482Smarkj mfi_autolearn_mode(props.auto_learn_mode, buf, sizeof(buf)); 233250482Smarkj printf(" Autolearn mode: %s\n", buf); 234250482Smarkj if (props.bbu_mode != 0) 235250482Smarkj printf(" BBU Mode: %d\n", props.bbu_mode); 236250482Smarkj } 237219717Sjhb printf(" Status:"); 238219717Sjhb comma = 0; 239219717Sjhb if (stat.fw_status & MFI_BBU_STATE_PACK_MISSING) { 240219717Sjhb printf(" PACK_MISSING"); 241219717Sjhb comma = 1; 242219717Sjhb } 243219717Sjhb if (stat.fw_status & MFI_BBU_STATE_VOLTAGE_LOW) { 244219717Sjhb printf("%s VOLTAGE_LOW", comma ? "," : ""); 245219717Sjhb comma = 1; 246219717Sjhb } 247219717Sjhb if (stat.fw_status & MFI_BBU_STATE_TEMPERATURE_HIGH) { 248219717Sjhb printf("%s TEMPERATURE_HIGH", comma ? "," : ""); 249219717Sjhb comma = 1; 250219717Sjhb } 251219717Sjhb if (stat.fw_status & MFI_BBU_STATE_CHARGE_ACTIVE) { 252219717Sjhb printf("%s CHARGING", comma ? "," : ""); 253219717Sjhb comma = 1; 254219717Sjhb } 255219717Sjhb if (stat.fw_status & MFI_BBU_STATE_DISCHARGE_ACTIVE) { 256219717Sjhb printf("%s DISCHARGING", comma ? "," : ""); 257235914Ssbruno comma = 1; 258219717Sjhb } 259235914Ssbruno if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_REQ) { 260235914Ssbruno printf("%s LEARN_CYCLE_REQUESTED", comma ? "," : ""); 261235914Ssbruno comma = 1; 262235914Ssbruno } 263235914Ssbruno if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_ACTIVE) { 264235914Ssbruno printf("%s LEARN_CYCLE_ACTIVE", comma ? "," : ""); 265235914Ssbruno comma = 1; 266235914Ssbruno } 267235914Ssbruno if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_FAIL) { 268235914Ssbruno printf("%s LEARN_CYCLE_FAIL", comma ? "," : ""); 269235914Ssbruno comma = 1; 270235914Ssbruno } 271235914Ssbruno if (stat.fw_status & MFI_BBU_STATE_LEARN_CYC_TIMEOUT) { 272235914Ssbruno printf("%s LEARN_CYCLE_TIMEOUT", comma ? "," : ""); 273235914Ssbruno comma = 1; 274235914Ssbruno } 275235914Ssbruno if (stat.fw_status & MFI_BBU_STATE_I2C_ERR_DETECT) { 276235914Ssbruno printf("%s I2C_ERROR_DETECT", comma ? "," : ""); 277235914Ssbruno comma = 1; 278235914Ssbruno } 279235914Ssbruno 280219717Sjhb if (!comma) 281219717Sjhb printf(" normal"); 282219717Sjhb printf("\n"); 283219717Sjhb switch (stat.battery_type) { 284219717Sjhb case MFI_BBU_TYPE_BBU: 285219717Sjhb printf(" State of Health: %s\n", 286219717Sjhb stat.detail.bbu.is_SOH_good ? "good" : "bad"); 287219717Sjhb break; 288219717Sjhb } 289196200Sscottl 290196200Sscottl close(fd); 291196200Sscottl 292196200Sscottl return (0); 293196200Sscottl} 294196200SscottlMFI_COMMAND(show, battery, show_battery); 295196200Sscottl 296253244Ssbrunovoid 297196200Sscottlprint_ld(struct mfi_ld_info *info, int state_len) 298196200Sscottl{ 299196200Sscottl struct mfi_ld_params *params = &info->ld_config.params; 300196200Sscottl const char *level; 301196200Sscottl char size[6], stripe[5]; 302196200Sscottl 303196200Sscottl humanize_number(size, sizeof(size), info->size * 512, 304196200Sscottl "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 305196200Sscottl format_stripe(stripe, sizeof(stripe), 306196200Sscottl info->ld_config.params.stripe_size); 307196200Sscottl level = mfi_raid_level(params->primary_raid_level, 308196200Sscottl params->secondary_raid_level); 309196200Sscottl if (state_len > 0) 310196200Sscottl printf("(%6s) %-8s %6s %-*s", size, level, stripe, state_len, 311196200Sscottl mfi_ldstate(params->state)); 312196200Sscottl else 313196200Sscottl printf("(%s) %s %s %s", size, level, stripe, 314196200Sscottl mfi_ldstate(params->state)); 315196200Sscottl} 316196200Sscottl 317253244Ssbrunovoid 318223345Sbzprint_pd(struct mfi_pd_info *info, int state_len) 319196200Sscottl{ 320196200Sscottl const char *s; 321253244Ssbruno char buf[256]; 322196200Sscottl 323260325Ssbruno humanize_number(buf, 6, info->raw_size * 512, "", 324196200Sscottl HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL); 325196200Sscottl printf("(%6s) ", buf); 326253244Ssbruno if (info->state.ddf.v.pd_type.is_foreign) { 327253244Ssbruno sprintf(buf, "%s%s", mfi_pdstate(info->fw_state), foreign_state); 328253244Ssbruno s = buf; 329253244Ssbruno } else 330253244Ssbruno s = mfi_pdstate(info->fw_state); 331196200Sscottl if (state_len > 0) 332253244Ssbruno printf("%-*s", state_len, s); 333196200Sscottl else 334253244Ssbruno printf("%s",s); 335196200Sscottl s = mfi_pd_inq_string(info); 336196200Sscottl if (s != NULL) 337196200Sscottl printf(" %s", s); 338196200Sscottl} 339196200Sscottl 340196200Sscottlstatic int 341237589Seadlershow_config(int ac, char **av __unused) 342196200Sscottl{ 343196200Sscottl struct mfi_config_data *config; 344196200Sscottl struct mfi_array *ar; 345196200Sscottl struct mfi_ld_config *ld; 346196200Sscottl struct mfi_spare *sp; 347196200Sscottl struct mfi_ld_info linfo; 348196200Sscottl struct mfi_pd_info pinfo; 349196200Sscottl uint16_t device_id; 350196200Sscottl char *p; 351214396Sjhb int error, fd, i, j; 352196200Sscottl 353196200Sscottl if (ac != 1) { 354196200Sscottl warnx("show config: extra arguments"); 355196200Sscottl return (EINVAL); 356196200Sscottl } 357196200Sscottl 358237589Seadler fd = mfi_open(mfi_unit, O_RDONLY); 359196200Sscottl if (fd < 0) { 360214396Sjhb error = errno; 361196200Sscottl warn("mfi_open"); 362214396Sjhb return (error); 363196200Sscottl } 364196200Sscottl 365196200Sscottl /* Get the config from the controller. */ 366196200Sscottl if (mfi_config_read(fd, &config) < 0) { 367214396Sjhb error = errno; 368196200Sscottl warn("Failed to get config"); 369222899Sbz close(fd); 370214396Sjhb return (error); 371196200Sscottl } 372196200Sscottl 373196200Sscottl /* Dump out the configuration. */ 374196200Sscottl printf("mfi%d Configuration: %d arrays, %d volumes, %d spares\n", 375196200Sscottl mfi_unit, config->array_count, config->log_drv_count, 376196200Sscottl config->spares_count); 377196200Sscottl p = (char *)config->array; 378196200Sscottl 379196200Sscottl for (i = 0; i < config->array_count; i++) { 380196200Sscottl ar = (struct mfi_array *)p; 381196200Sscottl printf(" array %u of %u drives:\n", ar->array_ref, 382196200Sscottl ar->num_drives); 383196200Sscottl for (j = 0; j < ar->num_drives; j++) { 384196200Sscottl device_id = ar->pd[j].ref.v.device_id; 385223345Sbz printf(" drive %s ", mfi_drive_name(NULL, 386223345Sbz device_id, 387223345Sbz MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 388223345Sbz if (device_id != 0xffff) { 389196200Sscottl if (mfi_pd_get_info(fd, device_id, &pinfo, 390196200Sscottl NULL) < 0) 391196200Sscottl printf("%s", 392196200Sscottl mfi_pdstate(ar->pd[j].fw_state)); 393196200Sscottl else 394223345Sbz print_pd(&pinfo, -1); 395196200Sscottl } 396225168Sbz printf("\n"); 397196200Sscottl } 398196200Sscottl p += config->array_size; 399196200Sscottl } 400196200Sscottl 401196200Sscottl for (i = 0; i < config->log_drv_count; i++) { 402196200Sscottl ld = (struct mfi_ld_config *)p; 403196200Sscottl printf(" volume %s ", 404196200Sscottl mfi_volume_name(fd, ld->properties.ld.v.target_id)); 405196200Sscottl if (mfi_ld_get_info(fd, ld->properties.ld.v.target_id, &linfo, 406196200Sscottl NULL) < 0) { 407196200Sscottl printf("%s %s", 408196200Sscottl mfi_raid_level(ld->params.primary_raid_level, 409196200Sscottl ld->params.secondary_raid_level), 410196200Sscottl mfi_ldstate(ld->params.state)); 411196200Sscottl } else 412196200Sscottl print_ld(&linfo, -1); 413196200Sscottl if (ld->properties.name[0] != '\0') 414196200Sscottl printf(" <%s>", ld->properties.name); 415196200Sscottl printf(" spans:\n"); 416196200Sscottl for (j = 0; j < ld->params.span_depth; j++) 417196200Sscottl printf(" array %u\n", ld->span[j].array_ref); 418196200Sscottl p += config->log_drv_size; 419196200Sscottl } 420196200Sscottl 421196200Sscottl for (i = 0; i < config->spares_count; i++) { 422196200Sscottl sp = (struct mfi_spare *)p; 423223345Sbz printf(" %s spare %s ", 424196200Sscottl sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" : 425223345Sbz "global", mfi_drive_name(NULL, sp->ref.v.device_id, 426223345Sbz MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 427196200Sscottl if (mfi_pd_get_info(fd, sp->ref.v.device_id, &pinfo, NULL) < 0) 428196200Sscottl printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE)); 429196200Sscottl else 430223345Sbz print_pd(&pinfo, -1); 431196200Sscottl if (sp->spare_type & MFI_SPARE_DEDICATED) { 432196200Sscottl printf(" backs:\n"); 433196200Sscottl for (j = 0; j < sp->array_count; j++) 434196200Sscottl printf(" array %u\n", sp->array_ref[j]); 435196200Sscottl } else 436196200Sscottl printf("\n"); 437196200Sscottl p += config->spares_size; 438196200Sscottl } 439222899Sbz free(config); 440196200Sscottl close(fd); 441196200Sscottl 442196200Sscottl return (0); 443196200Sscottl} 444196200SscottlMFI_COMMAND(show, config, show_config); 445196200Sscottl 446196200Sscottlstatic int 447237589Seadlershow_volumes(int ac, char **av __unused) 448196200Sscottl{ 449196200Sscottl struct mfi_ld_list list; 450196200Sscottl struct mfi_ld_info info; 451214396Sjhb int error, fd; 452196200Sscottl u_int i, len, state_len; 453196200Sscottl 454196200Sscottl if (ac != 1) { 455196200Sscottl warnx("show volumes: extra arguments"); 456196200Sscottl return (EINVAL); 457196200Sscottl } 458196200Sscottl 459237589Seadler fd = mfi_open(mfi_unit, O_RDONLY); 460196200Sscottl if (fd < 0) { 461214396Sjhb error = errno; 462196200Sscottl warn("mfi_open"); 463214396Sjhb return (error); 464196200Sscottl } 465196200Sscottl 466196200Sscottl /* Get the logical drive list from the controller. */ 467196200Sscottl if (mfi_ld_get_list(fd, &list, NULL) < 0) { 468214396Sjhb error = errno; 469196200Sscottl warn("Failed to get volume list"); 470222899Sbz close(fd); 471214396Sjhb return (error); 472196200Sscottl } 473196200Sscottl 474196200Sscottl /* List the volumes. */ 475196200Sscottl printf("mfi%d Volumes:\n", mfi_unit); 476196200Sscottl state_len = strlen("State"); 477196200Sscottl for (i = 0; i < list.ld_count; i++) { 478196200Sscottl len = strlen(mfi_ldstate(list.ld_list[i].state)); 479196200Sscottl if (len > state_len) 480196200Sscottl state_len = len; 481196200Sscottl } 482196200Sscottl printf(" Id Size Level Stripe "); 483196200Sscottl len = state_len - strlen("State"); 484196200Sscottl for (i = 0; i < (len + 1) / 2; i++) 485196200Sscottl printf(" "); 486196200Sscottl printf("State"); 487196200Sscottl for (i = 0; i < len / 2; i++) 488196200Sscottl printf(" "); 489196200Sscottl printf(" Cache Name\n"); 490196200Sscottl for (i = 0; i < list.ld_count; i++) { 491196200Sscottl if (mfi_ld_get_info(fd, list.ld_list[i].ld.v.target_id, &info, 492196200Sscottl NULL) < 0) { 493214396Sjhb error = errno; 494196200Sscottl warn("Failed to get info for volume %d", 495196200Sscottl list.ld_list[i].ld.v.target_id); 496222899Sbz close(fd); 497214396Sjhb return (error); 498196200Sscottl } 499196200Sscottl printf("%6s ", 500196200Sscottl mfi_volume_name(fd, list.ld_list[i].ld.v.target_id)); 501196200Sscottl print_ld(&info, state_len); 502196200Sscottl switch (info.ld_config.properties.current_cache_policy & 503196200Sscottl (MR_LD_CACHE_ALLOW_WRITE_CACHE | 504196200Sscottl MR_LD_CACHE_ALLOW_READ_CACHE)) { 505196200Sscottl case 0: 506196200Sscottl printf(" Disabled"); 507196200Sscottl break; 508196200Sscottl case MR_LD_CACHE_ALLOW_READ_CACHE: 509196200Sscottl printf(" Reads "); 510196200Sscottl break; 511196200Sscottl case MR_LD_CACHE_ALLOW_WRITE_CACHE: 512196200Sscottl printf(" Writes "); 513196200Sscottl break; 514196200Sscottl case MR_LD_CACHE_ALLOW_WRITE_CACHE | 515196200Sscottl MR_LD_CACHE_ALLOW_READ_CACHE: 516196200Sscottl printf(" Enabled "); 517196200Sscottl break; 518196200Sscottl } 519196200Sscottl if (info.ld_config.properties.name[0] != '\0') 520196200Sscottl printf(" <%s>", info.ld_config.properties.name); 521196200Sscottl printf("\n"); 522196200Sscottl } 523196200Sscottl close(fd); 524196200Sscottl 525196200Sscottl return (0); 526196200Sscottl} 527196200SscottlMFI_COMMAND(show, volumes, show_volumes); 528196200Sscottl 529196200Sscottlstatic int 530237589Seadlershow_drives(int ac, char **av __unused) 531196200Sscottl{ 532196200Sscottl struct mfi_pd_list *list; 533196200Sscottl struct mfi_pd_info info; 534196200Sscottl u_int i, len, state_len; 535214396Sjhb int error, fd; 536196200Sscottl 537196200Sscottl if (ac != 1) { 538196200Sscottl warnx("show drives: extra arguments"); 539196200Sscottl return (EINVAL); 540196200Sscottl } 541196200Sscottl 542237589Seadler fd = mfi_open(mfi_unit, O_RDONLY); 543196200Sscottl if (fd < 0) { 544214396Sjhb error = errno; 545196200Sscottl warn("mfi_open"); 546214396Sjhb return (error); 547196200Sscottl } 548196200Sscottl 549222899Sbz list = NULL; 550196200Sscottl if (mfi_pd_get_list(fd, &list, NULL) < 0) { 551214396Sjhb error = errno; 552196200Sscottl warn("Failed to get drive list"); 553222899Sbz goto error; 554196200Sscottl } 555196200Sscottl 556196200Sscottl /* Walk the list of drives to determine width of state column. */ 557196200Sscottl state_len = 0; 558196200Sscottl for (i = 0; i < list->count; i++) { 559196200Sscottl if (list->addr[i].scsi_dev_type != 0) 560196200Sscottl continue; 561196200Sscottl 562196200Sscottl if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 563196200Sscottl NULL) < 0) { 564214396Sjhb error = errno; 565196200Sscottl warn("Failed to fetch info for drive %u", 566196200Sscottl list->addr[i].device_id); 567222899Sbz goto error; 568196200Sscottl } 569196200Sscottl len = strlen(mfi_pdstate(info.fw_state)); 570253244Ssbruno if (info.state.ddf.v.pd_type.is_foreign) 571253244Ssbruno len += strlen(foreign_state); 572196200Sscottl if (len > state_len) 573196200Sscottl state_len = len; 574196200Sscottl } 575196200Sscottl 576196200Sscottl /* List the drives. */ 577196200Sscottl printf("mfi%d Physical Drives:\n", mfi_unit); 578196200Sscottl for (i = 0; i < list->count; i++) { 579196200Sscottl 580196200Sscottl /* Skip non-hard disks. */ 581196200Sscottl if (list->addr[i].scsi_dev_type != 0) 582196200Sscottl continue; 583196200Sscottl 584196200Sscottl /* Fetch details for this drive. */ 585196200Sscottl if (mfi_pd_get_info(fd, list->addr[i].device_id, &info, 586196200Sscottl NULL) < 0) { 587214396Sjhb error = errno; 588196200Sscottl warn("Failed to fetch info for drive %u", 589196200Sscottl list->addr[i].device_id); 590222899Sbz goto error; 591196200Sscottl } 592196200Sscottl 593223345Sbz printf("%s ", mfi_drive_name(&info, list->addr[i].device_id, 594223345Sbz MFI_DNAME_DEVICE_ID)); 595223345Sbz print_pd(&info, state_len); 596223345Sbz printf(" %s", mfi_drive_name(&info, list->addr[i].device_id, 597223345Sbz MFI_DNAME_ES)); 598196200Sscottl printf("\n"); 599196200Sscottl } 600224495Sjhb error = 0; 601222899Sbzerror: 602222899Sbz free(list); 603196200Sscottl close(fd); 604196200Sscottl 605222899Sbz return (error); 606196200Sscottl} 607196200SscottlMFI_COMMAND(show, drives, show_drives); 608196200Sscottl 609196200Sscottlint fw_name_width, fw_version_width, fw_date_width, fw_time_width; 610196200Sscottl 611196200Sscottlstatic void 612196200Sscottlscan_firmware(struct mfi_info_component *comp) 613196200Sscottl{ 614196200Sscottl int len; 615196200Sscottl 616196200Sscottl len = strlen(comp->name); 617196200Sscottl if (fw_name_width < len) 618196200Sscottl fw_name_width = len; 619196200Sscottl len = strlen(comp->version); 620196200Sscottl if (fw_version_width < len) 621196200Sscottl fw_version_width = len; 622196200Sscottl len = strlen(comp->build_date); 623196200Sscottl if (fw_date_width < len) 624196200Sscottl fw_date_width = len; 625196200Sscottl len = strlen(comp->build_time); 626196200Sscottl if (fw_time_width < len) 627196200Sscottl fw_time_width = len; 628196200Sscottl} 629196200Sscottl 630196200Sscottlstatic void 631196200Sscottldisplay_firmware(struct mfi_info_component *comp, const char *tag) 632196200Sscottl{ 633196200Sscottl 634196200Sscottl printf("%-*s %-*s %-*s %-*s %s\n", fw_name_width, comp->name, 635196200Sscottl fw_version_width, comp->version, fw_date_width, comp->build_date, 636196200Sscottl fw_time_width, comp->build_time, tag); 637196200Sscottl} 638196200Sscottl 639196200Sscottlstatic int 640237589Seadlershow_firmware(int ac, char **av __unused) 641196200Sscottl{ 642196200Sscottl struct mfi_ctrl_info info; 643196200Sscottl struct mfi_info_component header; 644214396Sjhb int error, fd; 645196200Sscottl u_int i; 646196200Sscottl 647196200Sscottl if (ac != 1) { 648221208Sjhb warnx("show firmware: extra arguments"); 649196200Sscottl return (EINVAL); 650196200Sscottl } 651196200Sscottl 652237589Seadler fd = mfi_open(mfi_unit, O_RDONLY); 653196200Sscottl if (fd < 0) { 654214396Sjhb error = errno; 655196200Sscottl warn("mfi_open"); 656214396Sjhb return (error); 657196200Sscottl } 658196200Sscottl 659196200Sscottl if (mfi_ctrl_get_info(fd, &info, NULL) < 0) { 660214396Sjhb error = errno; 661196200Sscottl warn("Failed to get controller info"); 662222899Sbz close(fd); 663214396Sjhb return (error); 664196200Sscottl } 665196200Sscottl 666196200Sscottl if (info.package_version[0] != '\0') 667196200Sscottl printf("mfi%d Firmware Package Version: %s\n", mfi_unit, 668196200Sscottl info.package_version); 669196200Sscottl printf("mfi%d Firmware Images:\n", mfi_unit); 670196200Sscottl strcpy(header.name, "Name"); 671196200Sscottl strcpy(header.version, "Version"); 672196200Sscottl strcpy(header.build_date, "Date"); 673196200Sscottl strcpy(header.build_time, "Time"); 674196200Sscottl scan_firmware(&header); 675196200Sscottl if (info.image_component_count > 8) 676196200Sscottl info.image_component_count = 8; 677196200Sscottl for (i = 0; i < info.image_component_count; i++) 678196200Sscottl scan_firmware(&info.image_component[i]); 679196200Sscottl if (info.pending_image_component_count > 8) 680196200Sscottl info.pending_image_component_count = 8; 681196200Sscottl for (i = 0; i < info.pending_image_component_count; i++) 682196200Sscottl scan_firmware(&info.pending_image_component[i]); 683196200Sscottl display_firmware(&header, "Status"); 684196200Sscottl for (i = 0; i < info.image_component_count; i++) 685196200Sscottl display_firmware(&info.image_component[i], "active"); 686196200Sscottl for (i = 0; i < info.pending_image_component_count; i++) 687196200Sscottl display_firmware(&info.pending_image_component[i], "pending"); 688196200Sscottl 689196200Sscottl close(fd); 690196200Sscottl 691196200Sscottl return (0); 692196200Sscottl} 693196200SscottlMFI_COMMAND(show, firmware, show_firmware); 694221208Sjhb 695221208Sjhbstatic int 696237589Seadlershow_progress(int ac, char **av __unused) 697221208Sjhb{ 698221208Sjhb struct mfi_ld_list llist; 699221208Sjhb struct mfi_pd_list *plist; 700221208Sjhb struct mfi_ld_info linfo; 701221208Sjhb struct mfi_pd_info pinfo; 702221208Sjhb int busy, error, fd; 703221208Sjhb u_int i; 704221208Sjhb uint16_t device_id; 705221208Sjhb uint8_t target_id; 706221208Sjhb 707221208Sjhb if (ac != 1) { 708221208Sjhb warnx("show progress: extra arguments"); 709221208Sjhb return (EINVAL); 710221208Sjhb } 711221208Sjhb 712237589Seadler fd = mfi_open(mfi_unit, O_RDONLY); 713221208Sjhb if (fd < 0) { 714221208Sjhb error = errno; 715221208Sjhb warn("mfi_open"); 716221208Sjhb return (error); 717221208Sjhb } 718221208Sjhb 719221208Sjhb if (mfi_ld_get_list(fd, &llist, NULL) < 0) { 720221208Sjhb error = errno; 721221208Sjhb warn("Failed to get volume list"); 722222899Sbz close(fd); 723221208Sjhb return (error); 724221208Sjhb } 725221208Sjhb if (mfi_pd_get_list(fd, &plist, NULL) < 0) { 726221208Sjhb error = errno; 727221208Sjhb warn("Failed to get drive list"); 728222899Sbz close(fd); 729221208Sjhb return (error); 730221208Sjhb } 731221208Sjhb 732222899Sbz busy = 0; 733221208Sjhb for (i = 0; i < llist.ld_count; i++) { 734221208Sjhb target_id = llist.ld_list[i].ld.v.target_id; 735221208Sjhb if (mfi_ld_get_info(fd, target_id, &linfo, NULL) < 0) { 736221208Sjhb error = errno; 737221208Sjhb warn("Failed to get info for volume %s", 738221208Sjhb mfi_volume_name(fd, target_id)); 739222899Sbz free(plist); 740222899Sbz close(fd); 741221208Sjhb return (error); 742221208Sjhb } 743221208Sjhb if (linfo.progress.active & MFI_LD_PROGRESS_CC) { 744221208Sjhb printf("volume %s ", mfi_volume_name(fd, target_id)); 745221208Sjhb mfi_display_progress("Consistency Check", 746221208Sjhb &linfo.progress.cc); 747221208Sjhb busy = 1; 748221208Sjhb } 749221208Sjhb if (linfo.progress.active & MFI_LD_PROGRESS_BGI) { 750221208Sjhb printf("volume %s ", mfi_volume_name(fd, target_id)); 751221208Sjhb mfi_display_progress("Background Init", 752221208Sjhb &linfo.progress.bgi); 753221208Sjhb busy = 1; 754221208Sjhb } 755221208Sjhb if (linfo.progress.active & MFI_LD_PROGRESS_FGI) { 756221208Sjhb printf("volume %s ", mfi_volume_name(fd, target_id)); 757221208Sjhb mfi_display_progress("Foreground Init", 758221208Sjhb &linfo.progress.fgi); 759221208Sjhb busy = 1; 760221208Sjhb } 761221208Sjhb if (linfo.progress.active & MFI_LD_PROGRESS_RECON) { 762221208Sjhb printf("volume %s ", mfi_volume_name(fd, target_id)); 763221208Sjhb mfi_display_progress("Reconstruction", 764221208Sjhb &linfo.progress.recon); 765221208Sjhb busy = 1; 766221208Sjhb } 767221208Sjhb } 768221208Sjhb 769221208Sjhb for (i = 0; i < plist->count; i++) { 770221208Sjhb if (plist->addr[i].scsi_dev_type != 0) 771221208Sjhb continue; 772221208Sjhb 773221208Sjhb device_id = plist->addr[i].device_id; 774221208Sjhb if (mfi_pd_get_info(fd, device_id, &pinfo, NULL) < 0) { 775221208Sjhb error = errno; 776221208Sjhb warn("Failed to fetch info for drive %u", device_id); 777222899Sbz free(plist); 778222899Sbz close(fd); 779221208Sjhb return (error); 780221208Sjhb } 781221208Sjhb 782221208Sjhb if (pinfo.prog_info.active & MFI_PD_PROGRESS_REBUILD) { 783223345Sbz printf("drive %s ", mfi_drive_name(NULL, device_id, 784223345Sbz MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 785221208Sjhb mfi_display_progress("Rebuild", &pinfo.prog_info.rbld); 786221208Sjhb busy = 1; 787221208Sjhb } 788221208Sjhb if (pinfo.prog_info.active & MFI_PD_PROGRESS_PATROL) { 789223345Sbz printf("drive %s ", mfi_drive_name(NULL, device_id, 790223345Sbz MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 791221208Sjhb mfi_display_progress("Patrol Read", 792221208Sjhb &pinfo.prog_info.patrol); 793221208Sjhb busy = 1; 794221208Sjhb } 795221208Sjhb if (pinfo.prog_info.active & MFI_PD_PROGRESS_CLEAR) { 796223345Sbz printf("drive %s ", mfi_drive_name(NULL, device_id, 797223345Sbz MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS)); 798221208Sjhb mfi_display_progress("Clear", &pinfo.prog_info.clear); 799266401Sjhb busy = 1; 800221208Sjhb } 801221208Sjhb } 802221208Sjhb 803222899Sbz free(plist); 804221208Sjhb close(fd); 805221208Sjhb 806221208Sjhb if (!busy) 807221208Sjhb printf("No activity in progress for adapter mfi%d\n", mfi_unit); 808221208Sjhb 809221208Sjhb return (0); 810221208Sjhb} 811221208SjhbMFI_COMMAND(show, progress, show_progress); 812253244Ssbruno 813253244Ssbrunostatic int 814253244Ssbrunoshow_foreign(int ac, char **av) 815253244Ssbruno{ 816253244Ssbruno return(display_format(ac, av, 0/*normal display*/, MFI_DCMD_CFG_FOREIGN_DISPLAY)); 817253244Ssbruno} 818253244SsbrunoMFI_COMMAND(show, foreign, show_foreign); 819