Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Sep 2012 12:32:52 GMT
From:      Steven Hartland <steven.hartland@multiplay.co.uk>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   misc/172091: Improvements to mfi support including foreign disks / configs in mfiutil
Message-ID:  <201209261232.q8QCWqvT081912@red.freebsd.org>
Resent-Message-ID: <201209261240.q8QCe6o3058629@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         172091
>Category:       misc
>Synopsis:       Improvements to mfi support including foreign disks / configs in mfiutil
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 26 12:40:06 UTC 2012
>Closed-Date:
>Last-Modified:
>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:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209261232.q8QCWqvT081912>