From owner-freebsd-bugs@FreeBSD.ORG Wed Sep 26 12:40:06 2012 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id E64A2106566C for ; Wed, 26 Sep 2012 12:40:06 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id B776A8FC1A for ; Wed, 26 Sep 2012 12:40:06 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q8QCe6e9058639 for ; Wed, 26 Sep 2012 12:40:06 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q8QCe6o3058629; Wed, 26 Sep 2012 12:40:06 GMT (envelope-from gnats) Resent-Date: Wed, 26 Sep 2012 12:40:06 GMT Resent-Message-Id: <201209261240.q8QCe6o3058629@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Steven Hartland Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 2667D106564A for ; 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 ; 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 ; 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 To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: misc/172091: Improvements to mfi support including foreign disks / configs in mfiutil X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 26 Sep 2012 12:40:07 -0000 >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 #include #include -#ifdef DEBUG #include -#endif #include #include #include #include #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 #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 [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 \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 #include +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 +#include +#include +#include +#include +#include +#include +#include +#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: