summaryrefslogtreecommitdiff
path: root/usr.sbin/mfiutil
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2013-09-05 20:18:59 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2013-09-05 20:18:59 +0000
commitd1d015864103b253b3fcb2f72a0da5b0cfeb31b6 (patch)
tree22b131dceb13c3df96da594fbaadb693504797c7 /usr.sbin/mfiutil
parent12d4083451fc39b3e831d4ea0bfa67d3b32cfb54 (diff)
parentb6f49c23a36f329cbf1e7f28078e17fd87f0e245 (diff)
downloadsrc-test2-d1d015864103b253b3fcb2f72a0da5b0cfeb31b6.tar.gz
src-test2-d1d015864103b253b3fcb2f72a0da5b0cfeb31b6.zip
Merge from head
Notes
Notes: svn path=/projects/bmake/; revision=255263
Diffstat (limited to 'usr.sbin/mfiutil')
-rw-r--r--usr.sbin/mfiutil/Makefile2
-rw-r--r--usr.sbin/mfiutil/mfi_config.c44
-rw-r--r--usr.sbin/mfiutil/mfi_drive.c14
-rw-r--r--usr.sbin/mfiutil/mfi_foreign.c364
-rw-r--r--usr.sbin/mfiutil/mfi_show.c30
-rw-r--r--usr.sbin/mfiutil/mfiutil.869
-rw-r--r--usr.sbin/mfiutil/mfiutil.c11
-rw-r--r--usr.sbin/mfiutil/mfiutil.h17
8 files changed, 525 insertions, 26 deletions
diff --git a/usr.sbin/mfiutil/Makefile b/usr.sbin/mfiutil/Makefile
index c460b3fa02ed..f6e358a24e62 100644
--- a/usr.sbin/mfiutil/Makefile
+++ b/usr.sbin/mfiutil/Makefile
@@ -2,7 +2,7 @@
PROG= mfiutil
SRCS= mfiutil.c mfi_bbu.c mfi_cmd.c mfi_config.c mfi_drive.c mfi_evt.c \
- mfi_flash.c mfi_patrol.c mfi_show.c mfi_volume.c
+ mfi_flash.c mfi_patrol.c mfi_show.c mfi_volume.c mfi_foreign.c
MAN8= mfiutil.8
CFLAGS+= -fno-builtin-strftime
diff --git a/usr.sbin/mfiutil/mfi_config.c b/usr.sbin/mfiutil/mfi_config.c
index 8576bc3325cf..a91921491518 100644
--- a/usr.sbin/mfiutil/mfi_config.c
+++ b/usr.sbin/mfiutil/mfi_config.c
@@ -37,19 +37,13 @@
#include <errno.h>
#include <fcntl.h>
#include <libutil.h>
-#ifdef DEBUG
#include <stdint.h>
-#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mfiutil.h"
-#ifdef DEBUG
-static void dump_config(int fd, struct mfi_config_data *config);
-#endif
-
static int add_spare(int ac, char **av);
static int remove_spare(int ac, char **av);
@@ -81,9 +75,17 @@ dehumanize(const char *value)
}
return (iv);
}
+
int
mfi_config_read(int fd, struct mfi_config_data **configp)
{
+ return mfi_config_read_opcode(fd, MFI_DCMD_CFG_READ, configp, NULL, 0);
+}
+
+int
+mfi_config_read_opcode(int fd, uint32_t opcode, struct mfi_config_data **configp,
+ uint8_t *mbox, size_t mboxlen)
+{
struct mfi_config_data *config;
uint32_t config_size;
int error;
@@ -98,8 +100,8 @@ fetch:
config = reallocf(config, config_size);
if (config == NULL)
return (-1);
- if (mfi_dcmd_command(fd, MFI_DCMD_CFG_READ, config,
- config_size, NULL, 0, NULL) < 0) {
+ if (mfi_dcmd_command(fd, opcode, config,
+ config_size, mbox, mboxlen, NULL) < 0) {
error = errno;
free(config);
errno = error;
@@ -366,6 +368,13 @@ parse_array(int fd, int raid_type, char *array_str, struct array_info *info)
info->drives = NULL;
return (EINVAL);
}
+
+ if (pinfo->state.ddf.v.pd_type.is_foreign) {
+ warnx("Drive %u is foreign", device_id);
+ free(info->drives);
+ info->drives = NULL;
+ return (EINVAL);
+ }
}
return (0);
@@ -804,7 +813,7 @@ create_volume(int ac, char **av)
#ifdef DEBUG
if (dump)
- dump_config(fd, config);
+ dump_config(fd, config, NULL);
#endif
/* Send the new config to the controller. */
@@ -1093,10 +1102,9 @@ remove_spare(int ac, char **av)
}
MFI_COMMAND(top, remove, remove_spare);
-#ifdef DEBUG
/* Display raw data about a config. */
-static void
-dump_config(int fd, struct mfi_config_data *config)
+void
+dump_config(int fd, struct mfi_config_data *config, const char *msg_prefix)
{
struct mfi_array *ar;
struct mfi_ld_config *ld;
@@ -1106,9 +1114,12 @@ dump_config(int fd, struct mfi_config_data *config)
char *p;
int i, j;
+ if (NULL == msg_prefix)
+ msg_prefix = "Configuration (Debug)";
+
printf(
- "mfi%d Configuration (Debug): %d arrays, %d volumes, %d spares\n",
- mfi_unit, config->array_count, config->log_drv_count,
+ "mfi%d %s: %d arrays, %d volumes, %d spares\n", mfi_unit,
+ msg_prefix, 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);
@@ -1186,6 +1197,7 @@ dump_config(int fd, struct mfi_config_data *config)
}
}
+#ifdef DEBUG
static int
debug_config(int ac, char **av)
{
@@ -1213,7 +1225,7 @@ debug_config(int ac, char **av)
}
/* Dump out the configuration. */
- dump_config(fd, config);
+ dump_config(fd, config, NULL);
free(config);
close(fd);
@@ -1265,7 +1277,7 @@ dump(int ac, char **av)
close(fd);
return (error);
}
- dump_config(fd, config);
+ dump_config(fd, config, NULL);
free(config);
close(fd);
diff --git a/usr.sbin/mfiutil/mfi_drive.c b/usr.sbin/mfiutil/mfi_drive.c
index 1927facd67ab..2bc902ea2756 100644
--- a/usr.sbin/mfiutil/mfi_drive.c
+++ b/usr.sbin/mfiutil/mfi_drive.c
@@ -474,6 +474,20 @@ rebuild_drive(int ac, char **av)
MFI_COMMAND(top, rebuild, rebuild_drive);
static int
+syspd_drive(int ac, char **av)
+{
+
+ if (ac != 2) {
+ warnx("syspd: %s", ac > 2 ? "extra arguments" :
+ "drive required");
+ return (EINVAL);
+ }
+
+ return (drive_set_state(av[1], MFI_PD_STATE_SYSTEM));
+}
+MFI_COMMAND(top, syspd, syspd_drive);
+
+static int
start_rebuild(int ac, char **av)
{
struct mfi_pd_info info;
diff --git a/usr.sbin/mfiutil/mfi_foreign.c b/usr.sbin/mfiutil/mfi_foreign.c
new file mode 100644
index 000000000000..8c6183d7788d
--- /dev/null
+++ b/usr.sbin/mfiutil/mfi_foreign.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2013 smh@freebsd.org
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "mfiutil.h"
+
+MFI_TABLE(top, foreign);
+
+static int
+foreign_clear(__unused int ac, __unused char **av)
+{
+ int ch, error, fd;
+
+ fd = mfi_open(mfi_unit, O_RDWR);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
+
+ printf(
+ "Are you sure you wish to clear ALL foreign configurations"
+ " on mfi%u? [y/N] ", mfi_unit);
+
+ ch = getchar();
+ if (ch != 'y' && ch != 'Y') {
+ printf("\nAborting\n");
+ close(fd);
+ return (0);
+ }
+
+ if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_CLEAR, NULL, 0, NULL,
+ 0, NULL) < 0) {
+ error = errno;
+ warn("Failed to clear foreign configuration");
+ close(fd);
+ return (error);
+ }
+
+ printf("mfi%d: Foreign configuration cleared\n", mfi_unit);
+ close(fd);
+ return (0);
+}
+MFI_COMMAND(foreign, clear, foreign_clear);
+
+static int
+foreign_scan(__unused int ac, __unused char **av)
+{
+ struct mfi_foreign_scan_info info;
+ int error, fd;
+
+ fd = mfi_open(mfi_unit, O_RDONLY);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
+
+ if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
+ sizeof(info), NULL, 0, NULL) < 0) {
+ error = errno;
+ warn("Failed to scan foreign configuration");
+ close(fd);
+ return (error);
+ }
+
+ printf("mfi%d: Found %d foreign configurations\n", mfi_unit,
+ info.count);
+ close(fd);
+ return (0);
+}
+MFI_COMMAND(foreign, scan, foreign_scan);
+
+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);
+}
+
+int
+display_format(int ac, char **av, int diagnostic, mfi_dcmd_t display_cmd)
+{
+ struct mfi_foreign_scan_info info;
+ uint8_t i;
+ int error, fd;
+
+ if (ac > 2) {
+ warnx("foreign display: extra arguments");
+ return (EINVAL);
+ }
+
+ fd = mfi_open(mfi_unit, O_RDONLY);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
+
+ if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
+ sizeof(info), NULL, 0, NULL) < 0) {
+ error = errno;
+ warn("Failed to scan foreign configuration");
+ close(fd);
+ return (error);
+ }
+
+ if (info.count == 0) {
+ warnx("foreign display: no foreign configs found");
+ close(fd);
+ return (EINVAL);
+ }
+
+ if (ac == 1) {
+ for (i = 0; i < info.count; i++) {
+ error = foreign_show_cfg(fd,
+ display_cmd, i, diagnostic);
+ if(error != 0) {
+ close(fd);
+ return (error);
+ }
+ if (i < info.count - 1)
+ printf("\n");
+ }
+ } else if (ac == 2) {
+ error = foreign_show_cfg(fd,
+ display_cmd, atoi(av[1]), diagnostic);
+ if (error != 0) {
+ close(fd);
+ return (error);
+ }
+ }
+
+ close(fd);
+ return (0);
+}
+
+static int
+foreign_display(int ac, char **av)
+{
+ return(display_format(ac, av, 1/*diagnostic output*/, MFI_DCMD_CFG_FOREIGN_DISPLAY));
+}
+MFI_COMMAND(foreign, diag, foreign_display);
+
+static int
+foreign_preview(int ac, char **av)
+{
+ return(display_format(ac, av, 1/*diagnostic output*/, MFI_DCMD_CFG_FOREIGN_PREVIEW));
+}
+MFI_COMMAND(foreign, preview, foreign_preview);
+
+static int
+foreign_import(int ac, char **av)
+{
+ struct mfi_foreign_scan_info info;
+ int ch, error, fd;
+ uint8_t cfgidx;
+ uint8_t mbox[4];
+
+ if (ac > 2) {
+ warnx("foreign preview: extra arguments");
+ return (EINVAL);
+ }
+
+ fd = mfi_open(mfi_unit, O_RDWR);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
+
+ if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,
+ sizeof(info), NULL, 0, NULL) < 0) {
+ error = errno;
+ warn("Failed to scan foreign configuration");
+ close(fd);
+ return (error);
+ }
+
+ if (info.count == 0) {
+ warnx("foreign import: no foreign configs found");
+ close(fd);
+ return (EINVAL);
+ }
+
+ if (ac == 1) {
+ cfgidx = 0xff;
+ printf("Are you sure you wish to import ALL foreign "
+ "configurations on mfi%u? [y/N] ", mfi_unit);
+ } else {
+ /*
+ * While this is docmmented for MegaCli this failed with
+ * exit code 0x03 on the test controller which was a Supermicro
+ * SMC2108 with firmware 12.12.0-0095 which is a LSI 2108 based
+ * controller.
+ */
+ cfgidx = atoi(av[1]);
+ if (cfgidx >= info.count) {
+ warnx("Invalid foreign config %d specified max is %d",
+ cfgidx, info.count - 1);
+ close(fd);
+ return (EINVAL);
+ }
+ printf("Are you sure you wish to import the foreign "
+ "configuration %d on mfi%u? [y/N] ", cfgidx, mfi_unit);
+ }
+
+ ch = getchar();
+ if (ch != 'y' && ch != 'Y') {
+ printf("\nAborting\n");
+ close(fd);
+ return (0);
+ }
+
+ bzero(mbox, sizeof(mbox));
+ mbox[0] = cfgidx;
+ if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_IMPORT, NULL, 0, mbox,
+ sizeof(mbox), NULL) < 0) {
+ error = errno;
+ warn("Failed to import foreign configuration");
+ close(fd);
+ return (error);
+ }
+
+ if (ac == 1)
+ printf("mfi%d: All foreign configurations imported\n",
+ mfi_unit);
+ else
+ printf("mfi%d: Foreign configuration %d imported\n", mfi_unit,
+ cfgidx);
+ close(fd);
+ return (0);
+}
+MFI_COMMAND(foreign, import, foreign_import);
diff --git a/usr.sbin/mfiutil/mfi_show.c b/usr.sbin/mfiutil/mfi_show.c
index 06721c2e8a04..6bb86124f996 100644
--- a/usr.sbin/mfiutil/mfi_show.c
+++ b/usr.sbin/mfiutil/mfi_show.c
@@ -40,9 +40,11 @@
#include <unistd.h>
#include "mfiutil.h"
+static const char* foreign_state = " (FOREIGN)";
+
MFI_TABLE(top, show);
-static void
+void
format_stripe(char *buf, size_t buflen, uint8_t stripe)
{
@@ -291,7 +293,7 @@ show_battery(int ac, char **av __unused)
}
MFI_COMMAND(show, battery, show_battery);
-static void
+void
print_ld(struct mfi_ld_info *info, int state_len)
{
struct mfi_ld_params *params = &info->ld_config.params;
@@ -312,19 +314,24 @@ print_ld(struct mfi_ld_info *info, int state_len)
mfi_ldstate(params->state));
}
-static void
+void
print_pd(struct mfi_pd_info *info, int state_len)
{
const char *s;
- char buf[6];
+ char buf[256];
humanize_number(buf, sizeof(buf), info->raw_size * 512, "",
HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL);
printf("(%6s) ", buf);
+ if (info->state.ddf.v.pd_type.is_foreign) {
+ sprintf(buf, "%s%s", mfi_pdstate(info->fw_state), foreign_state);
+ s = buf;
+ } else
+ s = mfi_pdstate(info->fw_state);
if (state_len > 0)
- printf("%-*s", state_len, mfi_pdstate(info->fw_state));
+ printf("%-*s", state_len, s);
else
- printf("%s", mfi_pdstate(info->fw_state));
+ printf("%s",s);
s = mfi_pd_inq_string(info);
if (s != NULL)
printf(" %s", s);
@@ -560,6 +567,8 @@ show_drives(int ac, char **av __unused)
goto error;
}
len = strlen(mfi_pdstate(info.fw_state));
+ if (info.state.ddf.v.pd_type.is_foreign)
+ len += strlen(foreign_state);
if (len > state_len)
state_len = len;
}
@@ -757,7 +766,7 @@ show_progress(int ac, char **av __unused)
printf("drive %s ", mfi_drive_name(NULL, device_id,
MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS));
mfi_display_progress("Clear", &pinfo.prog_info.clear);
- busy = 1;
+
}
}
@@ -770,3 +779,10 @@ show_progress(int ac, char **av __unused)
return (0);
}
MFI_COMMAND(show, progress, show_progress);
+
+static int
+show_foreign(int ac, char **av)
+{
+ return(display_format(ac, av, 0/*normal display*/, MFI_DCMD_CFG_FOREIGN_DISPLAY));
+}
+MFI_COMMAND(show, foreign, show_foreign);
diff --git a/usr.sbin/mfiutil/mfiutil.8 b/usr.sbin/mfiutil/mfiutil.8
index 54686176b43a..8346922c9e68 100644
--- a/usr.sbin/mfiutil/mfiutil.8
+++ b/usr.sbin/mfiutil/mfiutil.8
@@ -63,6 +63,9 @@
.Cm show firmware
.Nm
.Op Fl u Ar unit
+.Cm show foreign Op Ar volume
+.Nm
+.Op Fl u Ar unit
.Cm show logstate
.Nm
.Op Fl d
@@ -88,6 +91,9 @@
.Cm rebuild Ar drive
.Nm
.Op Fl u Ar unit
+.Cm syspd Ar drive
+.Nm
+.Op Fl u Ar unit
.Cm drive progress Ar drive
.Nm
.Op Fl u Ar unit
@@ -140,6 +146,21 @@
.Cm patrol Ar command Op Ar interval Op Ar start
.Nm
.Op Fl u Ar unit
+.Cm foreign scan
+.Nm
+.Op Fl u Ar unit
+.Cm foreign clear Op Ar config
+.Nm
+.Op Fl u Ar unit
+.Cm foreign diag Op Ar config
+.Nm
+.Op Fl u Ar unit
+.Cm foreign preview Op Ar config
+.Nm
+.Op Fl u Ar unit
+.Cm foreign import Op Ar config
+.Nm
+.Op Fl u Ar unit
.Cm flash Ar file
.Nm
.Op Fl u Ar unit
@@ -321,6 +342,8 @@ The entry in the event log corresponding to the most recent boot.
.El
.It Cm show firmware
Lists all of the firmware images present on the controller.
+.It Cm show foreign
+Displays detected foreign configurations on disks for importation or removal.
.It Cm show logstate
Display the various sequence numbers associated with the event log.
.It Cm show patrol
@@ -352,6 +375,11 @@ Mark a failed
that is still part of an array as a good drive suitable for a rebuild.
The firmware should kick off an array rebuild on its own if a failed drive
is marked as a rebuild drive.
+.It Cm syspd Ar drive
+Present the drive to the host operating system as a disk SYSPD block device in
+the format /dev/mfisyspdX. Clear this flag with
+.Cm good
+.Ar drive
.It Cm drive progress Ar drive
Report the current progress and estimated completion time of drive operations
such as rebuilds or patrol reads.
@@ -567,12 +595,45 @@ Enable manual patrol reads that are only initiated by the user.
Start a patrol read operation.
.It Cm stop patrol
Stop a currently running patrol read operation.
+.It Cm foreign scan
+Scan for foreign configurations and display the number found. The
+.Ar config
+argument for the commands below takes the form of a number from 0 to the total
+configurations found.
+.It Cm foreign clear Op config
+Clear the specifed foreign
+.Ar config
+or all if no
+.Ar config
+argument is provided.
+.It Cm foreign diag Op config
+Display a diagnostic display of the specifed foreign
+.Ar config
+or all if no
+.Ar config
+argument is provided.
+.It Cm foreign preview Op config
+Preview the specifed foreign
+.Ar config
+after import or all if no
+.Ar config
+argument is provided.
+.It Cm foreign import Op config
+Import the specifed foreign
+.Ar config
+or all if no
+.Ar config
+argument is provided.
.It Cm flash Ar file
Updates the flash on the controller with the firmware stored in
.Ar file .
A reboot is required for the new firmware to take effect.
.It Cm start learn
Start a battery relearn.
+Note that this seems to always result in the battery being completely drained,
+regardless of the BBU mode.
+In particular, the controller write cache will be disabled during the relearn
+even if transparent learning mode is enabled.
.It Cm bbu Ar setting Ar value
Update battery backup unit (BBU) properties related to battery relearning.
The following settings are configurable:
@@ -626,10 +687,18 @@ Add the drive in slot 2 in the main chassis as a hot spare for volume mfid0:
.Pp
.Dl Nm Cm add s2 mfid0
.Pp
+Reconfigure a disk as a SYSPD block device with no RAID
+.Pp
+.Dl Nm Cm syspd 0
+.Pp
Configure the adapter to run periodic patrol reads once a week with the first
patrol read starting in 5 minutes:
.Pp
.Dl Nm Cm patrol auto 604800 300
+.Pp
+Display the second detected foreign configuration:
+.Pp
+.Dl Nm Cm show foreign 1
.Sh SEE ALSO
.Xr mfi 4
.Sh HISTORY
diff --git a/usr.sbin/mfiutil/mfiutil.c b/usr.sbin/mfiutil/mfiutil.c
index 7488e24d825e..a8d9ef826449 100644
--- a/usr.sbin/mfiutil/mfiutil.c
+++ b/usr.sbin/mfiutil/mfiutil.c
@@ -60,13 +60,15 @@ usage(void)
fprintf(stderr, " show drives - list physical drives\n");
fprintf(stderr, " show events - display event log\n");
fprintf(stderr, " show firmware - list firmware images\n");
+ fprintf(stderr, " show foreign - display detected foreign volumes\n");
fprintf(stderr, " show logstate - display event log sequence numbers\n");
fprintf(stderr, " show volumes - list logical volumes\n");
fprintf(stderr, " show patrol - display patrol read status\n");
fprintf(stderr, " show progress - display status of active operations\n");
fprintf(stderr, " fail <drive> - fail a physical drive\n");
- fprintf(stderr, " good <drive> - mark a bad physical drive as good\n");
+ fprintf(stderr, " good <drive> - set a failed/SYSPD drive as UNCONFIGURED\n");
fprintf(stderr, " rebuild <drive> - mark failed drive ready for rebuild\n");
+ fprintf(stderr, " syspd <drive> - set drive into use as SYSPD JBOD\n");
fprintf(stderr, " drive progress <drive> - display status of active operations\n");
fprintf(stderr, " drive clear <drive> <start|stop> - clear a drive with all 0x00\n");
fprintf(stderr, " start rebuild <drive>\n");
@@ -83,6 +85,11 @@ usage(void)
fprintf(stderr, " patrol <disable|auto|manual> [interval [start]]\n");
fprintf(stderr, " start patrol - start a patrol read\n");
fprintf(stderr, " stop patrol - stop a patrol read\n");
+ fprintf(stderr, " foreign scan - scan for foreign configurations\n");
+ fprintf(stderr, " foreign clear [volume] - clear foreign configurations (default all)\n");
+ fprintf(stderr, " foreign diag [volume] - diagnostic display foreign configurations (default all)\n");
+ fprintf(stderr, " foreign preview [volume] - preview foreign configurations (default all)\n");
+ fprintf(stderr, " foreign import [volume] - import foreign configurations (default all)\n");
fprintf(stderr, " flash <firmware>\n");
fprintf(stderr, " start learn - start a BBU relearn\n");
fprintf(stderr, " bbu <setting> <value> - set BBU properties\n");
@@ -97,7 +104,7 @@ static int
version(int ac __unused, char **av __unused)
{
- printf("mfiutil version 1.0.14");
+ printf("mfiutil version 1.0.15");
#ifdef DEBUG
printf(" (DEBUG)");
#endif
diff --git a/usr.sbin/mfiutil/mfiutil.h b/usr.sbin/mfiutil/mfiutil.h
index 8a544c29350e..251816a51e75 100644
--- a/usr.sbin/mfiutil/mfiutil.h
+++ b/usr.sbin/mfiutil/mfiutil.h
@@ -124,6 +124,16 @@ extern int mfi_unit;
extern u_int mfi_opts;
+/* We currently don't know the full details of the following struct */
+struct mfi_foreign_scan_cfg {
+ char data[24];
+};
+
+struct mfi_foreign_scan_info {
+ uint32_t count; /* Number of foreign configs found */
+ struct mfi_foreign_scan_cfg cfgs[8];
+};
+
void mbox_store_ldref(uint8_t *mbox, union mfi_ld_ref *ref);
void mbox_store_pdref(uint8_t *mbox, union mfi_pd_ref *ref);
void mfi_display_progress(const char *label, struct mfi_progress *prog);
@@ -136,6 +146,8 @@ const char *mfi_pd_inq_string(struct mfi_pd_info *info);
const char *mfi_volume_name(int fd, uint8_t target_id);
int mfi_volume_busy(int fd, uint8_t target_id);
int mfi_config_read(int fd, struct mfi_config_data **configp);
+int mfi_config_read_opcode(int fd, uint32_t opcode,
+ struct mfi_config_data **configp, uint8_t *mbox, size_t mboxlen);
int mfi_lookup_drive(int fd, char *drive, uint16_t *device_id);
int mfi_lookup_volume(int fd, const char *name, uint8_t *target_id);
int mfi_dcmd_command(int fd, uint32_t opcode, void *buf, size_t bufsize,
@@ -152,6 +164,10 @@ int mfi_reconfig_supported(void);
const char *mfi_status(u_int status_code);
const char *mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t device_id,
uint32_t def);
+void format_stripe(char *buf, size_t buflen, uint8_t stripe);
+void print_ld(struct mfi_ld_info *info, int state_len);
+void print_pd(struct mfi_pd_info *info, int state_len);
+void dump_config(int fd, struct mfi_config_data *config, const char *msg_prefix);
int mfi_bbu_get_props(int fd, struct mfi_bbu_properties *props,
uint8_t *statusp);
int mfi_bbu_set_props(int fd, struct mfi_bbu_properties *props,
@@ -163,4 +179,5 @@ void mfi_autolearn_mode(uint8_t, char *, size_t);
void scan_firmware(struct mfi_info_component *comp);
void display_firmware(struct mfi_info_component *comp, const char *tag);
+int display_format(int ac, char **av, int diagnostic, mfi_dcmd_t display_cmd);
#endif /* !__MFIUTIL_H__ */