2 * Copyright (c) 2013 smh@freebsd.org
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
42 MFI_TABLE(top, foreign);
45 foreign_clear(__unused int ac, __unused char **av)
49 fd = mfi_open(mfi_unit, O_RDWR);
57 "Are you sure you wish to clear ALL foreign configurations"
58 " on mfi%u? [y/N] ", mfi_unit);
61 if (ch != 'y' && ch != 'Y') {
62 printf("\nAborting\n");
67 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_CLEAR, NULL, 0, NULL,
70 warn("Failed to clear foreign configuration");
75 printf("mfi%d: Foreign configuration cleared\n", mfi_unit);
79 MFI_COMMAND(foreign, clear, foreign_clear);
82 foreign_scan(__unused int ac, __unused char **av)
84 struct mfi_foreign_scan_info info;
87 fd = mfi_open(mfi_unit, O_RDONLY);
94 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
95 sizeof(info), NULL, 0, NULL) < 0) {
97 warn("Failed to scan foreign configuration");
102 printf("mfi%d: Found %d foreign configurations\n", mfi_unit,
107 MFI_COMMAND(foreign, scan, foreign_scan);
110 foreign_show_cfg(int fd, uint32_t opcode, uint8_t cfgidx, int diagnostic)
112 struct mfi_config_data *config;
117 bzero(mbox, sizeof(mbox));
119 if (mfi_config_read_opcode(fd, opcode, &config, mbox, sizeof(mbox)) < 0) {
121 warn("Failed to get foreign config %d", error);
126 if (opcode == MFI_DCMD_CFG_FOREIGN_PREVIEW)
127 sprintf(prefix, "Foreign configuration preview %d", cfgidx);
129 sprintf(prefix, "Foreign configuration %d", cfgidx);
131 * MegaCli uses DCMD opcodes: 0x03100200 (which fails) followed by
132 * 0x1a721880 which returns what looks to be drive / volume info
133 * but we have no real information on what these are or what they do
134 * so we're currently relying solely on the config returned above
137 dump_config(fd, config, prefix);
142 ld_list = (char *)(config->array);
144 printf("%s: %d arrays, %d volumes, %d spares\n", prefix,
145 config->array_count, config->log_drv_count,
146 config->spares_count);
149 for (i = 0; i < config->array_count; i++)
150 ld_list += config->array_size;
152 for (i = 0; i < config->log_drv_count; i++) {
154 char size[6], stripe[5];
155 struct mfi_ld_config *ld;
157 ld = (struct mfi_ld_config *)ld_list;
159 format_stripe(stripe, sizeof(stripe),
160 ld->params.stripe_size);
162 * foreign configs don't seem to have a secondary raid level
163 * but, we can use span depth here as if a LD spans multiple
164 * arrays of disks (2 raid 1 sets for example), we will have an
165 * indication based on the spam depth. swb
167 level = mfi_raid_level(ld->params.primary_raid_level,
168 (ld->params.span_depth - 1));
170 humanize_number(size, sizeof(size), ld->span[0].num_blocks * 512,
171 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
174 printf("(%6s) %-8s |",
176 printf("volume spans %d %s\n", ld->params.span_depth,
177 (ld->params.span_depth > 1) ? "arrays" : "array");
178 for (int j = 0; j < ld->params.span_depth; j++) {
180 struct mfi_array *ar;
183 printf(" array %u @ ", ld->span[j].array_ref);
184 humanize_number(size, sizeof(size), ld->span[j].num_blocks * 512,
185 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
187 printf("(%6s)\n",size);
188 ar_list = (char *)config->array + (ld->span[j].array_ref * config->array_size);
190 ar = (struct mfi_array *)ar_list;
191 for (int k = 0; k < ar->num_drives; k++) {
192 device_id = ar->pd[k].ref.v.device_id;
193 if (device_id == 0xffff)
194 printf(" drive MISSING\n");
196 printf(" drive %u %s\n", device_id,
197 mfi_pdstate(ar->pd[k].fw_state));
202 ld_list += config->log_drv_size;
212 display_format(int ac, char **av, int diagnostic, mfi_dcmd_t display_cmd)
214 struct mfi_foreign_scan_info info;
219 warnx("foreign display: extra arguments");
223 fd = mfi_open(mfi_unit, O_RDONLY);
230 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
231 sizeof(info), NULL, 0, NULL) < 0) {
233 warn("Failed to scan foreign configuration");
238 if (info.count == 0) {
239 warnx("foreign display: no foreign configs found");
245 for (i = 0; i < info.count; i++) {
246 error = foreign_show_cfg(fd,
247 display_cmd, i, diagnostic);
252 if (i < info.count - 1)
255 } else if (ac == 2) {
256 error = foreign_show_cfg(fd,
257 display_cmd, atoi(av[1]), diagnostic);
269 foreign_display(int ac, char **av)
271 return(display_format(ac, av, 1/*diagnostic output*/, MFI_DCMD_CFG_FOREIGN_DISPLAY));
273 MFI_COMMAND(foreign, diag, foreign_display);
276 foreign_preview(int ac, char **av)
278 return(display_format(ac, av, 1/*diagnostic output*/, MFI_DCMD_CFG_FOREIGN_PREVIEW));
280 MFI_COMMAND(foreign, preview, foreign_preview);
283 foreign_import(int ac, char **av)
285 struct mfi_foreign_scan_info info;
291 warnx("foreign preview: extra arguments");
295 fd = mfi_open(mfi_unit, O_RDWR);
302 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
303 sizeof(info), NULL, 0, NULL) < 0) {
305 warn("Failed to scan foreign configuration");
310 if (info.count == 0) {
311 warnx("foreign import: no foreign configs found");
318 printf("Are you sure you wish to import ALL foreign "
319 "configurations on mfi%u? [y/N] ", mfi_unit);
322 * While this is docmmented for MegaCli this failed with
323 * exit code 0x03 on the test controller which was a Supermicro
324 * SMC2108 with firmware 12.12.0-0095 which is a LSI 2108 based
327 cfgidx = atoi(av[1]);
328 if (cfgidx >= info.count) {
329 warnx("Invalid foreign config %d specified max is %d",
330 cfgidx, info.count - 1);
334 printf("Are you sure you wish to import the foreign "
335 "configuration %d on mfi%u? [y/N] ", cfgidx, mfi_unit);
339 if (ch != 'y' && ch != 'Y') {
340 printf("\nAborting\n");
345 bzero(mbox, sizeof(mbox));
347 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_IMPORT, NULL, 0, mbox,
348 sizeof(mbox), NULL) < 0) {
350 warn("Failed to import foreign configuration");
356 printf("mfi%d: All foreign configurations imported\n",
359 printf("mfi%d: Foreign configuration %d imported\n", mfi_unit,
364 MFI_COMMAND(foreign, import, foreign_import);