mfi(4)/mfiutil(8): Add support for foreign configurations and drives.
authorSascha Wildner <saw@online.de>
Mon, 1 Apr 2013 21:26:47 +0000 (23:26 +0200)
committerSascha Wildner <saw@online.de>
Mon, 1 Apr 2013 21:27:25 +0000 (23:27 +0200)
For this, the following commands are added to mfiutil(8):

foreign scan - lists the number of foreign configs
foreign drives - lists the drives which are flagged as foreign
foreign display - displays the specified foreign configuration
foreign preview - previews the specified foreign configuration after import
foreign clear - clears the foreign configuration
foreign import - imports the foreign configuration

Foreign drive support has been added to 'show drives' too.

Tested-by: ftigeot
Taken-from: http://www.freebsd.org/cgi/query-pr.cgi?pr=172091

sys/dev/raid/mfi/mfi.c
sys/dev/raid/mfi/mfireg.h
usr.sbin/mfiutil/Makefile
usr.sbin/mfiutil/mfi_cmd.c
usr.sbin/mfiutil/mfi_config.c
usr.sbin/mfiutil/mfi_foreign.c [new file with mode: 0644]
usr.sbin/mfiutil/mfi_show.c
usr.sbin/mfiutil/mfiutil.8
usr.sbin/mfiutil/mfiutil.c
usr.sbin/mfiutil/mfiutil.h

index e0b08b3..5b76159 100644 (file)
@@ -2550,6 +2550,7 @@ mfi_config_lock(struct mfi_softc *sc, uint32_t opcode)
        case MFI_DCMD_LD_DELETE:
        case MFI_DCMD_CFG_ADD:
        case MFI_DCMD_CFG_CLEAR:
+       case MFI_DCMD_CFG_FOREIGN_IMPORT:
                lockmgr(&sc->mfi_config_lock, LK_EXCLUSIVE);
                return (1);
        default:
@@ -2665,10 +2666,9 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
                }
                break;
        case MFI_DCMD_CFG_ADD:
-               mfi_ldprobe(sc);
-               break;
        case MFI_DCMD_CFG_FOREIGN_IMPORT:
-               mfi_ldprobe(sc);
+               if (cm->cm_frame->header.cmd_status == MFI_STAT_OK)
+                       mfi_ldprobe(sc);
                break;
        case MFI_DCMD_PD_STATE_SET:
                mbox = (uint16_t *)cm->cm_frame->dcmd.mbox;
index 63e3af9..25579a9 100644 (file)
@@ -231,7 +231,11 @@ typedef enum {
        MFI_DCMD_CFG_CLEAR =            0x04030000,
        MFI_DCMD_CFG_MAKE_SPARE =       0x04040000,
        MFI_DCMD_CFG_REMOVE_SPARE =     0x04050000,
+       MFI_DCMD_CFG_FOREIGN_SCAN =     0x04060100,
+       MFI_DCMD_CFG_FOREIGN_DISPLAY =  0x04060200,
+       MFI_DCMD_CFG_FOREIGN_PREVIEW =  0x04060300,
        MFI_DCMD_CFG_FOREIGN_IMPORT =   0x04060400,
+       MFI_DCMD_CFG_FOREIGN_CLEAR =    0x04060500,
        MFI_DCMD_BBU_GET_STATUS =       0x05010000,
        MFI_DCMD_BBU_GET_CAPACITY_INFO =0x05020000,
        MFI_DCMD_BBU_GET_DESIGN_INFO =  0x05030000,
index b9247f9..31ffc0e 100644 (file)
@@ -2,7 +2,7 @@
 PROG=  mfiutil
 
 SRCS=  mfiutil.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_foreign.c mfi_patrol.c mfi_show.c mfi_volume.c
 MAN8=  mfiutil.8
 
 CFLAGS+= -fno-builtin-strftime
index e7c546b..30f1ccf 100644 (file)
@@ -286,7 +286,7 @@ mfi_dcmd_command(int fd, uint32_t opcode, void *buf, size_t bufsize,
        if (statusp != NULL)
                *statusp = dcmd->header.cmd_status;
        else if (dcmd->header.cmd_status != MFI_STAT_OK) {
-               warnx("Command failed: %s",
+               warnx("Command 0x%08x failed: %s", opcode,
                    mfi_status(dcmd->header.cmd_status));
                errno = EIO;
                return (-1);
index 0b5d37b..b4d9a54 100644 (file)
 #include <err.h>
 #include <errno.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);
 
 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;
@@ -69,8 +70,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;
@@ -338,6 +339,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);
@@ -782,7 +790,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. */
@@ -1071,10 +1079,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;
@@ -1084,9 +1091,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);
@@ -1164,6 +1174,7 @@ dump_config(int fd, struct mfi_config_data *config)
        }
 }
 
+#ifdef DEBUG
 static int
 debug_config(int ac, char **av)
 {
@@ -1191,7 +1202,7 @@ debug_config(int ac, char **av)
        }
 
        /* Dump out the configuration. */
-       dump_config(fd, config);
+       dump_config(fd, config, NULL);
        free(config);
        close(fd);
 
@@ -1243,7 +1254,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_foreign.c b/usr.sbin/mfiutil/mfi_foreign.c
new file mode 100644 (file)
index 0000000..8983b8f
--- /dev/null
@@ -0,0 +1,402 @@
+/*-
+ * Copyright (c) 2008, 2009 Yahoo!, Inc.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "mfiutil.h"
+
+MFI_TABLE(top, foreign);
+
+/* 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];
+};
+
+static int
+foreign_drives(int ac __unused, char **av __unused)
+{
+       struct mfi_pd_info info;
+       struct mfi_pd_list *list;
+       int error, fd;
+       u_int i;
+       fd = mfi_open(mfi_unit);
+       if (fd < 0) {
+               error = errno;
+               warn("mfi_open");
+               return (error);
+       }
+
+       list = NULL;
+       if (mfi_pd_get_list(fd, &list, NULL) < 0) {
+               error = errno;
+               warn("Failed to get drive list");
+               goto error;
+       }
+       /* List the drives. */
+       printf("mfi%d Foreign disks:\n", mfi_unit);
+       for (i = 0; i < list->count; i++) {
+               /* Skip non-hard disks. */
+               if (list->addr[i].scsi_dev_type != 0)
+                       continue;
+               /* Fetch details for this drive. */
+               if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,
+                   NULL) < 0) {
+                       error = errno;
+                       warn("Failed to fetch info for drive %u",
+                           list->addr[i].device_id);
+                       goto error;
+               }
+
+               if (!info.state.ddf.v.pd_type.is_foreign)
+                       continue;
+
+               printf("%s ", mfi_drive_name(&info, list->addr[i].device_id,
+                   MFI_DNAME_DEVICE_ID));
+               print_pd(&info, -1);
+               printf(" %s\n", mfi_drive_name(&info, list->addr[i].device_id,
+                   MFI_DNAME_ES));
+       }
+error:
+       if(list)
+               free(list);
+       close(fd);
+       error = 0;
+       return (0);
+}
+MFI_COMMAND(foreign, drives, foreign_drives);
+
+static int
+foreign_clear(int ac __unused, char **av __unused)
+{
+       int ch, error, fd;
+
+       fd = mfi_open(mfi_unit);
+       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(int ac __unused, char **av __unused)
+{
+       struct mfi_foreign_scan_info info;
+       int error, fd;
+
+       fd = mfi_open(mfi_unit);
+       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)
+{
+       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", cfgidx);
+               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
+        */
+       dump_config(fd, config, prefix);
+       free(config);
+
+       return (0);
+}
+
+static int
+foreign_display(int ac, char **av)
+{
+       struct mfi_foreign_scan_info info;
+       uint8_t i;
+       int error, fd;
+
+       if (2 < ac) {
+               warnx("foreign display: extra arguments");
+                return (EINVAL);
+       }
+
+       fd = mfi_open(mfi_unit);
+       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 (0 == info.count) {
+               warnx("foreign display: no foreign configs found");
+               close(fd);
+               return (EINVAL);
+       }
+
+       if (1 == ac) {
+               for (i = 0; i < info.count; i++) {
+                       error = foreign_show_cfg(fd,
+                               MFI_DCMD_CFG_FOREIGN_DISPLAY, i);
+                       if(0 != error) {
+                               close(fd);
+                               return (error);
+                       }
+                       if (i < info.count - 1)
+                               printf("\n");
+               }
+       } else if (2 == ac) {
+               error = foreign_show_cfg(fd,
+                       MFI_DCMD_CFG_FOREIGN_DISPLAY, atoi(av[1]));
+               if (0 != error) {
+                       close(fd);
+                       return (error);
+               }
+       }
+
+       close(fd);
+       return (0);
+}
+MFI_COMMAND(foreign, display, foreign_display);
+
+static int
+foreign_preview(int ac, char **av)
+{
+       struct mfi_foreign_scan_info info;
+       uint8_t i;
+       int error, fd;
+
+       if (2 < ac) {
+               warnx("foreign preview: extra arguments");
+                return (EINVAL);
+       }
+
+       fd = mfi_open(mfi_unit);
+       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 (0 == info.count) {
+               warnx("foreign preview: no foreign configs found");
+               close(fd);
+               return (EINVAL);
+       }
+
+       if (1 == ac) {
+               for (i = 0; i < info.count; i++) {
+                       error = foreign_show_cfg(fd,
+                               MFI_DCMD_CFG_FOREIGN_PREVIEW, i);
+                       if(0 != error) {
+                               close(fd);
+                               return (error);
+                       }
+                       if (i < info.count - 1)
+                               printf("\n");
+               }
+       } else if (2 == ac) {
+               error = foreign_show_cfg(fd,
+                       MFI_DCMD_CFG_FOREIGN_PREVIEW, atoi(av[1]));
+               if (0 != error) {
+                       close(fd);
+                       return (error);
+               }
+       }
+
+       close(fd);
+       return (0);
+}
+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 (2 < ac) {
+               warnx("foreign preview: extra arguments");
+                return (EINVAL);
+       }
+
+       fd = mfi_open(mfi_unit);
+       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 (0 == info.count) {
+               warnx("foreign import: no foreign configs found");
+               close(fd);
+               return (EINVAL);
+       }
+
+       if (1 == ac) {
+               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 (1 == ac)
+               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);
index 8ba0e03..9ecf84b 100644 (file)
 #include <unistd.h>
 #include "mfiutil.h"
 
+const char* foreign_state = " (FOREIGN)";
+
 MFI_TABLE(top, show);
 
-static void
+void
 format_stripe(char *buf, size_t buflen, uint8_t stripe)
 {
 
@@ -241,7 +243,7 @@ show_battery(int ac, __unused char **av)
 }
 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;
@@ -262,19 +264,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 = mfi_pd_inq_string(info);
        if (s != NULL)
                printf(" %s", s);
@@ -510,6 +517,8 @@ show_drives(int ac, __unused char **av)
                        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;
        }
index f699951..be32d71 100644 (file)
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD: src/usr.sbin/mfiutil/mfiutil.8,v 1.9 2011/09/02 16:00:51 jhb Exp $
 .\"
-.Dd January 6, 2012
+.Dd April 1, 2013
 .Dt MFIUTIL 8
 .Os
 .Sh NAME
 .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 drives
+.Nm
+.Op Fl u Ar unit
+.Cm foreign clear Op Ar config
+.Nm
+.Op Fl u Ar unit
+.Cm foreign display 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
 .Sh DESCRIPTION
 The
@@ -561,6 +579,38 @@ 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 drives
+Scan for drives flagged as foreign and display them.
+.It Cm foreign clear Op config
+Clear the specifed foreign
+.Ar config
+or all if no
+.Ar config
+argument is provided.
+.It Cm foreign display Op config
+Display 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 .
index 95579ad..55ed3e1 100644 (file)
@@ -83,6 +83,12 @@ 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 drives            - list foreign drives\n");
+       fprintf(stderr, "    foreign clear [volume]    - clear foreign configurations (default all)\n");
+       fprintf(stderr, "    foreign display [volume]  - 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");
 #ifdef DEBUG
        fprintf(stderr, "    debug                     - debug 'show config'\n");
index 42f0bd8..fc84935 100644 (file)
@@ -91,6 +91,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,
@@ -107,5 +109,9 @@ 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);
 
 #endif /* !__MFIUTIL_H__ */