From nobody@FreeBSD.org  Wed Sep 26 12:32:53 2012
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 2667D106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 26 Sep 2012 12:32:53 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 0E9368FC0A
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 26 Sep 2012 12:32:53 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.5/8.14.5) with ESMTP id q8QCWq4k081913
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 26 Sep 2012 12:32:52 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.5/8.14.5/Submit) id q8QCWqvT081912;
	Wed, 26 Sep 2012 12:32:52 GMT
	(envelope-from nobody)
Message-Id: <201209261232.q8QCWqvT081912@red.freebsd.org>
Date: Wed, 26 Sep 2012 12:32:52 GMT
From: Steven Hartland <steven.hartland@multiplay.co.uk>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Improvements to mfi support including foreign disks / configs in mfiutil
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         172091
>Category:       kern
>Synopsis:       [mfi] [patch] Improvements to mfi support including foreign disks / configs in mfiutil
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    sbruno
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 26 12:40:06 UTC 2012
>Closed-Date:    Sat Jun 08 02:57:48 UTC 2013
>Last-Modified:  Fri Jul 12 02:30:00 UTC 2013
>Originator:     Steven Hartland
>Release:        8.3-RELEASE
>Organization:
Multiplay
>Environment:
FreeBSD dev 8.3-RELEASE-p4 FreeBSD 8.3-RELEASE-p4 #22: Mon Sep 17 17:18:32 UTC 2012     root@dev:/usr/obj/usr/src/sys/MULTIPLAY  amd64
>Description:
Currently mfiutil lacks support for foreign disks.

Along with the missing functionality this also causes confusing errors to be returned when using otherwise good disks with other commands as can be seen in the following PR:
http://www.freebsd.org/cgi/query-pr.cgi?pr=157293

When run under a debug kernel a MFI_DCMD_CFG_FOREIGN_IMPORT call from user space will cause a panic:
Lock MFI config not exclusively locked @ /usr/src/sys/dev/mfi/mfi.c:1001

When a long running command operates a timeout error is generated. The current timeout is hardcoded at 30 seconds which isn't always long enough for operations such as secure erase.
>How-To-Repeat:
1. Try to work with foreign configurations / disks under mfi.
2. Make a MFI_DCMD_CFG_FOREIGN_IMPORT call from user space under a debug kernel
3. Run a controller command which takes more than 30 seconds, a timeout will be generated.

>Fix:
The attached patch fixes all these issue.

It adds support for foreign disks / configs this implements the following new
methods to mfiutil
* 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

mfiutil show drives - now identifies foreign drives

It should be noted that although foreign import takes a configuration option
this currently fails with error code 0x03 (invalid argument). This also
occurs with MegaCli so its currently thought this is a firmware bug.

Fixes a panic when MFI_DCMD_CFG_FOREIGN_IMPORT is called from user space.

Adds hw.mfi.cmd_timeout loader / sysctl tuneable which controls the default
timeout used in the mfi driver. This is useful for long running commands
such as secure erase.

Additional debugging of DCMD commands has also been added which added identifying the DCMD's used by MegaCli to perform the various actions.

Patch attached with submission follows:

Add support for foreign disks / configs this implements the following new
methods to mfiutil
* 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

mfiutil show drives - now identifies foreign drives

It should be noted that although foreign import takes a configuration option
this currently fails with error code 0x03 (invalid argument). This also
occurs with MegaCli so its currently thought this is a firmware bug.

Fixes a panic when MFI_DCMD_CFG_FOREIGN_IMPORT is called from user space.

Adds hw.mfi.cmd_timeout loader / sysctl tuneable which controls the default
timeout used in the mfi driver. This is useful for long running commands
such as secure erase.

Additional debugging of DCMD commands has also been added which added
identifying the DCMD's used by MegaCli to perform the various actions.
--- usr.sbin/mfiutil/Makefile.orig	2012-03-03 06:15:13.000000000 +0000
+++ usr.sbin/mfiutil/Makefile	2012-09-21 15:52:24.648147593 +0000
@@ -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_patrol.c mfi_show.c mfi_volume.c mfi_foreign.c
 MAN8=	mfiutil.8
 
 CFLAGS+= -fno-builtin-strftime
--- usr.sbin/mfiutil/mfi_cmd.c.orig	2012-03-03 06:15:13.000000000 +0000
+++ usr.sbin/mfiutil/mfi_cmd.c	2012-09-24 13:22:53.204020111 +0000
@@ -284,7 +284,7 @@
 	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);
--- usr.sbin/mfiutil/mfi_config.c.orig	2012-03-03 06:15:13.000000000 +0000
+++ usr.sbin/mfiutil/mfi_config.c	2012-09-24 16:39:46.856313431 +0000
@@ -36,19 +36,13 @@
 #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);
 
@@ -80,9 +74,17 @@
         }
         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;
@@ -97,8 +99,8 @@
 	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 @@
 			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 @@
 
 #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 @@
 }
 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 @@
 	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 @@
 	}
 }
 
+#ifdef DEBUG
 static int
 debug_config(int ac, char **av)
 {
@@ -1213,7 +1225,7 @@
 	}
 
 	/* Dump out the configuration. */
-	dump_config(fd, config);
+	dump_config(fd, config, NULL);
 	free(config);
 	close(fd);
 
@@ -1265,7 +1277,7 @@
 		close(fd);
 		return (error);
 	}
-	dump_config(fd, config);
+	dump_config(fd, config, NULL);
 	free(config);
 	close(fd);
 
--- usr.sbin/mfiutil/mfi_show.c.orig	2012-03-03 06:15:13.000000000 +0000
+++ usr.sbin/mfiutil/mfi_show.c	2012-09-21 15:53:51.791817529 +0000
@@ -39,9 +39,11 @@
 #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 @@
 }
 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 @@
 		    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 @@
 			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;
 	}
--- usr.sbin/mfiutil/mfiutil.c.orig	2012-03-03 06:15:13.000000000 +0000
+++ usr.sbin/mfiutil/mfiutil.c	2012-09-25 12:16:01.912563546 +0000
@@ -83,6 +83,12 @@
 	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");
--- usr.sbin/mfiutil/mfiutil.h.orig	2012-03-03 06:15:13.000000000 +0000
+++ usr.sbin/mfiutil/mfiutil.h	2012-09-24 16:35:21.816610669 +0000
@@ -135,6 +135,8 @@
 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,
@@ -151,5 +153,9 @@
 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__ */
--- sys/dev/mfi/mfi_debug.c.orig	2012-03-03 06:15:13.000000000 +0000
+++ sys/dev/mfi/mfi_debug.c	2012-09-25 15:07:09.318736816 +0000
@@ -54,6 +54,85 @@
 #include <dev/mfi/mfi_ioctl.h>
 #include <dev/mfi/mfivar.h>
 
+struct mfi_op_table_entry {
+	uint32_t    opcode;
+	const char  *desc;
+};
+
+/* Keep in sync with mfi_dcmd_t in mfireg.h */
+static struct mfi_op_table_entry mfi_op_codes[] = {
+	{ MFI_DCMD_CTRL_GETINFO, "MFI_DCMD_CTRL_GETINFO" },
+	{ MFI_DCMD_CTRL_EVENT_GETINFO, "MFI_DCMD_CTRL_EVENT_GETINFO" },
+	{ MFI_DCMD_CTRL_EVENT_GET, "MFI_DCMD_CTRL_EVENT_GET" },
+	{ MFI_DCMD_CTRL_EVENT_WAIT, "MFI_DCMD_CTRL_EVENT_WAIT" },
+	{ MFI_DCMD_CTRL_SHUTDOWN, "MFI_DCMD_CTRL_SHUTDOWN" },
+	{ MFI_DCMD_PR_GET_STATUS, "MFI_DCMD_PR_GET_STATUS" },
+	{ MFI_DCMD_PR_GET_PROPERTIES, "MFI_DCMD_PR_GET_PROPERTIES" },
+	{ MFI_DCMD_PR_SET_PROPERTIES, "MFI_DCMD_PR_SET_PROPERTIES" },
+	{ MFI_DCMD_PR_START, "MFI_DCMD_PR_START" },
+	{ MFI_DCMD_PR_STOP, "MFI_DCMD_PR_STOP" },
+	{ MFI_DCMD_TIME_SECS_GET, "MFI_DCMD_TIME_SECS_GET" },
+	{ MFI_DCMD_CTRL_MFC_DEFAULTS_GET, "MFI_DCMD_CTRL_MFC_DEFAULTS_GET" },
+	{ MFI_DCMD_CTRL_MFC_DEFAULTS_SET, "MFI_DCMD_CTRL_MFC_DEFAULTS_SET" },
+	{ MFI_DCMD_FLASH_FW_OPEN, "MFI_DCMD_FLASH_FW_OPEN" },
+	{ MFI_DCMD_FLASH_FW_DOWNLOAD, "MFI_DCMD_FLASH_FW_DOWNLOAD" },
+	{ MFI_DCMD_FLASH_FW_FLASH, "MFI_DCMD_FLASH_FW_FLASH" },
+	{ MFI_DCMD_FLASH_FW_CLOSE, "MFI_DCMD_FLASH_FW_CLOSE" },
+	{ MFI_DCMD_CTRL_FLUSHCACHE, "MFI_DCMD_CTRL_FLUSHCACHE" },
+	{ MFI_DCMD_PD_GET_LIST, "MFI_DCMD_PD_GET_LIST" },
+	{ MFI_DCMD_PD_LIST_QUERY, "MFI_DCMD_PD_LIST_QUERY" },
+	{ MFI_DCMD_PD_GET_INFO, "MFI_DCMD_PD_GET_INFO" },
+	{ MFI_DCMD_PD_STATE_SET, "MFI_DCMD_PD_STATE_SET" },
+	{ MFI_DCMD_PD_REBUILD_START, "MFI_DCMD_PD_REBUILD_START" },
+	{ MFI_DCMD_PD_REBUILD_ABORT, "MFI_DCMD_PD_REBUILD_ABORT" },
+	{ MFI_DCMD_PD_CLEAR_START, "MFI_DCMD_PD_CLEAR_START" },
+	{ MFI_DCMD_PD_CLEAR_ABORT, "MFI_DCMD_PD_CLEAR_ABORT" },
+	{ MFI_DCMD_PD_GET_PROGRESS, "MFI_DCMD_PD_GET_PROGRESS" },
+	{ MFI_DCMD_PD_LOCATE_START, "MFI_DCMD_PD_LOCATE_START" },
+	{ MFI_DCMD_PD_LOCATE_STOP, "MFI_DCMD_PD_LOCATE_STOP" },
+	{ MFI_DCMD_LD_GET_LIST, "MFI_DCMD_LD_GET_LIST" },
+	{ MFI_DCMD_LD_GET_INFO, "MFI_DCMD_LD_GET_INFO" },
+	{ MFI_DCMD_LD_GET_PROP, "MFI_DCMD_LD_GET_PROP" },
+	{ MFI_DCMD_LD_SET_PROP, "MFI_DCMD_LD_SET_PROP" },
+	{ MFI_DCMD_LD_INIT_START, "MFI_DCMD_LD_INIT_START" },
+	{ MFI_DCMD_LD_DELETE, "MFI_DCMD_LD_DELETE" },
+	{ MFI_DCMD_CFG_READ, "MFI_DCMD_CFG_READ" },
+	{ MFI_DCMD_CFG_ADD, "MFI_DCMD_CFG_ADD" },
+	{ MFI_DCMD_CFG_CLEAR, "MFI_DCMD_CFG_CLEAR" },
+	{ MFI_DCMD_CFG_MAKE_SPARE, "MFI_DCMD_CFG_MAKE_SPARE" },
+	{ MFI_DCMD_CFG_REMOVE_SPARE, "MFI_DCMD_CFG_REMOVE_SPARE" },
+	{ MFI_DCMD_CFG_FOREIGN_SCAN, "MFI_DCMD_CFG_FOREIGN_SCAN" },
+	{ MFI_DCMD_CFG_FOREIGN_DISPLAY, "MFI_DCMD_CFG_FOREIGN_DISPLAY" },
+	{ MFI_DCMD_CFG_FOREIGN_PREVIEW, "MFI_DCMD_CFG_FOREIGN_PREVIEW" },
+	{ MFI_DCMD_CFG_FOREIGN_IMPORT, "MFI_DCMD_CFG_FOREIGN_IMPORT" },
+	{ MFI_DCMD_CFG_FOREIGN_CLEAR, "MFI_DCMD_CFG_FOREIGN_CLEAR" },
+	{ MFI_DCMD_BBU_GET_STATUS, "MFI_DCMD_BBU_GET_STATUS" },
+	{ MFI_DCMD_BBU_GET_CAPACITY_INFO, "MFI_DCMD_BBU_GET_CAPACITY_INFO" },
+	{ MFI_DCMD_BBU_GET_DESIGN_INFO, "MFI_DCMD_BBU_GET_DESIGN_INFO" },
+	{ MFI_DCMD_CLUSTER, "MFI_DCMD_CLUSTER" },
+	{ MFI_DCMD_CLUSTER_RESET_ALL, "MFI_DCMD_CLUSTER_RESET_ALL" },
+	{ MFI_DCMD_CLUSTER_RESET_LD, "MFI_DCMD_CLUSTER_RESET_LD" }
+};
+
+static void
+mfi_dump_bytes(const char *prefix, unsigned char *p, int len)
+{
+       int i, c = 1, j = 0;
+
+       if (prefix)
+	       printf("%s: ", prefix);
+       printf("[%d]\ndata[%d] ", len, j);
+       for (i = 0; i < len; ++i) {
+	       printf(" %02x", p[i]);
+	       c++;
+	       if ( 32 == c ) {
+		       printf("\ndata[%d] ", j++);
+		       c = 1;
+	       }
+       }
+       printf("\n");
+}
+
 static void
 mfi_print_frame_flags(device_t dev, uint32_t flags)
 {
@@ -118,61 +197,16 @@
 {
 	struct mfi_dcmd_frame *dcmd;
 	struct mfi_frame_header *hdr;
-	const char *opcode;
 
 	dcmd = &cm->cm_frame->dcmd;
 	hdr = &dcmd->header;
 
-	switch (dcmd->opcode) {
-	case MFI_DCMD_CTRL_GETINFO:
-		opcode = "CTRL_GETINFO";
-		break;
-	case MFI_DCMD_CTRL_FLUSHCACHE:
-		opcode = "CTRL_FLUSHCACHE";
-		break;
-	case MFI_DCMD_CTRL_SHUTDOWN:
-		opcode = "CTRL_SHUTDOWN";
-		break;
-	case MFI_DCMD_CTRL_EVENT_GETINFO:
-		opcode = "EVENT_GETINFO";
-		break;
-	case MFI_DCMD_CTRL_EVENT_GET:
-		opcode = "EVENT_GET";
-		break;
-	case MFI_DCMD_CTRL_EVENT_WAIT:
-		opcode = "EVENT_WAIT";
-		break;
-	case MFI_DCMD_LD_GET_LIST:
-		opcode = "LD_GET_LIST";
-		break;
-	case MFI_DCMD_LD_GET_INFO:
-		opcode = "LD_GET_INFO";
-		break;
-	case MFI_DCMD_LD_GET_PROP:
-		opcode = "LD_GET_PROP";
-		break;
-	case MFI_DCMD_LD_SET_PROP:
-		opcode = "LD_SET_PROP";
-		break;
-	case MFI_DCMD_CLUSTER:
-		opcode = "CLUSTER";
-		break;
-	case MFI_DCMD_CLUSTER_RESET_ALL:
-		opcode = "CLUSTER_RESET_ALL";
-		break;
-	case MFI_DCMD_CLUSTER_RESET_LD:
-		opcode = "CLUSTER_RESET_LD";
-		break;
-	default:
-		opcode = "UNKNOWN";
-		break;
-	}
-
-	device_printf(dev, "cmd=MFI_CMD_DCMD opcode=%s data_len=%d\n",
-	    opcode, hdr->data_len);
+	device_printf(dev, "cmd=MFI_CMD_DCMD opcode=%s (0x%08x) data_len=%d\n",
+	    mfi_op_desc(dcmd->opcode), dcmd->opcode, hdr->data_len);
 	mfi_print_frame_flags(dev, hdr->flags);
 	mfi_print_sgl(hdr, &dcmd->sgl, hdr->sg_count);
-
+	if (NULL != dcmd->mbox)
+                mfi_dump_bytes("dcmd->mbox", dcmd->mbox, MFI_MBOX_SIZE);
 }
 
 static void
@@ -261,4 +295,19 @@
 	}
 }
 
+const char *
+mfi_op_desc(uint32_t opcode)
+{
+	int i;
+	int num_ops = sizeof(mfi_op_codes)/sizeof(mfi_op_codes[0]);
+	for (i = 0; i < num_ops; i++) {
+		if (mfi_op_codes[i].opcode == opcode)
+			return(mfi_op_codes[i].desc);
+		else if (mfi_op_codes[i].opcode > opcode)
+			break;
+	}
+
+	return ("UNKNOWN");
+}
+
 #endif
--- sys/dev/mfi/mfireg.h.orig	2012-03-03 06:15:13.000000000 +0000
+++ sys/dev/mfi/mfireg.h	2012-09-25 14:29:58.800392000 +0000
@@ -143,27 +143,32 @@
 	MFI_CMD_STP
 } mfi_cmd_t;
 
-/* Direct commands */
+/*
+ * Direct commands
+ *
+ * NOTE: Keep mfi_op_codes in mfi_debug.c up to date when adding values
+ */
 typedef enum {
 	MFI_DCMD_CTRL_GETINFO =		0x01010000,
-	MFI_DCMD_CTRL_MFC_DEFAULTS_GET =0x010e0201,
-	MFI_DCMD_CTRL_MFC_DEFAULTS_SET =0x010e0202,
-	MFI_DCMD_CTRL_FLUSHCACHE =	0x01101000,
-	MFI_DCMD_CTRL_SHUTDOWN =	0x01050000,
 	MFI_DCMD_CTRL_EVENT_GETINFO =	0x01040100,
 	MFI_DCMD_CTRL_EVENT_GET =	0x01040300,
 	MFI_DCMD_CTRL_EVENT_WAIT =	0x01040500,
+	MFI_DCMD_CTRL_SHUTDOWN =	0x01050000,
 	MFI_DCMD_PR_GET_STATUS =	0x01070100,
 	MFI_DCMD_PR_GET_PROPERTIES =	0x01070200,
 	MFI_DCMD_PR_SET_PROPERTIES =	0x01070300,
 	MFI_DCMD_PR_START =		0x01070400,
 	MFI_DCMD_PR_STOP =		0x01070500,
 	MFI_DCMD_TIME_SECS_GET =	0x01080201,
+	MFI_DCMD_CTRL_MFC_DEFAULTS_GET =0x010e0201,
+	MFI_DCMD_CTRL_MFC_DEFAULTS_SET =0x010e0202,
 	MFI_DCMD_FLASH_FW_OPEN =	0x010f0100,
 	MFI_DCMD_FLASH_FW_DOWNLOAD =	0x010f0200,
 	MFI_DCMD_FLASH_FW_FLASH =	0x010f0300,
 	MFI_DCMD_FLASH_FW_CLOSE =	0x010f0400,
+	MFI_DCMD_CTRL_FLUSHCACHE =	0x01101000,
 	MFI_DCMD_PD_GET_LIST =		0x02010000,
+	MFI_DCMD_PD_LIST_QUERY =	0x02010100,
 	MFI_DCMD_PD_GET_INFO = 		0x02020000,
 	MFI_DCMD_PD_STATE_SET =		0x02030100,
 	MFI_DCMD_PD_REBUILD_START =	0x02040100,
@@ -184,7 +189,11 @@
 	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,
--- sys/dev/mfi/mfivar.h.orig	2012-03-03 06:15:13.000000000 +0000
+++ sys/dev/mfi/mfivar.h	2012-09-25 14:50:12.073354183 +0000
@@ -387,6 +387,7 @@
 extern void mfi_print_cmd(struct mfi_command *cm);
 extern void mfi_dump_cmds(struct mfi_softc *sc);
 extern void mfi_validate_sg(struct mfi_softc *, struct mfi_command *, const char *, int );
+extern const char * mfi_op_desc(uint32_t opcode);
 #define MFI_PRINT_CMD(cm)	mfi_print_cmd(cm)
 #define MFI_DUMP_CMDS(sc)	mfi_dump_cmds(sc)
 #define MFI_VALIDATE_CMD(sc, cm) mfi_validate_sg(sc, cm, __FUNCTION__, __LINE__)
--- usr.sbin/mfiutil/mfi_foreign.c	2012-09-26 01:44:00.000000000 +0000
+++ usr.sbin/mfiutil/mfi_foreign.c	2012-09-26 01:47:24.062531098 +0000
@@ -0,0 +1,404 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#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, char **av)
+{
+	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, char **av)
+{
+	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, char **av)
+{
+	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, i;
+	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", i);
+		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);
--- usr.sbin/mfiutil/mfiutil.8.orig	2012-03-03 06:15:13.000000000 +0000
+++ usr.sbin/mfiutil/mfiutil.8	2012-09-26 11:59:05.298961617 +0000
@@ -140,6 +140,24 @@
 .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,37 @@
 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 .
--- sys/dev/mfi/mfi.c.orig	2012-03-03 06:15:13.000000000 +0000
+++ sys/dev/mfi/mfi.c	2012-09-26 01:40:03.283617692 +0000
@@ -133,6 +133,11 @@
 SYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds,
 	   0, "Max commands");
 
+static int	mfi_cmd_timeout = MFI_CMD_TIMEOUT;
+TUNABLE_INT("hw.mfi.cmd_timeout", &mfi_cmd_timeout);
+SYSCTL_INT(_hw_mfi, OID_AUTO, cmd_timeout, CTLFLAG_RW, &mfi_cmd_timeout,
+	   0, "Command timeout (in seconds)");
+
 /* Management interface */
 static d_open_t		mfi_open;
 static d_close_t	mfi_close;
@@ -535,7 +540,7 @@
 
 	/* Start the timeout watchdog */
 	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);
-	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
+	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
 	    mfi_timeout, sc);
 
 	return (0);
@@ -622,13 +627,14 @@
 	struct mfi_command *cm;
 	struct mfi_dcmd_frame *dcmd;
 	void *buf = NULL;
-	
+
 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
 	
 	cm = mfi_dequeue_free(sc);
 	if (cm == NULL)
 		return (EBUSY);
 
+
 	if ((bufsize > 0) && (bufp != NULL)) {
 		if (*bufp == NULL) {
 			buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
@@ -655,6 +661,7 @@
 	cm->cm_data = buf;
 	cm->cm_private = buf;
 	cm->cm_len = bufsize;
+	MFI_PRINT_CMD(cm);
 
 	*cmp = cm;
 	if ((bufp != NULL) && (*bufp == NULL) && (buf != NULL))
@@ -1756,6 +1763,7 @@
 	case MFI_DCMD_LD_DELETE:
 	case MFI_DCMD_CFG_ADD:
 	case MFI_DCMD_CFG_CLEAR:
+	case MFI_DCMD_CFG_FOREIGN_IMPORT:
 		sx_xlock(&sc->mfi_config_lock);
 		return (1);
 	default:
@@ -1778,6 +1786,7 @@
 	struct mfi_disk *ld, *ld2;
 	int error;
 
+	MFI_PRINT_CMD(cm);
 	mtx_assert(&sc->mfi_io_lock, MA_OWNED);
 	error = 0;
 	switch (cm->cm_frame->dcmd.opcode) {
@@ -1817,6 +1826,7 @@
 {
 	struct mfi_disk *ld, *ldn;
 
+	MFI_PRINT_CMD(cm);
 	switch (cm->cm_frame->dcmd.opcode) {
 	case MFI_DCMD_LD_DELETE:
 		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
@@ -1848,10 +1858,9 @@
 		}
 		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;
 	}
 }
@@ -2509,7 +2518,7 @@
 			break;
 		device_printf(sc->mfi_dev, "Dumping\n\n");
 		timedout = 0;
-		deadline = time_uptime - MFI_CMD_TIMEOUT;
+		deadline = time_uptime - mfi_cmd_timeout;
 		mtx_lock(&sc->mfi_io_lock);
 		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
 			if (cm->cm_timestamp < deadline) {
@@ -2540,7 +2549,7 @@
 	time_t deadline;
 	int timedout = 0;
 
-	deadline = time_uptime - MFI_CMD_TIMEOUT;
+	deadline = time_uptime - mfi_cmd_timeout;
 	mtx_lock(&sc->mfi_io_lock);
 	TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
 		if (sc->mfi_aen_cm == cm)
@@ -2562,7 +2571,7 @@
 
 	mtx_unlock(&sc->mfi_io_lock);
 
-	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,
+	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,
 	    mfi_timeout, sc);
 
 	if (0)


>Release-Note:
>Audit-Trail:

From: "Steven Hartland" <killing@multiplay.co.uk>
To: <bug-followup@freebsd.org>,
	<steven.hartland@multiplay.co.uk>
Cc:  
Subject: Re: kern/172091: [mfi] [patch] Improvements to mfi support including foreign disks / configs in mfiutil
Date: Wed, 31 Oct 2012 10:00:43 -0000

 Updated patch for 8-STABLE
 
 ================================================
 This e.mail is private and confidential between Multiplay (UK) Ltd. and the person or entity to whom it is addressed. In the event of misdirection, the recipient is prohibited from using, copying, printing or otherwise disseminating it or any information contained in it. 
 
 In the event of misdirection, illegible or incomplete transmission please telephone +44 845 868 1337
 or return the E.mail to postmaster@multiplay.co.uk.
 

From: "Steven Hartland" <killing@multiplay.co.uk>
To: <bug-followup@freebsd.org>
Cc:  
Subject: Re: kern/172091: [mfi] [patch] Improvements to mfi support including foreign disks / configs in mfiutil
Date: Thu, 1 Nov 2012 12:04:31 -0000

 This is a multi-part message in MIME format.
 
 ------=_NextPart_000_02D4_01CDB829.0CDC8180
 Content-Type: text/plain;
 	format=flowed;
 	charset="Windows-1252";
 	reply-type=original
 Content-Transfer-Encoding: 7bit
 
 Trying to send the updated patch again (renamed to .txt)
 
 ================================================
 This e.mail is private and confidential between Multiplay (UK) Ltd. and the person or entity to whom it is addressed. In the event of misdirection, the recipient is prohibited from using, copying, printing or otherwise disseminating it or any information contained in it. 
 
 In the event of misdirection, illegible or incomplete transmission please telephone +44 845 868 1337
 or return the E.mail to postmaster@multiplay.co.uk.
 ------=_NextPart_000_02D4_01CDB829.0CDC8180
 Content-Type: text/plain;
 	format=flowed;
 	name="z-mfi-foreign-timeout.txt";
 	reply-type=original
 Content-Transfer-Encoding: quoted-printable
 Content-Disposition: attachment;
 	filename="z-mfi-foreign-timeout.txt"
 
 Add support for foreign disks / configs this implements the following new=0A=
 methods to mfiutil=0A=
 * foreign scan - lists the number of foreign configs=0A=
 * foreign drives - lists the drives which are flagged as foreign=0A=
 * foreign display - displays the specified foreign configuration=0A=
 * foreign preview - previews the specified foreign configuration (after =
 import)=0A=
 * foreign clear - clears the foreign configuration=0A=
 * foreign import - imports the foreign configuration=0A=
 =0A=
 mfiutil show drives - now identifies foreign drives=0A=
 =0A=
 It should be noted that although foreign import takes a configuration =
 option=0A=
 this currently fails with error code 0x03 (invalid argument). This also=0A=
 occurs with MegaCli so its currently thought this is a firmware bug.=0A=
 =0A=
 Fixes a panic when MFI_DCMD_CFG_FOREIGN_IMPORT is called from user space.=0A=
 =0A=
 Adds hw.mfi.cmd_timeout loader / sysctl tuneable which controls the =
 default=0A=
 timeout used in the mfi driver. This is useful for long running commands=0A=
 such as secure erase.=0A=
 =0A=
 Additional debugging of DCMD commands has also been added which added=0A=
 identifying the DCMD's used by MegaCli to perform the various actions.=0A=
 --- usr.sbin/mfiutil/Makefile.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ usr.sbin/mfiutil/Makefile	2012-09-21 15:52:24.648147593 +0000=0A=
 @@ -2,7 +2,7 @@=0A=
  PROG=3D	mfiutil=0A=
  =0A=
  SRCS=3D	mfiutil.c mfi_cmd.c mfi_config.c mfi_drive.c mfi_evt.c =
 mfi_flash.c \=0A=
 -	mfi_patrol.c mfi_show.c mfi_volume.c=0A=
 +	mfi_patrol.c mfi_show.c mfi_volume.c mfi_foreign.c=0A=
  MAN8=3D	mfiutil.8=0A=
  =0A=
  CFLAGS+=3D -fno-builtin-strftime=0A=
 --- usr.sbin/mfiutil/mfi_cmd.c.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ usr.sbin/mfiutil/mfi_cmd.c	2012-09-24 13:22:53.204020111 +0000=0A=
 @@ -284,7 +284,7 @@=0A=
  	if (statusp !=3D NULL)=0A=
  		*statusp =3D dcmd->header.cmd_status;=0A=
  	else if (dcmd->header.cmd_status !=3D MFI_STAT_OK) {=0A=
 -		warnx("Command failed: %s",=0A=
 +		warnx("Command 0x%08x failed: %s", opcode,=0A=
  		    mfi_status(dcmd->header.cmd_status));=0A=
  		errno =3D EIO;=0A=
  		return (-1);=0A=
 --- usr.sbin/mfiutil/mfi_config.c.orig	2012-03-03 06:15:13.000000000 =
 +0000=0A=
 +++ usr.sbin/mfiutil/mfi_config.c	2012-09-24 16:39:46.856313431 +0000=0A=
 @@ -36,19 +36,13 @@=0A=
  #include <err.h>=0A=
  #include <errno.h>=0A=
  #include <libutil.h>=0A=
 -#ifdef DEBUG=0A=
  #include <stdint.h>=0A=
 -#endif=0A=
  #include <stdio.h>=0A=
  #include <stdlib.h>=0A=
  #include <string.h>=0A=
  #include <unistd.h>=0A=
  #include "mfiutil.h"=0A=
  =0A=
 -#ifdef DEBUG=0A=
 -static void	dump_config(int fd, struct mfi_config_data *config);=0A=
 -#endif=0A=
 -=0A=
  static int	add_spare(int ac, char **av);=0A=
  static int	remove_spare(int ac, char **av);=0A=
  =0A=
 @@ -80,9 +74,17 @@=0A=
          }=0A=
          return (iv);=0A=
  }=0A=
 +=0A=
  int=0A=
  mfi_config_read(int fd, struct mfi_config_data **configp)=0A=
  {=0A=
 +	return mfi_config_read_opcode(fd, MFI_DCMD_CFG_READ, configp, NULL, 0);=0A=
 +}=0A=
 +=0A=
 +int=0A=
 +mfi_config_read_opcode(int fd, uint32_t opcode, struct mfi_config_data =
 **configp,=0A=
 +	uint8_t *mbox, size_t mboxlen)=0A=
 +{=0A=
  	struct mfi_config_data *config;=0A=
  	uint32_t config_size;=0A=
  	int error;=0A=
 @@ -97,8 +99,8 @@=0A=
  	config =3D reallocf(config, config_size);=0A=
  	if (config =3D=3D NULL)=0A=
  		return (-1);=0A=
 -	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_READ, config,=0A=
 -	    config_size, NULL, 0, NULL) < 0) {=0A=
 +	if (mfi_dcmd_command(fd, opcode, config,=0A=
 +	    config_size, mbox, mboxlen, NULL) < 0) {=0A=
  		error =3D errno;=0A=
  		free(config);=0A=
  		errno =3D error;=0A=
 @@ -366,6 +368,13 @@=0A=
  			info->drives =3D NULL;=0A=
  			return (EINVAL);=0A=
  		}=0A=
 +=0A=
 +		if (pinfo->state.ddf.v.pd_type.is_foreign) {=0A=
 +			warnx("Drive %u is foreign", device_id);=0A=
 +			free(info->drives);=0A=
 +			info->drives =3D NULL;=0A=
 +			return (EINVAL);=0A=
 +		}=0A=
  	}=0A=
  =0A=
  	return (0);=0A=
 @@ -804,7 +813,7 @@=0A=
  =0A=
  #ifdef DEBUG=0A=
  	if (dump)=0A=
 -		dump_config(fd, config);=0A=
 +		dump_config(fd, config, NULL);=0A=
  #endif=0A=
  =0A=
  	/* Send the new config to the controller. */=0A=
 @@ -1093,10 +1102,9 @@=0A=
  }=0A=
  MFI_COMMAND(top, remove, remove_spare);=0A=
  =0A=
 -#ifdef DEBUG=0A=
  /* Display raw data about a config. */=0A=
 -static void=0A=
 -dump_config(int fd, struct mfi_config_data *config)=0A=
 +void=0A=
 +dump_config(int fd, struct mfi_config_data *config, const char =
 *msg_prefix)=0A=
  {=0A=
  	struct mfi_array *ar;=0A=
  	struct mfi_ld_config *ld;=0A=
 @@ -1106,9 +1114,12 @@=0A=
  	char *p;=0A=
  	int i, j;=0A=
  =0A=
 +	if (NULL =3D=3D msg_prefix)=0A=
 +		msg_prefix =3D "Configuration (Debug)";=0A=
 +=0A=
  	printf(=0A=
 -	    "mfi%d Configuration (Debug): %d arrays, %d volumes, %d spares\n",=0A=
 -	    mfi_unit, config->array_count, config->log_drv_count,=0A=
 +	    "mfi%d %s: %d arrays, %d volumes, %d spares\n", mfi_unit,=0A=
 +	    msg_prefix, config->array_count, config->log_drv_count,=0A=
  	    config->spares_count);=0A=
  	printf("  array size: %u\n", config->array_size);=0A=
  	printf("  volume size: %u\n", config->log_drv_size);=0A=
 @@ -1186,6 +1197,7 @@=0A=
  	}=0A=
  }=0A=
  =0A=
 +#ifdef DEBUG=0A=
  static int=0A=
  debug_config(int ac, char **av)=0A=
  {=0A=
 @@ -1213,7 +1225,7 @@=0A=
  	}=0A=
  =0A=
  	/* Dump out the configuration. */=0A=
 -	dump_config(fd, config);=0A=
 +	dump_config(fd, config, NULL);=0A=
  	free(config);=0A=
  	close(fd);=0A=
  =0A=
 @@ -1265,7 +1277,7 @@=0A=
  		close(fd);=0A=
  		return (error);=0A=
  	}=0A=
 -	dump_config(fd, config);=0A=
 +	dump_config(fd, config, NULL);=0A=
  	free(config);=0A=
  	close(fd);=0A=
  =0A=
 --- usr.sbin/mfiutil/mfi_show.c.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ usr.sbin/mfiutil/mfi_show.c	2012-09-21 15:53:51.791817529 +0000=0A=
 @@ -39,9 +39,11 @@=0A=
  #include <unistd.h>=0A=
  #include "mfiutil.h"=0A=
  =0A=
 +const char* foreign_state =3D " (FOREIGN)";=0A=
 +=0A=
  MFI_TABLE(top, show);=0A=
  =0A=
 -static void=0A=
 +void=0A=
  format_stripe(char *buf, size_t buflen, uint8_t stripe)=0A=
  {=0A=
  =0A=
 @@ -241,7 +243,7 @@=0A=
  }=0A=
  MFI_COMMAND(show, battery, show_battery);=0A=
  =0A=
 -static void=0A=
 +void=0A=
  print_ld(struct mfi_ld_info *info, int state_len)=0A=
  {=0A=
  	struct mfi_ld_params *params =3D &info->ld_config.params;=0A=
 @@ -262,19 +264,24 @@=0A=
  		    mfi_ldstate(params->state));=0A=
  }=0A=
  =0A=
 -static void=0A=
 +void=0A=
  print_pd(struct mfi_pd_info *info, int state_len)=0A=
  {=0A=
  	const char *s;=0A=
 -	char buf[6];=0A=
 +	char buf[256];=0A=
  =0A=
  	humanize_number(buf, sizeof(buf), info->raw_size * 512, "",=0A=
  	    HN_AUTOSCALE, HN_B | HN_NOSPACE |HN_DECIMAL);=0A=
  	printf("(%6s) ", buf);=0A=
 +	if (info->state.ddf.v.pd_type.is_foreign) {=0A=
 +		sprintf(buf, "%s%s", mfi_pdstate(info->fw_state), foreign_state);=0A=
 +		s =3D buf;=0A=
 +	} else=0A=
 +		s =3D mfi_pdstate(info->fw_state);=0A=
  	if (state_len > 0)=0A=
 -		printf("%-*s", state_len, mfi_pdstate(info->fw_state));=0A=
 +		printf("%-*s", state_len, s);=0A=
  	else=0A=
 -		printf("%s", mfi_pdstate(info->fw_state));=0A=
 +		printf(s);=0A=
  	s =3D mfi_pd_inq_string(info);=0A=
  	if (s !=3D NULL)=0A=
  		printf(" %s", s);=0A=
 @@ -510,6 +517,8 @@=0A=
  			goto error;=0A=
  		}=0A=
  		len =3D strlen(mfi_pdstate(info.fw_state));=0A=
 +		if (info.state.ddf.v.pd_type.is_foreign)=0A=
 +			len +=3D strlen(foreign_state);=0A=
  		if (len > state_len)=0A=
  			state_len =3D len;=0A=
  	}=0A=
 --- usr.sbin/mfiutil/mfiutil.c.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ usr.sbin/mfiutil/mfiutil.c	2012-09-25 12:16:01.912563546 +0000=0A=
 @@ -83,6 +83,12 @@=0A=
  	fprintf(stderr, "    patrol <disable|auto|manual> [interval =
 [start]]\n");=0A=
  	fprintf(stderr, "    start patrol              - start a patrol =
 read\n");=0A=
  	fprintf(stderr, "    stop patrol               - stop a patrol =
 read\n");=0A=
 +	fprintf(stderr, "    foreign scan              - scan for foreign =
 configurations\n");=0A=
 +	fprintf(stderr, "    foreign drives            - list foreign =
 drives\n");=0A=
 +	fprintf(stderr, "    foreign clear [volume]    - clear foreign =
 configurations (default all)\n");=0A=
 +	fprintf(stderr, "    foreign display [volume]  - display foreign =
 configurations (default all)\n");=0A=
 +	fprintf(stderr, "    foreign preview [volume]  - preview foreign =
 configurations (default all)\n");=0A=
 +	fprintf(stderr, "    foreign import [volume]   - import foreign =
 configurations (default all)\n");=0A=
  	fprintf(stderr, "    flash <firmware>\n");=0A=
  #ifdef DEBUG=0A=
  	fprintf(stderr, "    debug                     - debug 'show =
 config'\n");=0A=
 --- usr.sbin/mfiutil/mfiutil.h.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ usr.sbin/mfiutil/mfiutil.h	2012-09-24 16:35:21.816610669 +0000=0A=
 @@ -135,6 +135,8 @@=0A=
  const char *mfi_volume_name(int fd, uint8_t target_id);=0A=
  int	mfi_volume_busy(int fd, uint8_t target_id);=0A=
  int	mfi_config_read(int fd, struct mfi_config_data **configp);=0A=
 +int	mfi_config_read_opcode(int fd, uint32_t opcode,=0A=
 +    struct mfi_config_data **configp, uint8_t *mbox, size_t mboxlen);=0A=
  int	mfi_lookup_drive(int fd, char *drive, uint16_t *device_id);=0A=
  int	mfi_lookup_volume(int fd, const char *name, uint8_t *target_id);=0A=
  int	mfi_dcmd_command(int fd, uint32_t opcode, void *buf, size_t bufsize,=0A=
 @@ -151,5 +153,9 @@=0A=
  const char *mfi_status(u_int status_code);=0A=
  const char *mfi_drive_name(struct mfi_pd_info *pinfo, uint16_t =
 device_id,=0A=
      uint32_t def);=0A=
 +void	format_stripe(char *buf, size_t buflen, uint8_t stripe);=0A=
 +void	print_ld(struct mfi_ld_info *info, int state_len);=0A=
 +void	print_pd(struct mfi_pd_info *info, int state_len);=0A=
 +void	dump_config(int fd, struct mfi_config_data *config, const char* =
 msg_prefix);=0A=
  =0A=
  #endif /* !__MFIUTIL_H__ */=0A=
 --- sys/dev/mfi/mfi_debug.c.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ sys/dev/mfi/mfi_debug.c	2012-09-25 15:07:09.318736816 +0000=0A=
 @@ -54,6 +54,88 @@=0A=
  #include <dev/mfi/mfi_ioctl.h>=0A=
  #include <dev/mfi/mfivar.h>=0A=
  =0A=
 +struct mfi_op_table_entry {=0A=
 +	uint32_t    opcode;=0A=
 +	const char  *desc;=0A=
 +};=0A=
 +=0A=
 +/* Keep in sync with mfi_dcmd_t in mfireg.h */=0A=
 +static struct mfi_op_table_entry mfi_op_codes[] =3D {=0A=
 +	{ MFI_DCMD_CTRL_GETINFO, "MFI_DCMD_CTRL_GETINFO" },=0A=
 +	{ MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC, "MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC" =
 },=0A=
 +	{ MFI_DCMD_CTRL_EVENT_GETINFO, "MFI_DCMD_CTRL_EVENT_GETINFO" },=0A=
 +	{ MFI_DCMD_CTRL_EVENT_GET, "MFI_DCMD_CTRL_EVENT_GET" },=0A=
 +	{ MFI_DCMD_CTRL_EVENT_WAIT, "MFI_DCMD_CTRL_EVENT_WAIT" },=0A=
 +	{ MFI_DCMD_CTRL_SHUTDOWN, "MFI_DCMD_CTRL_SHUTDOWN" },=0A=
 +	{ MFI_DCMD_PR_GET_STATUS, "MFI_DCMD_PR_GET_STATUS" },=0A=
 +	{ MFI_DCMD_PR_GET_PROPERTIES, "MFI_DCMD_PR_GET_PROPERTIES" },=0A=
 +	{ MFI_DCMD_PR_SET_PROPERTIES, "MFI_DCMD_PR_SET_PROPERTIES" },=0A=
 +	{ MFI_DCMD_PR_START, "MFI_DCMD_PR_START" },=0A=
 +	{ MFI_DCMD_PR_STOP, "MFI_DCMD_PR_STOP" },=0A=
 +	{ MFI_DCMD_TIME_SECS_GET, "MFI_DCMD_TIME_SECS_GET" },=0A=
 +	{ MFI_DCMD_CTRL_MFC_DEFAULTS_GET, "MFI_DCMD_CTRL_MFC_DEFAULTS_GET" },=0A=
 +	{ MFI_DCMD_CTRL_MFC_DEFAULTS_SET, "MFI_DCMD_CTRL_MFC_DEFAULTS_SET" },=0A=
 +	{ MFI_DCMD_FLASH_FW_OPEN, "MFI_DCMD_FLASH_FW_OPEN" },=0A=
 +	{ MFI_DCMD_FLASH_FW_DOWNLOAD, "MFI_DCMD_FLASH_FW_DOWNLOAD" },=0A=
 +	{ MFI_DCMD_FLASH_FW_FLASH, "MFI_DCMD_FLASH_FW_FLASH" },=0A=
 +	{ MFI_DCMD_FLASH_FW_CLOSE, "MFI_DCMD_FLASH_FW_CLOSE" },=0A=
 +	{ MFI_DCMD_CTRL_FLUSHCACHE, "MFI_DCMD_CTRL_FLUSHCACHE" },=0A=
 +	{ MFI_DCMD_PD_GET_LIST, "MFI_DCMD_PD_GET_LIST" },=0A=
 +	{ MFI_DCMD_PD_LIST_QUERY, "MFI_DCMD_PD_LIST_QUERY" },=0A=
 +	{ MFI_DCMD_PD_GET_INFO, "MFI_DCMD_PD_GET_INFO" },=0A=
 +	{ MFI_DCMD_PD_STATE_SET, "MFI_DCMD_PD_STATE_SET" },=0A=
 +	{ MFI_DCMD_PD_REBUILD_START, "MFI_DCMD_PD_REBUILD_START" },=0A=
 +	{ MFI_DCMD_PD_REBUILD_ABORT, "MFI_DCMD_PD_REBUILD_ABORT" },=0A=
 +	{ MFI_DCMD_PD_CLEAR_START, "MFI_DCMD_PD_CLEAR_START" },=0A=
 +	{ MFI_DCMD_PD_CLEAR_ABORT, "MFI_DCMD_PD_CLEAR_ABORT" },=0A=
 +	{ MFI_DCMD_PD_GET_PROGRESS, "MFI_DCMD_PD_GET_PROGRESS" },=0A=
 +	{ MFI_DCMD_PD_LOCATE_START, "MFI_DCMD_PD_LOCATE_START" },=0A=
 +	{ MFI_DCMD_PD_LOCATE_STOP, "MFI_DCMD_PD_LOCATE_STOP" },=0A=
 +	{ MFI_DCMD_LD_MAP_GET_INFO, "MFI_DCMD_LD_MAP_GET_INFO" },=0A=
 +	{ MFI_DCMD_LD_SYNC, "MFI_DCMD_LD_SYNC" },=0A=
 +	{ MFI_DCMD_LD_GET_LIST, "MFI_DCMD_LD_GET_LIST" },=0A=
 +	{ MFI_DCMD_LD_GET_INFO, "MFI_DCMD_LD_GET_INFO" },=0A=
 +	{ MFI_DCMD_LD_GET_PROP, "MFI_DCMD_LD_GET_PROP" },=0A=
 +	{ MFI_DCMD_LD_SET_PROP, "MFI_DCMD_LD_SET_PROP" },=0A=
 +	{ MFI_DCMD_LD_INIT_START, "MFI_DCMD_LD_INIT_START" },=0A=
 +	{ MFI_DCMD_LD_DELETE, "MFI_DCMD_LD_DELETE" },=0A=
 +	{ MFI_DCMD_CFG_READ, "MFI_DCMD_CFG_READ" },=0A=
 +	{ MFI_DCMD_CFG_ADD, "MFI_DCMD_CFG_ADD" },=0A=
 +	{ MFI_DCMD_CFG_CLEAR, "MFI_DCMD_CFG_CLEAR" },=0A=
 +	{ MFI_DCMD_CFG_MAKE_SPARE, "MFI_DCMD_CFG_MAKE_SPARE" },=0A=
 +	{ MFI_DCMD_CFG_REMOVE_SPARE, "MFI_DCMD_CFG_REMOVE_SPARE" },=0A=
 +	{ MFI_DCMD_CFG_FOREIGN_SCAN, "MFI_DCMD_CFG_FOREIGN_SCAN" },=0A=
 +	{ MFI_DCMD_CFG_FOREIGN_DISPLAY, "MFI_DCMD_CFG_FOREIGN_DISPLAY" },=0A=
 +	{ MFI_DCMD_CFG_FOREIGN_PREVIEW, "MFI_DCMD_CFG_FOREIGN_PREVIEW" },=0A=
 +	{ MFI_DCMD_CFG_FOREIGN_IMPORT, "MFI_DCMD_CFG_FOREIGN_IMPORT" },=0A=
 +	{ MFI_DCMD_CFG_FOREIGN_CLEAR, "MFI_DCMD_CFG_FOREIGN_CLEAR" },=0A=
 +	{ MFI_DCMD_BBU_GET_STATUS, "MFI_DCMD_BBU_GET_STATUS" },=0A=
 +	{ MFI_DCMD_BBU_GET_CAPACITY_INFO, "MFI_DCMD_BBU_GET_CAPACITY_INFO" },=0A=
 +	{ MFI_DCMD_BBU_GET_DESIGN_INFO, "MFI_DCMD_BBU_GET_DESIGN_INFO" },=0A=
 +	{ MFI_DCMD_CLUSTER, "MFI_DCMD_CLUSTER" },=0A=
 +	{ MFI_DCMD_CLUSTER_RESET_ALL, "MFI_DCMD_CLUSTER_RESET_ALL" },=0A=
 +	{ MFI_DCMD_CLUSTER_RESET_LD, "MFI_DCMD_CLUSTER_RESET_LD" }=0A=
 +};=0A=
 +=0A=
 +static void=0A=
 +mfi_dump_bytes(const char *prefix, unsigned char *p, int len)=0A=
 +{=0A=
 +       int i, c =3D 1, j =3D 0;=0A=
 +=0A=
 +       if (prefix)=0A=
 +	       printf("%s: ", prefix);=0A=
 +       printf("[%d]\ndata[%d] ", len, j);=0A=
 +       for (i =3D 0; i < len; ++i) {=0A=
 +	       printf(" %02x", p[i]);=0A=
 +	       c++;=0A=
 +	       if ( 32 =3D=3D c ) {=0A=
 +		       printf("\ndata[%d] ", j++);=0A=
 +		       c =3D 1;=0A=
 +	       }=0A=
 +       }=0A=
 +       printf("\n");=0A=
 +}=0A=
 +=0A=
  static void=0A=
  mfi_print_frame_flags(device_t dev, uint32_t flags)=0A=
  {=0A=
 @@ -118,64 +197,16 @@=0A=
  {=0A=
  	struct mfi_dcmd_frame *dcmd;=0A=
  	struct mfi_frame_header *hdr;=0A=
 -	const char *opcode;=0A=
  =0A=
  	dcmd =3D &cm->cm_frame->dcmd;=0A=
  	hdr =3D &dcmd->header;=0A=
  =0A=
 -	switch (dcmd->opcode) {=0A=
 -	case MFI_DCMD_CTRL_GETINFO:=0A=
 -		opcode =3D "CTRL_GETINFO";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CTRL_FLUSHCACHE:=0A=
 -		opcode =3D "CTRL_FLUSHCACHE";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CTRL_SHUTDOWN:=0A=
 -		opcode =3D "CTRL_SHUTDOWN";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CTRL_EVENT_GETINFO:=0A=
 -		opcode =3D "EVENT_GETINFO";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CTRL_EVENT_GET:=0A=
 -		opcode =3D "EVENT_GET";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CTRL_EVENT_WAIT:=0A=
 -		opcode =3D "EVENT_WAIT";=0A=
 -		break;=0A=
 -	case MFI_DCMD_LD_GET_LIST:=0A=
 -		opcode =3D "LD_GET_LIST";=0A=
 -		break;=0A=
 -	case MFI_DCMD_LD_GET_INFO:=0A=
 -		opcode =3D "LD_GET_INFO";=0A=
 -		break;=0A=
 -	case MFI_DCMD_LD_GET_PROP:=0A=
 -		opcode =3D "LD_GET_PROP";=0A=
 -		break;=0A=
 -	case MFI_DCMD_LD_SET_PROP:=0A=
 -		opcode =3D "LD_SET_PROP";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CLUSTER:=0A=
 -		opcode =3D "CLUSTER";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CLUSTER_RESET_ALL:=0A=
 -		opcode =3D "CLUSTER_RESET_ALL";=0A=
 -		break;=0A=
 -	case MFI_DCMD_CLUSTER_RESET_LD:=0A=
 -		opcode =3D "CLUSTER_RESET_LD";=0A=
 -		break;=0A=
 -	case MFI_DCMD_LD_MAP_GET_INFO:=0A=
 -		opcode =3D "LD_MAP_GET_INFO";=0A=
 -		break;=0A=
 -	default:=0A=
 -		opcode =3D "UNKNOWN";=0A=
 -		break;=0A=
 -	}=0A=
 -=0A=
 -	device_printf(dev, "cmd=3DMFI_CMD_DCMD opcode=3D%s data_len=3D%d\n",=0A=
 -	    opcode, hdr->data_len);=0A=
 +	device_printf(dev, "cmd=3DMFI_CMD_DCMD opcode=3D%s (0x%08x) =
 data_len=3D%d\n",=0A=
 +	    mfi_op_desc(dcmd->opcode), dcmd->opcode, hdr->data_len);=0A=
  	mfi_print_frame_flags(dev, hdr->flags);=0A=
  	mfi_print_sgl(hdr, &dcmd->sgl, hdr->sg_count);=0A=
 -=0A=
 +	if (NULL !=3D dcmd->mbox)=0A=
 +                mfi_dump_bytes("dcmd->mbox", dcmd->mbox, MFI_MBOX_SIZE);=0A=
  }=0A=
  =0A=
  static void=0A=
 @@ -261,4 +295,19 @@=0A=
  	}=0A=
  }=0A=
  =0A=
 +const char *=0A=
 +mfi_op_desc(uint32_t opcode)=0A=
 +{=0A=
 +	int i;=0A=
 +	int num_ops =3D sizeof(mfi_op_codes)/sizeof(mfi_op_codes[0]);=0A=
 +	for (i =3D 0; i < num_ops; i++) {=0A=
 +		if (mfi_op_codes[i].opcode =3D=3D opcode)=0A=
 +			return(mfi_op_codes[i].desc);=0A=
 +		else if (mfi_op_codes[i].opcode > opcode)=0A=
 +			break;=0A=
 +	}=0A=
 +=0A=
 +	return ("UNKNOWN");=0A=
 +}=0A=
 +=0A=
  #endif=0A=
 --- sys/dev/mfi/mfireg.h.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ sys/dev/mfi/mfireg.h	2012-09-25 14:29:58.800392000 +0000=0A=
 @@ -143,27 +143,31 @@=0A=
  	MFI_CMD_STP=0A=
  } mfi_cmd_t;=0A=
  =0A=
 -/* Direct commands */=0A=
 +/*=0A=
 + * Direct commands=0A=
 + *=0A=
 + * NOTE: Keep mfi_op_codes in mfi_debug.c up to date when adding values=0A=
 + */=0A=
  typedef enum {=0A=
  	MFI_DCMD_CTRL_GETINFO =3D		0x01010000,=0A=
 -	MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC =3D0x0100e100,=0A=
 -	MFI_DCMD_CTRL_MFC_DEFAULTS_GET =3D0x010e0201,=0A=
 -	MFI_DCMD_CTRL_MFC_DEFAULTS_SET =3D0x010e0202,=0A=
 -	MFI_DCMD_CTRL_FLUSHCACHE =3D	0x01101000,=0A=
 -	MFI_DCMD_CTRL_SHUTDOWN =3D	0x01050000,=0A=
  	MFI_DCMD_CTRL_EVENT_GETINFO =3D	0x01040100,=0A=
  	MFI_DCMD_CTRL_EVENT_GET =3D	0x01040300,=0A=
  	MFI_DCMD_CTRL_EVENT_WAIT =3D	0x01040500,=0A=
 +	MFI_DCMD_CTRL_SHUTDOWN =3D	0x01050000,=0A=
  	MFI_DCMD_PR_GET_STATUS =3D	0x01070100,=0A=
  	MFI_DCMD_PR_GET_PROPERTIES =3D	0x01070200,=0A=
  	MFI_DCMD_PR_SET_PROPERTIES =3D	0x01070300,=0A=
  	MFI_DCMD_PR_START =3D		0x01070400,=0A=
  	MFI_DCMD_PR_STOP =3D		0x01070500,=0A=
  	MFI_DCMD_TIME_SECS_GET =3D	0x01080201,=0A=
 +	MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC =3D0x0100e100,=0A=
 +	MFI_DCMD_CTRL_MFC_DEFAULTS_GET =3D0x010e0201,=0A=
 +	MFI_DCMD_CTRL_MFC_DEFAULTS_SET =3D0x010e0202,=0A=
  	MFI_DCMD_FLASH_FW_OPEN =3D	0x010f0100,=0A=
  	MFI_DCMD_FLASH_FW_DOWNLOAD =3D	0x010f0200,=0A=
  	MFI_DCMD_FLASH_FW_FLASH =3D	0x010f0300,=0A=
  	MFI_DCMD_FLASH_FW_CLOSE =3D	0x010f0400,=0A=
 +	MFI_DCMD_CTRL_FLUSHCACHE =3D	0x01101000,=0A=
  	MFI_DCMD_PD_GET_LIST =3D		0x02010000,=0A=
 	MFI_DCMD_PD_LIST_QUERY =3D	0x02010100,=0A=
  	MFI_DCMD_PD_GET_INFO =3D 		0x02020000,=0A=
 @@ -184,7 +189,11 @@=0A=
 	MFI_DCMD_CFG_CLEAR =3D		0x04030000,=0A=
 	MFI_DCMD_CFG_MAKE_SPARE =3D	0x04040000,=0A=
 	MFI_DCMD_CFG_REMOVE_SPARE =3D	0x04050000,=0A=
 +	MFI_DCMD_CFG_FOREIGN_SCAN =3D	0x04060100,=0A=
 +	MFI_DCMD_CFG_FOREIGN_DISPLAY =3D	0x04060200,=0A=
 +	MFI_DCMD_CFG_FOREIGN_PREVIEW =3D	0x04060300,=0A=
 	MFI_DCMD_CFG_FOREIGN_IMPORT =3D	0x04060400,=0A=
 +	MFI_DCMD_CFG_FOREIGN_CLEAR =3D	0x04060500,=0A=
 	MFI_DCMD_BBU_GET_STATUS =3D	0x05010000,=0A=
 	MFI_DCMD_BBU_GET_CAPACITY_INFO =3D0x05020000,=0A=
 	MFI_DCMD_BBU_GET_DESIGN_INFO =3D	0x05030000,=0A=
 --- sys/dev/mfi/mfivar.h.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ sys/dev/mfi/mfivar.h	2012-09-25 14:50:12.073354183 +0000=0A=
 @@ -387,6 +387,7 @@=0A=
  extern void mfi_print_cmd(struct mfi_command *cm);=0A=
  extern void mfi_dump_cmds(struct mfi_softc *sc);=0A=
  extern void mfi_validate_sg(struct mfi_softc *, struct mfi_command *, =
 const char *, int );=0A=
 +extern const char * mfi_op_desc(uint32_t opcode);=0A=
  #define MFI_PRINT_CMD(cm)	mfi_print_cmd(cm)=0A=
  #define MFI_DUMP_CMDS(sc)	mfi_dump_cmds(sc)=0A=
  #define MFI_VALIDATE_CMD(sc, cm) mfi_validate_sg(sc, cm, __FUNCTION__, =
 __LINE__)=0A=
 --- /dev/null	2012-10-27 22:11:00.000000000 +0000=0A=
 +++ usr.sbin/mfiutil/mfi_foreign.c	2012-10-27 22:15:26.676979633 +0000=0A=
 @@ -0,0 +1,405 @@=0A=
 +/*-=0A=
 + * Copyright (c) 2008, 2009 Yahoo!, Inc.=0A=
 + * All rights reserved.=0A=
 + *=0A=
 + * Redistribution and use in source and binary forms, with or without=0A=
 + * modification, are permitted provided that the following conditions=0A=
 + * are met:=0A=
 + * 1. Redistributions of source code must retain the above copyright=0A=
 + *    notice, this list of conditions and the following disclaimer.=0A=
 + * 2. Redistributions in binary form must reproduce the above copyright=0A=
 + *    notice, this list of conditions and the following disclaimer in =
 the=0A=
 + *    documentation and/or other materials provided with the =
 distribution.=0A=
 + * 3. The names of the authors may not be used to endorse or promote=0A=
 + *    products derived from this software without specific prior written=0A=
 + *    permission.=0A=
 + *=0A=
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' =
 AND=0A=
 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=0A=
 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR =
 PURPOSE=0A=
 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE =
 LIABLE=0A=
 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR =
 CONSEQUENTIAL=0A=
 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE =
 GOODS=0A=
 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=0A=
 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, =
 STRICT=0A=
 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN =
 ANY WAY=0A=
 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY =
 OF=0A=
 + * SUCH DAMAGE.=0A=
 + *=0A=
 + * $FreeBSD$=0A=
 + */=0A=
 +=0A=
 +#include <sys/param.h>=0A=
 +#include <err.h>=0A=
 +#include <errno.h>=0A=
 +#include <fcntl.h>=0A=
 +#include <libutil.h>=0A=
 +#include <stdio.h>=0A=
 +#include <stdlib.h>=0A=
 +#include <string.h>=0A=
 +#include <unistd.h>=0A=
 +#include "mfiutil.h"=0A=
 +=0A=
 +MFI_TABLE(top, foreign);=0A=
 +=0A=
 +/* We currently don't know the full details of the following struct */=0A=
 +struct mfi_foreign_scan_cfg {=0A=
 +	char data[24];=0A=
 +};=0A=
 +=0A=
 +struct mfi_foreign_scan_info {=0A=
 +	uint32_t count; /* Number of foreign configs found */=0A=
 +	struct mfi_foreign_scan_cfg cfgs[8];=0A=
 +};=0A=
 +=0A=
 +static int=0A=
 +foreign_drives(int ac, char **av)=0A=
 +{=0A=
 +	struct mfi_pd_info info;=0A=
 +	struct mfi_pd_list *list;=0A=
 +	int error, fd;=0A=
 +	u_int i;=0A=
 +	fd =3D mfi_open(mfi_unit, O_RDONLY);=0A=
 +	if (fd < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("mfi_open");=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	list =3D NULL;=0A=
 +	if (mfi_pd_get_list(fd, &list, NULL) < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to get drive list");=0A=
 +		goto error;=0A=
 +	}=0A=
 +	/* List the drives. */=0A=
 +	printf("mfi%d Foreign disks:\n", mfi_unit);=0A=
 +	for (i =3D 0; i < list->count; i++) {=0A=
 +		/* Skip non-hard disks. */=0A=
 +		if (list->addr[i].scsi_dev_type !=3D 0)=0A=
 +			continue;=0A=
 +		/* Fetch details for this drive. */=0A=
 +		if (mfi_pd_get_info(fd, list->addr[i].device_id, &info,=0A=
 +		    NULL) < 0) {=0A=
 +			error =3D errno;=0A=
 +			warn("Failed to fetch info for drive %u",=0A=
 +			    list->addr[i].device_id);=0A=
 +			goto error;=0A=
 +		}=0A=
 +=0A=
 +		if (!info.state.ddf.v.pd_type.is_foreign)=0A=
 +			continue;=0A=
 +					=0A=
 +		printf("%s ", mfi_drive_name(&info, list->addr[i].device_id,=0A=
 +		    MFI_DNAME_DEVICE_ID));=0A=
 +		print_pd(&info, -1);=0A=
 +		printf(" %s\n", mfi_drive_name(&info, list->addr[i].device_id,=0A=
 +		    MFI_DNAME_ES));=0A=
 +	}=0A=
 +error:=0A=
 +	if(list)=0A=
 +		free(list);=0A=
 +	close(fd);=0A=
 +	error =3D 0;=0A=
 +	return (0);=0A=
 +}=0A=
 +MFI_COMMAND(foreign, drives, foreign_drives);=0A=
 +=0A=
 +static int=0A=
 +foreign_clear(int ac, char **av)=0A=
 +{=0A=
 +	int ch, error, fd;=0A=
 +=0A=
 +	fd =3D mfi_open(mfi_unit, O_RDWR);=0A=
 +	if (fd < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("mfi_open");=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	printf(=0A=
 +	    "Are you sure you wish to clear ALL foreign configurations"=0A=
 +	    " on mfi%u? [y/N] ", mfi_unit);=0A=
 +=0A=
 +	ch =3D getchar();=0A=
 +	if (ch !=3D 'y' && ch !=3D 'Y') {=0A=
 +		printf("\nAborting\n");=0A=
 +		close(fd);=0A=
 +		return (0);=0A=
 +	}=0A=
 +=0A=
 +	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_CLEAR, NULL, 0, NULL,=0A=
 +	    0, NULL) < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to clear foreign configuration");=0A=
 +		close(fd);=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	printf("mfi%d: Foreign configuration cleared\n", mfi_unit);=0A=
 +	close(fd);=0A=
 +	return (0);=0A=
 +}=0A=
 +MFI_COMMAND(foreign, clear, foreign_clear);=0A=
 +=0A=
 +static int=0A=
 +foreign_scan(int ac, char **av)=0A=
 +{=0A=
 +	struct mfi_foreign_scan_info info;=0A=
 +	int error, fd;=0A=
 +=0A=
 +	fd =3D mfi_open(mfi_unit, O_RDONLY);=0A=
 +	if (fd < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("mfi_open");=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,=0A=
 +	    sizeof(info), NULL, 0, NULL) < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to scan foreign configuration");=0A=
 +		close(fd);=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	printf("mfi%d: Found %d foreign configurations\n", mfi_unit,=0A=
 +	       info.count);=0A=
 +	close(fd);=0A=
 +	return (0);=0A=
 +}=0A=
 +MFI_COMMAND(foreign, scan, foreign_scan);=0A=
 +=0A=
 +static int=0A=
 +foreign_show_cfg(int fd, uint32_t opcode, uint8_t cfgidx)=0A=
 +{=0A=
 +	struct mfi_config_data *config;=0A=
 +	char prefix[26];=0A=
 +	int error, i;=0A=
 +	uint8_t mbox[4];=0A=
 +=0A=
 +	bzero(mbox, sizeof(mbox));=0A=
 +	mbox[0] =3D cfgidx;=0A=
 +	if (mfi_config_read_opcode(fd, opcode, &config, mbox, sizeof(mbox))=0A=
 +	    < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to get foreign config %d", i);=0A=
 +		close(fd);=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (opcode =3D=3D MFI_DCMD_CFG_FOREIGN_PREVIEW)=0A=
 +		sprintf(prefix, "Foreign configuration preview %d", cfgidx);=0A=
 +	else=0A=
 +		sprintf(prefix, "Foreign configuration %d", cfgidx);=0A=
 +	/*=0A=
 +	 * MegaCli uses DCMD opcodes: 0x03100200 (which fails) followed by=0A=
 +	 * 0x1a721880 which returns what looks to be drive / volume info=0A=
 +	 * but we have no real information on what these are or what they do=0A=
 +	 * so we're currently relying solely on the config returned above=0A=
 +	 */=0A=
 +	dump_config(fd, config, prefix);=0A=
 +	free(config);=0A=
 +=0A=
 +	return (0);=0A=
 +}=0A=
 +=0A=
 +static int=0A=
 +foreign_display(int ac, char **av)=0A=
 +{=0A=
 +	struct mfi_foreign_scan_info info;=0A=
 +	uint8_t i;=0A=
 +	int error, fd;=0A=
 +=0A=
 +	if (2 < ac) {=0A=
 +		warnx("foreign display: extra arguments");=0A=
 +                return (EINVAL);=0A=
 +	}=0A=
 +=0A=
 +	fd =3D mfi_open(mfi_unit, O_RDONLY);=0A=
 +	if (fd < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("mfi_open");=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,=0A=
 +	    sizeof(info), NULL, 0, NULL) < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to scan foreign configuration");=0A=
 +		close(fd);=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (0 =3D=3D info.count) {=0A=
 +		warnx("foreign display: no foreign configs found");=0A=
 +		close(fd);=0A=
 +		return (EINVAL);=0A=
 +	}=0A=
 +=0A=
 +	if (1 =3D=3D ac) {=0A=
 +		for (i =3D 0; i < info.count; i++) {=0A=
 +			error =3D foreign_show_cfg(fd,=0A=
 +				MFI_DCMD_CFG_FOREIGN_DISPLAY, i);=0A=
 +			if(0 !=3D error) {=0A=
 +				close(fd);=0A=
 +				return (error);=0A=
 +			}=0A=
 +			if (i < info.count - 1)=0A=
 +				printf("\n");=0A=
 +		}=0A=
 +	} else if (2 =3D=3D ac) {=0A=
 +		error =3D foreign_show_cfg(fd,=0A=
 +			MFI_DCMD_CFG_FOREIGN_DISPLAY, atoi(av[1]));=0A=
 +		if (0 !=3D error) {=0A=
 +			close(fd);=0A=
 +			return (error);=0A=
 +		}=0A=
 +	}=0A=
 +	=0A=
 +	close(fd);=0A=
 +	return (0);=0A=
 +}=0A=
 +MFI_COMMAND(foreign, display, foreign_display);=0A=
 +=0A=
 +static int=0A=
 +foreign_preview(int ac, char **av)=0A=
 +{=0A=
 +	struct mfi_foreign_scan_info info;=0A=
 +	uint8_t i;=0A=
 +	int error, fd;=0A=
 +=0A=
 +	if (2 < ac) {=0A=
 +		warnx("foreign preview: extra arguments");=0A=
 +                return (EINVAL);=0A=
 +	}=0A=
 +=0A=
 +	fd =3D mfi_open(mfi_unit, O_RDONLY);=0A=
 +	if (fd < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("mfi_open");=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,=0A=
 +	    sizeof(info), NULL, 0, NULL) < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to scan foreign configuration");=0A=
 +		close(fd);=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (0 =3D=3D info.count) {=0A=
 +		warnx("foreign preview: no foreign configs found");=0A=
 +		close(fd);=0A=
 +		return (EINVAL);=0A=
 +	}=0A=
 +=0A=
 +	if (1 =3D=3D ac) {=0A=
 +		for (i =3D 0; i < info.count; i++) {=0A=
 +			error =3D foreign_show_cfg(fd,=0A=
 +				MFI_DCMD_CFG_FOREIGN_PREVIEW, i);=0A=
 +			if(0 !=3D error) {=0A=
 +				close(fd);=0A=
 +				return (error);=0A=
 +			}=0A=
 +			if (i < info.count - 1)=0A=
 +				printf("\n");=0A=
 +		}=0A=
 +	} else if (2 =3D=3D ac) {=0A=
 +		error =3D foreign_show_cfg(fd,=0A=
 +			MFI_DCMD_CFG_FOREIGN_PREVIEW, atoi(av[1]));=0A=
 +		if (0 !=3D error) {=0A=
 +			close(fd);=0A=
 +			return (error);=0A=
 +		}=0A=
 +	}=0A=
 +	=0A=
 +	close(fd);=0A=
 +	return (0);=0A=
 +}=0A=
 +MFI_COMMAND(foreign, preview, foreign_preview);=0A=
 +=0A=
 +static int=0A=
 +foreign_import(int ac, char **av)=0A=
 +{=0A=
 +	struct mfi_foreign_scan_info info;=0A=
 +	int ch, error, fd;=0A=
 +	uint8_t cfgidx;=0A=
 +	uint8_t mbox[4];=0A=
 +=0A=
 +	if (2 < ac) {=0A=
 +		warnx("foreign preview: extra arguments");=0A=
 +                return (EINVAL);=0A=
 +	}=0A=
 +=0A=
 +	fd =3D mfi_open(mfi_unit, O_RDWR);=0A=
 +	if (fd < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("mfi_open");=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_SCAN, &info,=0A=
 +	    sizeof(info), NULL, 0, NULL) < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to scan foreign configuration");=0A=
 +		close(fd);=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (0 =3D=3D info.count) {=0A=
 +		warnx("foreign import: no foreign configs found");=0A=
 +		close(fd);=0A=
 +		return (EINVAL);=0A=
 +	}=0A=
 +=0A=
 +	if (1 =3D=3D ac) {=0A=
 +		cfgidx =3D 0xff;=0A=
 +		printf("Are you sure you wish to import ALL foreign "=0A=
 +		       "configurations on mfi%u? [y/N] ", mfi_unit);=0A=
 +	} else {=0A=
 +		/*=0A=
 +		 * While this is docmmented for MegaCli this failed with=0A=
 +		 * exit code 0x03 on the test controller which was a Supermicro=0A=
 +		 * SMC2108 with firmware 12.12.0-0095 which is a LSI 2108 based=0A=
 +		 * controller.=0A=
 +		 */=0A=
 +		cfgidx =3D atoi(av[1]);=0A=
 +		if (cfgidx >=3D info.count) {=0A=
 +			warnx("Invalid foreign config %d specified max is %d",=0A=
 +			      cfgidx, info.count - 1);=0A=
 +			close(fd);=0A=
 +			return (EINVAL);=0A=
 +		}=0A=
 +		printf("Are you sure you wish to import the foreign "=0A=
 +		       "configuration %d on mfi%u? [y/N] ", cfgidx, mfi_unit);=0A=
 +	}=0A=
 +=0A=
 +	ch =3D getchar();=0A=
 +	if (ch !=3D 'y' && ch !=3D 'Y') {=0A=
 +		printf("\nAborting\n");=0A=
 +		close(fd);=0A=
 +		return (0);=0A=
 +	}=0A=
 +=0A=
 +	bzero(mbox, sizeof(mbox));=0A=
 +	mbox[0] =3D cfgidx;=0A=
 +	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_FOREIGN_IMPORT, NULL, 0, mbox,=0A=
 +	    sizeof(mbox), NULL) < 0) {=0A=
 +		error =3D errno;=0A=
 +		warn("Failed to import foreign configuration");=0A=
 +		close(fd);=0A=
 +		return (error);=0A=
 +	}=0A=
 +=0A=
 +	if (1 =3D=3D ac)=0A=
 +		printf("mfi%d: All foreign configurations imported\n",=0A=
 +		       mfi_unit);=0A=
 +	else=0A=
 +		printf("mfi%d: Foreign configuration %d imported\n", mfi_unit,=0A=
 +		       cfgidx);=0A=
 +	close(fd);=0A=
 +	return (0);=0A=
 +}=0A=
 +MFI_COMMAND(foreign, import, foreign_import);=0A=
 --- usr.sbin/mfiutil/mfiutil.8.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ usr.sbin/mfiutil/mfiutil.8	2012-09-26 11:59:05.298961617 +0000=0A=
 @@ -140,6 +140,24 @@=0A=
  .Cm patrol Ar command Op Ar interval Op Ar start=0A=
  .Nm=0A=
  .Op Fl u Ar unit=0A=
 +.Cm foreign scan=0A=
 +.Nm=0A=
 +.Op Fl u Ar unit=0A=
 +.Cm foreign drives=0A=
 +.Nm=0A=
 +.Op Fl u Ar unit=0A=
 +.Cm foreign clear Op Ar config=0A=
 +.Nm=0A=
 +.Op Fl u Ar unit=0A=
 +.Cm foreign display Op Ar config=0A=
 +.Nm=0A=
 +.Op Fl u Ar unit=0A=
 +.Cm foreign preview Op Ar config=0A=
 +.Nm=0A=
 +.Op Fl u Ar unit=0A=
 +.Cm foreign import Op Ar config=0A=
 +.Nm=0A=
 +.Op Fl u Ar unit=0A=
  .Cm flash Ar file=0A=
  .Sh DESCRIPTION=0A=
  The=0A=
 @@ -561,6 +579,37 @@=0A=
  Start a patrol read operation.=0A=
  .It Cm stop patrol=0A=
  Stop a currently running patrol read operation.=0A=
 +.It Cm foreign scan=0A=
 +Scan for foreign configurations and display the number found. The=0A=
 +.Ar config=0A=
 +argument for the commands below takes the form of a number from 0 to =
 the total=0A=
 +configurations found.=0A=
 +.It Cm foreign drives=0A=
 +Scan for drives flagged as foreign and display them.=0A=
 +.It Cm foreign clear Op config=0A=
 +Clear the specifed foreign=0A=
 +.Ar config=0A=
 +or all if no=0A=
 +.Ar config=0A=
 +argument is provided.=0A=
 +.It Cm foreign display Op config=0A=
 +Display the specifed foreign=0A=
 +.Ar config=0A=
 +or all if no=0A=
 +.Ar config=0A=
 +argument is provided.=0A=
 +.It Cm foreign preview Op config=0A=
 +Preview the specifed foreign=0A=
 +.Ar config=0A=
 +after import or all if no=0A=
 +.Ar config=0A=
 +argument is provided.=0A=
 +.It Cm foreign import Op config=0A=
 +Import the specifed foreign=0A=
 +.Ar config=0A=
 +or all if no=0A=
 +.Ar config=0A=
 +argument is provided.=0A=
  .It Cm flash Ar file=0A=
  Updates the flash on the controller with the firmware stored in=0A=
  .Ar file .=0A=
 --- sys/dev/mfi/mfi.c.orig	2012-03-03 06:15:13.000000000 +0000=0A=
 +++ sys/dev/mfi/mfi.c	2012-09-26 01:40:03.283617692 +0000=0A=
 @@ -133,6 +133,11 @@=0A=
  SYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds,=0A=
  	   0, "Max commands");=0A=
  =0A=
 +static int	mfi_cmd_timeout =3D MFI_CMD_TIMEOUT;=0A=
 +TUNABLE_INT("hw.mfi.cmd_timeout", &mfi_cmd_timeout);=0A=
 +SYSCTL_INT(_hw_mfi, OID_AUTO, cmd_timeout, CTLFLAG_RW, &mfi_cmd_timeout,=0A=
 +	   0, "Command timeout (in seconds)");=0A=
 +=0A=
  /* Management interface */=0A=
  static d_open_t		mfi_open;=0A=
  static d_close_t	mfi_close;=0A=
 @@ -535,7 +540,7 @@=0A=
  =0A=
  	/* Start the timeout watchdog */=0A=
  	callout_init(&sc->mfi_watchdog_callout, CALLOUT_MPSAFE);=0A=
 -	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,=0A=
 +	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,=0A=
  	    mfi_timeout, sc);=0A=
  =0A=
  	return (0);=0A=
 @@ -655,6 +661,7 @@=0A=
  	cm->cm_data =3D buf;=0A=
  	cm->cm_private =3D buf;=0A=
  	cm->cm_len =3D bufsize;=0A=
 +	MFI_PRINT_CMD(cm);=0A=
  =0A=
  	*cmp =3D cm;=0A=
  	if ((bufp !=3D NULL) && (*bufp =3D=3D NULL) && (buf !=3D NULL))=0A=
 @@ -1778,6 +1786,7 @@=0A=
  	struct mfi_disk *ld, *ld2;=0A=
  	int error;=0A=
  =0A=
 +	MFI_PRINT_CMD(cm);=0A=
  	mtx_assert(&sc->mfi_io_lock, MA_OWNED);=0A=
  	error =3D 0;=0A=
  	switch (cm->cm_frame->dcmd.opcode) {=0A=
 @@ -1817,6 +1826,7 @@=0A=
  {=0A=
  	struct mfi_disk *ld, *ldn;=0A=
  =0A=
 +	MFI_PRINT_CMD(cm);=0A=
  	switch (cm->cm_frame->dcmd.opcode) {=0A=
  	case MFI_DCMD_LD_DELETE:=0A=
  		TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {=0A=
 @@ -1848,10 +1858,9 @@=0A=
  		}=0A=
  		break;=0A=
  	case MFI_DCMD_CFG_ADD:=0A=
 -		mfi_ldprobe(sc);=0A=
 -		break;=0A=
  	case MFI_DCMD_CFG_FOREIGN_IMPORT:=0A=
 -		mfi_ldprobe(sc);=0A=
 +		if (cm->cm_frame->header.cmd_status =3D=3D MFI_STAT_OK)=0A=
 +			mfi_ldprobe(sc);=0A=
  		break;=0A=
  	}=0A=
  }=0A=
 @@ -2509,7 +2518,7 @@=0A=
  			break;=0A=
  		device_printf(sc->mfi_dev, "Dumping\n\n");=0A=
  		timedout =3D 0;=0A=
 -		deadline =3D time_uptime - MFI_CMD_TIMEOUT;=0A=
 +		deadline =3D time_uptime - mfi_cmd_timeout;=0A=
  		mtx_lock(&sc->mfi_io_lock);=0A=
  		TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {=0A=
  			if (cm->cm_timestamp < deadline) {=0A=
 @@ -2540,10 +2549,11 @@=0A=
  	time_t deadline;=0A=
  	int timedout =3D 0;=0A=
  =0A=
 -	deadline =3D time_uptime - MFI_CMD_TIMEOUT;=0A=
 +	deadline =3D time_uptime - mfi_cmd_timeout;=0A=
 	if (sc->adpreset =3D=3D 0) {=0A=
 		if (!mfi_tbolt_reset(sc)) {=0A=
 -			callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, =
 mfi_timeout, sc);=0A=
 +			callout_reset(&sc->mfi_watchdog_callout,=0A=
 +			    mfi_cmd_timeout * hz, mfi_timeout, sc);=0A=
 			return;=0A=
 		}=0A=
 	}=0A=
 @@ -2562,7 +2571,7 @@=0A=
  =0A=
  	mtx_unlock(&sc->mfi_io_lock);=0A=
  =0A=
 -	callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz,=0A=
 +	callout_reset(&sc->mfi_watchdog_callout, mfi_cmd_timeout * hz,=0A=
  	    mfi_timeout, sc);=0A=
  =0A=
  	if (0)=0A=
 
 ------=_NextPart_000_02D4_01CDB829.0CDC8180--
 
Responsible-Changed-From-To: freebsd-bugs->smh 
Responsible-Changed-By: smh 
Responsible-Changed-When: Thu Dec 13 22:08:48 UTC 2012 
Responsible-Changed-Why:  
I'll take it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=172091 
Responsible-Changed-From-To: smh->sbruno 
Responsible-Changed-By: sbruno 
Responsible-Changed-When: Sat Jun 8 02:34:00 UTC 2013 
Responsible-Changed-Why:  
Assignement to me for resolution 

http://www.freebsd.org/cgi/query-pr.cgi?pr=172091 
State-Changed-From-To: open->closed 
State-Changed-By: sbruno 
State-Changed-When: Sat Jun 8 02:57:33 UTC 2013 
State-Changed-Why:  
Patched and tested in head 

http://www.freebsd.org/cgi/query-pr.cgi?pr=172091 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/172091: commit references a PR
Date: Sat,  8 Jun 2013 02:55:09 +0000 (UTC)

 Author: sbruno
 Date: Sat Jun  8 02:54:59 2013
 New Revision: 251516
 URL: http://svnweb.freebsd.org/changeset/base/251516
 
 Log:
   Implement foreign volume handling.  Allows admins to view foreign metadata
   and clear or import it for use.
   
   PR:     kern/172091
   Submitted by:   smh@freebsd.org
   Reviewed by:    jhb@freebsd.org
   MFC after:      2 weeks
 
 Added:
   head/usr.sbin/mfiutil/mfi_foreign.c   (contents, props changed)
 Modified:
   head/sys/dev/mfi/mfireg.h
   head/usr.sbin/mfiutil/Makefile
   head/usr.sbin/mfiutil/mfi_config.c
   head/usr.sbin/mfiutil/mfi_show.c
   head/usr.sbin/mfiutil/mfiutil.8
   head/usr.sbin/mfiutil/mfiutil.c
   head/usr.sbin/mfiutil/mfiutil.h
 
 Modified: head/sys/dev/mfi/mfireg.h
 ==============================================================================
 --- head/sys/dev/mfi/mfireg.h	Fri Jun  7 22:35:58 2013	(r251515)
 +++ head/sys/dev/mfi/mfireg.h	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -230,7 +230,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,
 
 Modified: head/usr.sbin/mfiutil/Makefile
 ==============================================================================
 --- head/usr.sbin/mfiutil/Makefile	Fri Jun  7 22:35:58 2013	(r251515)
 +++ head/usr.sbin/mfiutil/Makefile	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -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
 
 Modified: head/usr.sbin/mfiutil/mfi_config.c
 ==============================================================================
 --- head/usr.sbin/mfiutil/mfi_config.c	Fri Jun  7 22:35:58 2013	(r251515)
 +++ head/usr.sbin/mfiutil/mfi_config.c	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -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 
  			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_da
  	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_da
  	}
  }
  
 +#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);
  
 
 Added: head/usr.sbin/mfiutil/mfi_foreign.c
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/usr.sbin/mfiutil/mfi_foreign.c	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -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);
 
 Modified: head/usr.sbin/mfiutil/mfi_show.c
 ==============================================================================
 --- head/usr.sbin/mfiutil/mfi_show.c	Fri Jun  7 22:35:58 2013	(r251515)
 +++ head/usr.sbin/mfiutil/mfi_show.c	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -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 s
  		    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);
 
 Modified: head/usr.sbin/mfiutil/mfiutil.8
 ==============================================================================
 --- head/usr.sbin/mfiutil/mfiutil.8	Fri Jun  7 22:35:58 2013	(r251515)
 +++ head/usr.sbin/mfiutil/mfiutil.8	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -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
 @@ -140,6 +143,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 +339,8 @@ The entry in the event log corresponding
  .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
 @@ -567,6 +587,35 @@ Enable manual patrol reads that are only
  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 .
 @@ -634,6 +683,10 @@ Configure the adapter to run periodic pa
  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
 
 Modified: head/usr.sbin/mfiutil/mfiutil.c
 ==============================================================================
 --- head/usr.sbin/mfiutil/mfiutil.c	Fri Jun  7 22:35:58 2013	(r251515)
 +++ head/usr.sbin/mfiutil/mfiutil.c	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -60,6 +60,7 @@ 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");
 @@ -83,6 +84,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");
 
 Modified: head/usr.sbin/mfiutil/mfiutil.h
 ==============================================================================
 --- head/usr.sbin/mfiutil/mfiutil.h	Fri Jun  7 22:35:58 2013	(r251515)
 +++ head/usr.sbin/mfiutil/mfiutil.h	Sat Jun  8 02:54:59 2013	(r251516)
 @@ -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
  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 *,
  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__ */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/172091: commit references a PR
Date: Fri, 12 Jul 2013 02:26:31 +0000 (UTC)

 Author: sbruno
 Date: Fri Jul 12 02:26:15 2013
 New Revision: 253244
 URL: http://svnweb.freebsd.org/changeset/base/253244
 
 Log:
   MFC r251516
   
   Implement foreign device handling.
   
   PR:	kern/172091
 
 Added:
   stable/9/usr.sbin/mfiutil/mfi_foreign.c
      - copied unchanged from r251516, head/usr.sbin/mfiutil/mfi_foreign.c
 Modified:
   stable/9/sys/dev/mfi/mfireg.h
   stable/9/usr.sbin/mfiutil/Makefile
   stable/9/usr.sbin/mfiutil/mfi_config.c
   stable/9/usr.sbin/mfiutil/mfi_show.c
   stable/9/usr.sbin/mfiutil/mfiutil.8
   stable/9/usr.sbin/mfiutil/mfiutil.c
   stable/9/usr.sbin/mfiutil/mfiutil.h
 Directory Properties:
   stable/9/sys/   (props changed)
   stable/9/sys/dev/   (props changed)
   stable/9/usr.sbin/mfiutil/   (props changed)
 
 Modified: stable/9/sys/dev/mfi/mfireg.h
 ==============================================================================
 --- stable/9/sys/dev/mfi/mfireg.h	Fri Jul 12 02:11:42 2013	(r253243)
 +++ stable/9/sys/dev/mfi/mfireg.h	Fri Jul 12 02:26:15 2013	(r253244)
 @@ -230,7 +230,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,
 
 Modified: stable/9/usr.sbin/mfiutil/Makefile
 ==============================================================================
 --- stable/9/usr.sbin/mfiutil/Makefile	Fri Jul 12 02:11:42 2013	(r253243)
 +++ stable/9/usr.sbin/mfiutil/Makefile	Fri Jul 12 02:26:15 2013	(r253244)
 @@ -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
 
 Modified: stable/9/usr.sbin/mfiutil/mfi_config.c
 ==============================================================================
 --- stable/9/usr.sbin/mfiutil/mfi_config.c	Fri Jul 12 02:11:42 2013	(r253243)
 +++ stable/9/usr.sbin/mfiutil/mfi_config.c	Fri Jul 12 02:26:15 2013	(r253244)
 @@ -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 
  			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_da
  	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_da
  	}
  }
  
 +#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);
  
 
 Copied: stable/9/usr.sbin/mfiutil/mfi_foreign.c (from r251516, head/usr.sbin/mfiutil/mfi_foreign.c)
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ stable/9/usr.sbin/mfiutil/mfi_foreign.c	Fri Jul 12 02:26:15 2013	(r253244, copy of r251516, head/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);
 
 Modified: stable/9/usr.sbin/mfiutil/mfi_show.c
 ==============================================================================
 --- stable/9/usr.sbin/mfiutil/mfi_show.c	Fri Jul 12 02:11:42 2013	(r253243)
 +++ stable/9/usr.sbin/mfiutil/mfi_show.c	Fri Jul 12 02:26:15 2013	(r253244)
 @@ -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 s
  		    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;
  	}
 @@ -787,7 +796,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;
 +			
  		}
  	}
  
 @@ -800,3 +809,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);
 
 Modified: stable/9/usr.sbin/mfiutil/mfiutil.8
 ==============================================================================
 --- stable/9/usr.sbin/mfiutil/mfiutil.8	Fri Jul 12 02:11:42 2013	(r253243)
 +++ stable/9/usr.sbin/mfiutil/mfiutil.8	Fri Jul 12 02:26:15 2013	(r253244)
 @@ -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
 @@ -140,6 +143,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 +339,8 @@ The entry in the event log corresponding
  .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
 @@ -567,6 +587,35 @@ Enable manual patrol reads that are only
  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 .
 @@ -635,6 +684,9 @@ 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
 
 Modified: stable/9/usr.sbin/mfiutil/mfiutil.c
 ==============================================================================
 --- stable/9/usr.sbin/mfiutil/mfiutil.c	Fri Jul 12 02:11:42 2013	(r253243)
 +++ stable/9/usr.sbin/mfiutil/mfiutil.c	Fri Jul 12 02:26:15 2013	(r253244)
 @@ -60,6 +60,7 @@ 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");
 @@ -83,6 +84,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");
 
 Modified: stable/9/usr.sbin/mfiutil/mfiutil.h
 ==============================================================================
 --- stable/9/usr.sbin/mfiutil/mfiutil.h	Fri Jul 12 02:11:42 2013	(r253243)
 +++ stable/9/usr.sbin/mfiutil/mfiutil.h	Fri Jul 12 02:26:15 2013	(r253244)
 @@ -123,6 +123,16 @@ struct mfiutil_command {
  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);
 @@ -135,6 +145,8 @@ const char *mfi_pd_inq_string(struct mfi
  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,
 @@ -151,6 +163,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,
 @@ -159,4 +175,5 @@ void	mfi_autolearn_period(uint32_t, char
  void	mfi_next_learn_time(uint32_t, char *, size_t);
  void	mfi_autolearn_mode(uint8_t, char *, size_t);
  
 +int	display_format(int ac, char **av, int diagnostic, mfi_dcmd_t display_cmd);
  #endif /* !__MFIUTIL_H__ */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
