2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2013 smh@freebsd.org
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/param.h>
44 MFI_TABLE(top, foreign);
47 foreign_clear(__unused int ac, __unused char **av)
51 fd = mfi_open(mfi_unit, O_RDWR);
59 "Are you sure you wish to clear ALL foreign configurations"
60 " on mfi%u? [y/N] ", mfi_unit);
63 if (ch != 'y' && ch != 'Y') {
64 printf("\nAborting\n");
69 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_CLEAR, NULL, 0, NULL,
72 warn("Failed to clear foreign configuration");
77 printf("mfi%d: Foreign configuration cleared\n", mfi_unit);
81 MFI_COMMAND(foreign, clear, foreign_clear);
84 foreign_scan(__unused int ac, __unused char **av)
86 struct mfi_foreign_scan_info info;
89 fd = mfi_open(mfi_unit, O_RDONLY);
96 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
97 sizeof(info), NULL, 0, NULL) < 0) {
99 warn("Failed to scan foreign configuration");
104 printf("mfi%d: Found %d foreign configurations\n", mfi_unit,
109 MFI_COMMAND(foreign, scan, foreign_scan);
112 foreign_show_cfg(int fd, uint32_t opcode, uint8_t cfgidx, int diagnostic)
114 struct mfi_config_data *config;
119 bzero(mbox, sizeof(mbox));
121 if (mfi_config_read_opcode(fd, opcode, &config, mbox, sizeof(mbox)) < 0) {
123 warn("Failed to get foreign config %d", error);
128 if (opcode == MFI_DCMD_CFG_FOREIGN_PREVIEW)
129 sprintf(prefix, "Foreign configuration preview %d", cfgidx);
131 sprintf(prefix, "Foreign configuration %d", cfgidx);
133 * MegaCli uses DCMD opcodes: 0x03100200 (which fails) followed by
134 * 0x1a721880 which returns what looks to be drive / volume info
135 * but we have no real information on what these are or what they do
136 * so we're currently relying solely on the config returned above
139 dump_config(fd, config, prefix);
144 ld_list = (char *)(config->array);
146 printf("%s: %d arrays, %d volumes, %d spares\n", prefix,
147 config->array_count, config->log_drv_count,
148 config->spares_count);
151 for (i = 0; i < config->array_count; i++)
152 ld_list += config->array_size;
154 for (i = 0; i < config->log_drv_count; i++) {
156 char size[6], stripe[5];
157 struct mfi_ld_config *ld;
159 ld = (struct mfi_ld_config *)ld_list;
161 format_stripe(stripe, sizeof(stripe),
162 ld->params.stripe_size);
164 * foreign configs don't seem to have a secondary raid level
165 * but, we can use span depth here as if a LD spans multiple
166 * arrays of disks (2 raid 1 sets for example), we will have an
167 * indication based on the spam depth. swb
169 level = mfi_raid_level(ld->params.primary_raid_level,
170 (ld->params.span_depth - 1));
172 humanize_number(size, sizeof(size), ld->span[0].num_blocks * 512,
173 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
176 printf("(%6s) %-8s |",
178 printf("volume spans %d %s\n", ld->params.span_depth,
179 (ld->params.span_depth > 1) ? "arrays" : "array");
180 for (int j = 0; j < ld->params.span_depth; j++) {
182 struct mfi_array *ar;
185 printf(" array %u @ ", ld->span[j].array_ref);
186 humanize_number(size, sizeof(size), ld->span[j].num_blocks * 512,
187 "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
189 printf("(%6s)\n",size);
190 ar_list = (char *)config->array + (ld->span[j].array_ref * config->array_size);
192 ar = (struct mfi_array *)ar_list;
193 for (int k = 0; k < ar->num_drives; k++) {
194 device_id = ar->pd[k].ref.v.device_id;
195 if (device_id == 0xffff)
196 printf(" drive MISSING\n");
198 printf(" drive %u %s\n", device_id,
199 mfi_pdstate(ar->pd[k].fw_state));
204 ld_list += config->log_drv_size;
214 display_format(int ac, char **av, int diagnostic, mfi_dcmd_t display_cmd)
216 struct mfi_foreign_scan_info info;
221 warnx("foreign display: extra arguments");
225 fd = mfi_open(mfi_unit, O_RDONLY);
232 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
233 sizeof(info), NULL, 0, NULL) < 0) {
235 warn("Failed to scan foreign configuration");
240 if (info.count == 0) {
241 warnx("foreign display: no foreign configs found");
247 for (i = 0; i < info.count; i++) {
248 error = foreign_show_cfg(fd,
249 display_cmd, i, diagnostic);
254 if (i < info.count - 1)
257 } else if (ac == 2) {
258 error = foreign_show_cfg(fd,
259 display_cmd, atoi(av[1]), diagnostic);
271 foreign_display(int ac, char **av)
273 return(display_format(ac, av, 1/*diagnostic output*/, MFI_DCMD_CFG_FOREIGN_DISPLAY));
275 MFI_COMMAND(foreign, diag, foreign_display);
278 foreign_preview(int ac, char **av)
280 return(display_format(ac, av, 1/*diagnostic output*/, MFI_DCMD_CFG_FOREIGN_PREVIEW));
282 MFI_COMMAND(foreign, preview, foreign_preview);
285 foreign_import(int ac, char **av)
287 struct mfi_foreign_scan_info info;
293 warnx("foreign preview: extra arguments");
297 fd = mfi_open(mfi_unit, O_RDWR);
304 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
305 sizeof(info), NULL, 0, NULL) < 0) {
307 warn("Failed to scan foreign configuration");
312 if (info.count == 0) {
313 warnx("foreign import: no foreign configs found");
320 printf("Are you sure you wish to import ALL foreign "
321 "configurations on mfi%u? [y/N] ", mfi_unit);
324 * While this is docmmented for MegaCli this failed with
325 * exit code 0x03 on the test controller which was a Supermicro
326 * SMC2108 with firmware 12.12.0-0095 which is a LSI 2108 based
329 cfgidx = atoi(av[1]);
330 if (cfgidx >= info.count) {
331 warnx("Invalid foreign config %d specified max is %d",
332 cfgidx, info.count - 1);
336 printf("Are you sure you wish to import the foreign "
337 "configuration %d on mfi%u? [y/N] ", cfgidx, mfi_unit);
341 if (ch != 'y' && ch != 'Y') {
342 printf("\nAborting\n");
347 bzero(mbox, sizeof(mbox));
349 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_IMPORT, NULL, 0, mbox,
350 sizeof(mbox), NULL) < 0) {
352 warn("Failed to import foreign configuration");
358 printf("mfi%d: All foreign configurations imported\n",
361 printf("mfi%d: Foreign configuration %d imported\n", mfi_unit,
366 MFI_COMMAND(foreign, import, foreign_import);