svn commit: r196200 - in head: etc/mtree include sys/dev/mfi usr.sbin usr.sbin/mfiutil

Scott Long scottl at FreeBSD.org
Thu Aug 13 23:18:46 UTC 2009


Author: scottl
Date: Thu Aug 13 23:18:45 2009
New Revision: 196200
URL: http://svn.freebsd.org/changeset/base/196200

Log:
  ntroduce mfiutil, a basic utility for managing LSI SAS-RAID & Dell PERC5/6
  controllers.  Controller, array, and drive status can be checked, basic
  attributes can be changed, and arrays and spares can be created and deleted.
  Controller firmware can also be flashed.
  
  This does not replace MegaCLI, found in ports, as that is officially sanctioned
  and supported by LSI and includes vastly more functionality.  However, mfiutil
  is open source and guaranteed to provide basic functionality, which can be
  especially useful if you have a problem and can't get MegaCLI to work.
  
  Approved by:    re
  Obtained from:  Yahoo! Inc.

Added:
  head/usr.sbin/mfiutil/
  head/usr.sbin/mfiutil/Makefile   (contents, props changed)
  head/usr.sbin/mfiutil/README   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_cmd.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_config.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_drive.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_evt.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_flash.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_patrol.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_show.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfi_volume.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfiutil.1   (contents, props changed)
  head/usr.sbin/mfiutil/mfiutil.c   (contents, props changed)
  head/usr.sbin/mfiutil/mfiutil.h   (contents, props changed)
Modified:
  head/etc/mtree/BSD.include.dist
  head/include/Makefile
  head/sys/dev/mfi/mfi_ioctl.h
  head/sys/dev/mfi/mfireg.h
  head/usr.sbin/Makefile

Modified: head/etc/mtree/BSD.include.dist
==============================================================================
--- head/etc/mtree/BSD.include.dist	Thu Aug 13 19:47:13 2009	(r196199)
+++ head/etc/mtree/BSD.include.dist	Thu Aug 13 23:18:45 2009	(r196200)
@@ -104,6 +104,8 @@
         ..
         lmc
         ..
+	mfi
+	..
         mpt
             mpilib
             ..

Modified: head/include/Makefile
==============================================================================
--- head/include/Makefile	Thu Aug 13 19:47:13 2009	(r196199)
+++ head/include/Makefile	Thu Aug 13 23:18:45 2009	(r196200)
@@ -40,7 +40,7 @@ LDIRS=	bsm cam geom net net80211 netatal
 
 LSUBDIRS=	cam/ata cam/scsi \
 	dev/acpica dev/an dev/bktr dev/firewire dev/hwpmc \
-	dev/ic dev/iicbus ${_dev_ieee488} dev/lmc dev/ofw \
+	dev/ic dev/iicbus ${_dev_ieee488} dev/lmc dev/mfi dev/ofw \
 	dev/pbio ${_dev_powermac_nvram} dev/ppbus dev/smbus \
 	dev/speaker dev/usb dev/utopia dev/vkbd dev/wi \
 	fs/devfs fs/fdescfs fs/fifofs fs/msdosfs fs/nfs fs/ntfs fs/nullfs \

Modified: head/sys/dev/mfi/mfi_ioctl.h
==============================================================================
--- head/sys/dev/mfi/mfi_ioctl.h	Thu Aug 13 19:47:13 2009	(r196199)
+++ head/sys/dev/mfi/mfi_ioctl.h	Thu Aug 13 23:18:45 2009	(r196200)
@@ -27,6 +27,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <dev/mfi/mfireg.h>
+
 #if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
 struct iovec32 {
 	u_int32_t	iov_base;

Modified: head/sys/dev/mfi/mfireg.h
==============================================================================
--- head/sys/dev/mfi/mfireg.h	Thu Aug 13 19:47:13 2009	(r196199)
+++ head/sys/dev/mfi/mfireg.h	Thu Aug 13 23:18:45 2009	(r196200)
@@ -89,7 +89,7 @@ __FBSDID("$FreeBSD$");
 #define MFI_ODCR0	0xa0 		/* outbound doorbell clear register0  */
 #define MFI_OSP0	0xb0 		/* outbound scratch pad0  */
 #define MFI_1078_EIM	0x80000004 	/* 1078 enable intrrupt mask  */
-#define MFI_RMI		0x2 		/* reply message interrupt  */
+#define MFI_RMI		0x2 		/* reply message interrupt  */       
 #define MFI_1078_RM	0x80000000 	/* reply 1078 message interrupt  */
 #define MFI_ODC		0x4 		/* outbound doorbell change interrupt */
 
@@ -151,15 +151,41 @@ typedef enum {
 	MFI_DCMD_CTRL_EVENT_GETINFO =	0x01040100,
 	MFI_DCMD_CTRL_EVENT_GET =	0x01040300,
 	MFI_DCMD_CTRL_EVENT_WAIT =	0x01040500,
+	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_FLASH_FW_OPEN =	0x010f0100,
+	MFI_DCMD_FLASH_FW_DOWNLOAD =	0x010f0200,
+	MFI_DCMD_FLASH_FW_FLASH =	0x010f0300,
+	MFI_DCMD_FLASH_FW_CLOSE =	0x010f0400,
+	MFI_DCMD_PD_GET_LIST =		0x02010000,
+	MFI_DCMD_PD_GET_INFO = 		0x02020000,
+	MFI_DCMD_PD_STATE_SET =		0x02030100,
+	MFI_DCMD_PD_REBUILD_START =	0x02040100,
+	MFI_DCMD_PD_REBUILD_ABORT =	0x02040200,
+	MFI_DCMD_PD_CLEAR_START =	0x02050100,
+	MFI_DCMD_PD_CLEAR_ABORT =	0x02050200,
+	MFI_DCMD_PD_GET_PROGRESS =	0x02060000,
+	MFI_DCMD_PD_LOCATE_START =	0x02070100,
+	MFI_DCMD_PD_LOCATE_STOP =	0x02070200,
 	MFI_DCMD_LD_GET_LIST =		0x03010000,
 	MFI_DCMD_LD_GET_INFO =		0x03020000,
 	MFI_DCMD_LD_GET_PROP =		0x03030000,
 	MFI_DCMD_LD_SET_PROP =		0x03040000,
+	MFI_DCMD_LD_INIT_START =	0x03060100,
 	MFI_DCMD_LD_DELETE =		0x03090000,
 	MFI_DCMD_CFG_READ =		0x04010000,
 	MFI_DCMD_CFG_ADD =		0x04020000,
 	MFI_DCMD_CFG_CLEAR =		0x04030000,
+	MFI_DCMD_CFG_MAKE_SPARE =	0x04040000,
+	MFI_DCMD_CFG_REMOVE_SPARE =	0x04050000,	
 	MFI_DCMD_CFG_FOREIGN_IMPORT =	0x04060400,
+	MFI_DCMD_BBU_GET_STATUS =	0x05010000,
+	MFI_DCMD_BBU_GET_CAPACITY_INFO =0x05020000,
+	MFI_DCMD_BBU_GET_DESIGN_INFO =	0x05030000,
 	MFI_DCMD_CLUSTER =		0x08000000,
 	MFI_DCMD_CLUSTER_RESET_ALL =	0x08010100,
 	MFI_DCMD_CLUSTER_RESET_LD =	0x08010200
@@ -245,6 +271,9 @@ typedef enum {
 	MFI_STAT_RESERVATION_IN_PROGRESS,
 	MFI_STAT_I2C_ERRORS_DETECTED,
 	MFI_STAT_PCI_ERRORS_DETECTED,
+	MFI_STAT_DIAG_FAILED,
+	MFI_STAT_BOOT_MSG_PENDING,
+	MFI_STAT_FOREIGN_CONFIG_INCOMPLETE,
 	MFI_STAT_INVALID_STATUS =	0xFF
 } mfi_status_t;
 
@@ -303,6 +332,17 @@ typedef enum {
 	MR_LD_CACHE_ALLOW_WRITE_CACHE =	0x20,
 	MR_LD_CACHE_ALLOW_READ_CACHE =	0x40
 } mfi_ld_cache;
+#define	MR_LD_CACHE_MASK	0x7f
+
+#define	MR_LD_CACHE_POLICY_READ_AHEAD_NONE		0
+#define	MR_LD_CACHE_POLICY_READ_AHEAD_ALWAYS		MR_LD_CACHE_READ_AHEAD
+#define	MR_LD_CACHE_POLICY_READ_AHEAD_ADAPTIVE		\
+	(MR_LD_CACHE_READ_AHEAD | MR_LD_CACHE_READ_ADAPTIVE)
+#define	MR_LD_CACHE_POLICY_WRITE_THROUGH		0
+#define	MR_LD_CACHE_POLICY_WRITE_BACK			MR_LD_CACHE_WRITE_BACK
+#define	MR_LD_CACHE_POLICY_IO_CACHED			\
+	(MR_LD_CACHE_ALLOW_WRITE_CACHE | MR_LD_CACHE_ALLOW_READ_CACHE)
+#define	MR_LD_CACHE_POLICY_IO_DIRECT			0
 
 typedef enum {
 	MR_PD_CACHE_UNCHANGED  =	0,
@@ -320,6 +360,7 @@ typedef enum {
 #define MFI_DEFAULT_ID		-1
 #define MFI_MAX_LUN		8
 #define MFI_MAX_LD		64
+#define	MFI_MAX_PD		256
 
 #define MFI_FRAME_SIZE		64
 #define MFI_MBOX_SIZE		12
@@ -866,12 +907,10 @@ union mfi_pd_ddf_type {
 } __packed;
 
 struct mfi_pd_progress {
-	struct {
-		uint32_t		rbld	: 1;
-		uint32_t		patrol	: 1;
-		uint32_t		clear	: 1;
-		uint32_t		reserved: 29;
-	} active;
+	uint32_t			active;
+#define	MFI_PD_PROGRESS_REBUILD	(1<<0)
+#define	MFI_PD_PROGRESS_PATROL	(1<<1)
+#define	MFI_PD_PROGRESS_CLEAR	(1<<2)
 	struct mfi_progress		rbld;
 	struct mfi_progress		patrol;
 	struct mfi_progress		clear;
@@ -890,8 +929,8 @@ struct mfi_pd_info {
 	uint32_t			other_err_count;
 	uint32_t			pred_fail_count;
 	uint32_t			last_pred_fail_event_seq_num;
-	uint16_t			fw_state;
-	uint8_t				disable_for_removal;
+	uint16_t			fw_state;	/* MFI_PD_STATE_* */
+	uint8_t				disabled_for_removal;
 	uint8_t				link_speed;
 	union mfi_pd_ddf_type		state;
 	struct {
@@ -918,7 +957,7 @@ struct mfi_pd_address {
 	uint16_t		encl_device_id;
 	uint8_t			encl_index;
 	uint8_t			slot_number;
-	uint8_t			scsi_dev_type;
+	uint8_t			scsi_dev_type;	/* 0 = disk */
 	uint8_t			connect_port_bitmap;
 	uint64_t		sas_addr[2];
 } __packed;
@@ -926,12 +965,19 @@ struct mfi_pd_address {
 struct mfi_pd_list {
 	uint32_t		size;
 	uint32_t		count;
-	uint8_t			data;
-	/*
-	struct mfi_pd_address	addr[];
-	*/
+	struct mfi_pd_address	addr[0];
 } __packed;
 
+enum mfi_pd_state {
+	MFI_PD_STATE_UNCONFIGURED_GOOD = 0x00,
+	MFI_PD_STATE_UNCONFIGURED_BAD = 0x01,
+	MFI_PD_STATE_HOT_SPARE = 0x02,
+	MFI_PD_STATE_OFFLINE = 0x10,
+	MFI_PD_STATE_FAILED = 0x11,
+	MFI_PD_STATE_REBUILD = 0x14,
+	MFI_PD_STATE_ONLINE = 0x18
+};
+
 union mfi_ld_ref {
 	struct {
 		uint8_t		target_id;
@@ -986,6 +1032,9 @@ struct mfi_ld_params {
 	uint8_t			span_depth;
 	uint8_t			state;
 	uint8_t			init_state;
+#define	MFI_LD_PARAMS_INIT_NO		0
+#define	MFI_LD_PARAMS_INIT_QUICK	1
+#define	MFI_LD_PARAMS_INIT_FULL		2
 	uint8_t			is_consistent;
 	uint8_t			reserved[23];
 } __packed;
@@ -995,7 +1044,7 @@ struct mfi_ld_progress {
 #define	MFI_LD_PROGRESS_CC	(1<<0)
 #define	MFI_LD_PROGRESS_BGI	(1<<1)
 #define	MFI_LD_PROGRESS_FGI	(1<<2)
-#define	MFI_LD_PORGRESS_RECON	(1<<3)
+#define	MFI_LD_PROGRESS_RECON	(1<<3)
 	struct mfi_progress	cc;
 	struct mfi_progress	bgi;
 	struct mfi_progress	fgi;
@@ -1028,26 +1077,18 @@ struct mfi_ld_info {
 	uint8_t			reserved2[16];
 } __packed;
 
-union mfi_spare_type {
-	struct {
-		uint8_t		is_dedicate		:1;
-		uint8_t		is_revertable		:1;
-		uint8_t		is_encl_affinity	:1;
-		uint8_t		reserved		:5;
-	} v;
-	uint8_t		type;
-} __packed;
-
 #define MAX_ARRAYS 16
 struct mfi_spare {
 	union mfi_pd_ref	ref;
-	union mfi_spare_type	spare_type;
+	uint8_t			spare_type;
+#define	MFI_SPARE_DEDICATED	(1 << 0)
+#define	MFI_SPARE_REVERTIBLE	(1 << 1)
+#define	MFI_SPARE_ENCL_AFFINITY	(1 << 2)
 	uint8_t			reserved[2];
 	uint8_t			array_count;
-	uint16_t		array_refd[MAX_ARRAYS];
+	uint16_t		array_ref[MAX_ARRAYS];
 } __packed;
 
-#define MAX_ROW_SIZE 32
 struct mfi_array {
 	uint64_t			size;
 	uint8_t				num_drives;
@@ -1055,13 +1096,13 @@ struct mfi_array {
 	uint16_t			array_ref;
 	uint8_t				pad[20];
 	struct {
-		union mfi_pd_ref	ref;
-		uint16_t		fw_state;
+		union mfi_pd_ref	ref;	/* 0xffff == missing drive */
+		uint16_t		fw_state;	/* MFI_PD_STATE_* */
 		struct {
 			uint8_t		pd;
 			uint8_t		slot;
 		} encl;
-	} pd[MAX_ROW_SIZE];
+	} pd[0];
 } __packed;
 
 struct mfi_config_data {
@@ -1073,13 +1114,117 @@ struct mfi_config_data {
 	uint16_t		spares_count;
 	uint16_t		spares_size;
 	uint8_t			reserved[16];
-	uint8_t			data;
-	/*
-	struct mfi_array	array[];
-	struct mfi_ld_config	ld[];
-	struct mfi_spare	spare[];
-	*/
-} __packed;
+	struct mfi_array	array[0];
+	struct mfi_ld_config	ld[0];
+	struct mfi_spare	spare[0];
+} __packed;
+
+struct mfi_bbu_capacity_info {
+	uint16_t		relative_charge;
+	uint16_t		absolute_charge;
+	uint16_t		remaining_capacity;
+	uint16_t		full_charge_capacity;
+	uint16_t		run_time_to_empty;
+	uint16_t		average_time_to_empty;
+	uint16_t		average_time_to_full;
+	uint16_t		cycle_count;
+	uint16_t		max_error;
+	uint16_t		remaining_capacity_alarm;
+	uint16_t		remaining_time_alarm;
+	uint8_t			reserved[26];
+} __packed;
+
+struct mfi_bbu_design_info {
+	uint32_t		mfg_date;
+	uint16_t		design_capacity;
+	uint16_t		design_voltage;
+	uint16_t		spec_info;
+	uint16_t		serial_number;
+	uint16_t		pack_stat_config;
+	uint8_t			mfg_name[12];
+	uint8_t			device_name[8];
+	uint8_t			device_chemistry[8];
+	uint8_t			mfg_data[8];
+	uint8_t			reserved[17];
+} __packed;
+
+struct mfi_ibbu_state {
+	uint16_t		gas_guage_status;
+	uint16_t		relative_charge;
+	uint16_t		charger_system_state;
+	uint16_t		charger_system_ctrl;
+	uint16_t		charging_current;
+	uint16_t		absolute_charge;
+	uint16_t		max_error;
+	uint8_t			reserved[18];
+} __packed;
+
+struct mfi_bbu_state {
+	uint16_t		gas_guage_status;
+	uint16_t		relative_charge;
+	uint16_t		charger_status;
+	uint16_t		remaining_capacity;
+	uint16_t		full_charge_capacity;
+	uint8_t			is_SOH_good;
+	uint8_t			reserved[21];
+} __packed;
+
+union mfi_bbu_status_detail {
+	struct mfi_ibbu_state	ibbu;
+	struct mfi_bbu_state	bbu;
+};
+
+struct mfi_bbu_status {
+	uint8_t			battery_type;
+#define	MFI_BBU_TYPE_NONE	0
+#define	MFI_BBU_TYPE_IBBU	1
+#define	MFI_BBU_TYPE_BBU	2	
+	uint8_t			reserved;
+	uint16_t		voltage;
+	int16_t			current;
+	uint16_t		temperature;
+	uint32_t		fw_status;
+#define	MFI_BBU_STATE_PACK_MISSING	(1 << 0)
+#define	MFI_BBU_STATE_VOLTAGE_LOW	(1 << 1)
+#define	MFI_BBU_STATE_TEMPERATURE_HIGH	(1 << 2)
+#define	MFI_BBU_STATE_CHARGE_ACTIVE	(1 << 0)
+#define	MFI_BBU_STATE_DISCHARGE_ACTIVE	(1 << 0)
+	uint8_t			pad[20];
+	union mfi_bbu_status_detail detail;
+} __packed;
+
+enum mfi_pr_state {
+	MFI_PR_STATE_STOPPED = 0,
+	MFI_PR_STATE_READY = 1,
+	MFI_PR_STATE_ACTIVE = 2,
+	MFI_PR_STATE_ABORTED = 0xff
+};
+
+struct mfi_pr_status {
+	uint32_t		num_iteration;
+	uint8_t			state;
+	uint8_t			num_pd_done;
+	uint8_t			reserved[10];
+};
+
+enum mfi_pr_opmode {
+	MFI_PR_OPMODE_AUTO = 0,
+	MFI_PR_OPMODE_MANUAL = 1,
+	MFI_PR_OPMODE_DISABLED = 2
+};
+
+struct mfi_pr_properties {
+	uint8_t			op_mode;
+	uint8_t			max_pd;
+	uint8_t			reserved;
+	uint8_t			exclude_ld_count;
+	uint16_t		excluded_ld[MFI_MAX_LD];
+	uint8_t			cur_pd_map[MFI_MAX_PD / 8];
+	uint8_t			last_pd_map[MFI_MAX_PD / 8];
+	uint32_t		next_exec;
+	uint32_t		exec_freq;
+	uint32_t		clear_freq;
+};
 
 #define MFI_SCSI_MAX_TARGETS	128
 #define MFI_SCSI_MAX_LUNS	8

Modified: head/usr.sbin/Makefile
==============================================================================
--- head/usr.sbin/Makefile	Thu Aug 13 19:47:13 2009	(r196199)
+++ head/usr.sbin/Makefile	Thu Aug 13 23:18:45 2009	(r196200)
@@ -94,6 +94,7 @@ SUBDIR=	${_ac} \
 	manctl \
 	memcontrol \
 	mergemaster \
+	mfiutil \
 	mixer \
 	${_mld6query} \
 	mlxcontrol \

Added: head/usr.sbin/mfiutil/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/mfiutil/Makefile	Thu Aug 13 23:18:45 2009	(r196200)
@@ -0,0 +1,17 @@
+# $FreeBSD$
+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
+
+CFLAGS+= -fno-builtin-strftime
+WARNS?=3
+
+LDADD=	-lutil
+
+# Here be dragons
+.ifdef DEBUG
+CFLAGS+= -DDEBUG
+.endif
+
+.include <bsd.prog.mk>

Added: head/usr.sbin/mfiutil/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/mfiutil/README	Thu Aug 13 23:18:45 2009	(r196200)
@@ -0,0 +1,104 @@
+# $FreeBSD$
+
+This package includes a mfiutil command for administering mfi(4) controllers
+on FreeBSD.
+
+Version 1.0.13
+	* Cleaned up warnings in preparation for integration with FreeBSD
+
+Version 1.0.12
+	* Add 'drive clear' command to wipe drives with all 0x00 characters
+
+Version 1.0.11
+	* Display serial number for drives
+	* Display location info for drives with 'show config'
+
+Version 1.0.10
+	* Display min and max stripe size supported by adapters.
+	* Added support for examining the controller event log.
+
+Version 1.0.9
+	* Display stripe size for volumes.
+	* Added support for setting the stripe size for new volumes.
+	* Fix a regression in 1.0.8 that broke creation of RAID-5 and RAID-50
+	  arrays.
+
+Version 1.0.8
+	* Added support for RAID-60 arrays.
+	* Added 'flash' command to support firmware flashing.
+
+Version 1.0.7
+	* Renamed 'clear config' to 'clear, 'create volume' to 'create',
+	  'delete volume' to 'delete', 'create spare' to 'add', and
+	  'delete spare' to 'remove'.  The old names still work.
+	* Added support for RAID-6 arrays.
+
+Version 1.0.6
+	* Added 'show patrol', 'patrol', 'start patrol', and 'stop patrol'
+	  commands to manage patrol reads.
+
+Version 1.0.5
+	* Added 'create volume' and 'delete volume' commands to manage volumes.
+	* Added 'clear config' command to clear entire configuration.
+	* Added more detailed error reporting based on firmware status codes.
+	* Renamed 'progress' command to 'drive progress'.
+	* Added 'volume progress' command to display progress of volume-level
+	  activites such as background inits.
+	* Fixed 'create spare' to properly add global spares.
+
+Version 1.0.4
+	* Added 'create spare' and 'delete spare' commands to manage hot spares.
+	* Added 'good' command to mark unconfigured bad drives as good.
+	* Display more information about hot spares in 'show config'
+	* Allow physical drives to be specified via Exx:Syy similar to megacli
+	* Display onboard memory size in 'show adapter'
+
+Version 1.0.3
+	* Added 'cache' command to manage cache settings for volumes.
+	* Added 'name' command to name volumes.
+	* Added manpage.
+
+Version 1.0.2
+	* Added 'show adapter' and 'show battery' commands.
+	* Added RAID level of volumes to 'show config' and 'show volumes'.
+	* Added drive model info to 'show config' and 'show drives'.
+	* Added package firmware version to 'show firmware'.
+	* Added read and write cache status to 'show volumes'.
+	* Map volume IDs to mfidX device names on newer kernels.
+
+Version 1.0.1
+	* Added 'show firmware' command
+
+Version 1.0.0
+	* Initial release
+
+usage: mfiutil [-u unit] <command> ...
+
+Commands include:
+    version
+    show adapter              - display controller information
+    show battery              - display battery information
+    show config               - display RAID configuration
+    show drives               - list physical drives
+    show firmware             - list firmware images
+    show volumes              - list logical volumes
+    show patrol               - display patrol read status
+    fail <drive>              - fail a physical drive
+    good <drive>              - mark a bad physical drive as good
+    rebuild <drive>           - mark failed drive ready for rebuild
+    drive progress <drive>    - display status of active operations
+    start rebuild <drive>
+    abort rebuild <drive>
+    locate <drive> <on|off>   - toggle drive LED
+    cache <volume> [command [setting]]
+    name <volume> <name>
+    volume progress <volume>  - display status of active operations
+    clear                     - clear volume configuration
+    create <type> [-v] <drive>[,<drive>[,...]] [<drive>[,<drive>[,...]]
+    delete <volume>
+    add <drive> [volume]      - add a hot spare
+    remove <drive>            - remove a hot spare
+    patrol <disable|auto|manual> [interval [start]]
+    start patrol              - start a patrol read
+    stop patrol               - stop a patrol read
+    flash <firmware>

Added: head/usr.sbin/mfiutil/mfi_cmd.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/mfiutil/mfi_cmd.c	Thu Aug 13 23:18:45 2009	(r196200)
@@ -0,0 +1,351 @@
+/*-
+ * 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/errno.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mfiutil.h"
+#include <dev/mfi/mfi_ioctl.h>
+
+static const char *mfi_status_codes[] = {
+	"Command completed succesfully",
+	"Invalid command",
+	"Invalid DMCD opcode",
+	"Invalid parameter",
+	"Invalid Sequence Number",
+	"Abort isn't possible for the requested command",
+	"Application 'host' code not found",
+	"Application in use",
+	"Application not initialized",
+	"Array index invalid",
+	"Array row not empty",
+	"Configuration resource conflict",
+	"Device not found",
+	"Drive too small",
+	"Flash memory allocation failed",
+	"Flash download already in progress",
+	"Flash operation failed",
+	"Bad flash image",
+	"Incomplete flash image",
+	"Flash not open",
+	"Flash not started",
+	"Flush failed",
+	"Specified application doesn't have host-resident code",
+	"Volume consistency check in progress",
+	"Volume initialization in progress",
+	"Volume LBA out of range",
+	"Maximum number of volumes are already configured",
+	"Volume is not OPTIMAL",
+	"Volume rebuild in progress",
+	"Volume reconstruction in progress",
+	"Volume RAID level is wrong for requested operation",
+	"Too many spares assigned",
+	"Scratch memory not available",
+	"Error writing MFC data to SEEPROM",
+	"Required hardware is missing",
+	"Item not found",
+	"Volume drives are not within an enclosure",
+	"Drive clear in progress",
+	"Drive type mismatch (SATA vs SAS)",
+	"Patrol read disabled",
+	"Invalid row index",
+	"SAS Config - Invalid action",
+	"SAS Config - Invalid data",
+	"SAS Config - Invalid page",
+	"SAS Config - Invalid type",
+	"SCSI command completed with error",
+	"SCSI I/O request failed",
+	"SCSI RESERVATION_CONFLICT",
+	"One or more flush operations during shutdown failed",
+	"Firmware time is not set",
+	"Wrong firmware or drive state",
+	"Volume is offline",
+	"Peer controller rejected request",
+	"Unable to inform peer of communication changes",
+	"Volume reservation already in progress",
+	"I2C errors were detected",
+	"PCI errors occurred during XOR/DMA operation",
+	"Diagnostics failed",
+	"Unable to process command as boot messages are pending",
+	"Foreign configuration is incomplete"
+};
+
+const char *
+mfi_status(u_int status_code)
+{
+	static char buffer[16];
+
+	if (status_code == MFI_STAT_INVALID_STATUS)
+		return ("Invalid status");
+	if (status_code < sizeof(mfi_status_codes) / sizeof(char *))
+		return (mfi_status_codes[status_code]);
+	snprintf(buffer, sizeof(buffer), "Status: 0x%02x", status_code);
+	return (buffer);
+}
+
+const char *
+mfi_raid_level(uint8_t primary_level, uint8_t secondary_level)
+{
+	static char buf[16];
+
+	switch (primary_level) {
+	case DDF_RAID0:
+		return ("RAID-0");
+	case DDF_RAID1:
+		if (secondary_level != 0)
+			return ("RAID-10");
+		else
+			return ("RAID-1");
+	case DDF_RAID1E:
+		return ("RAID-1E");
+	case DDF_RAID3:
+		return ("RAID-3");
+	case DDF_RAID5:
+		if (secondary_level != 0)
+			return ("RAID-50");
+		else
+			return ("RAID-5");
+	case DDF_RAID5E:
+		return ("RAID-5E");
+	case DDF_RAID5EE:
+		return ("RAID-5EE");
+	case DDF_RAID6:
+		if (secondary_level != 0)
+			return ("RAID-60");
+		else
+			return ("RAID-6");
+	case DDF_JBOD:
+		return ("JBOD");
+	case DDF_CONCAT:
+		return ("CONCAT");
+	default:
+		sprintf(buf, "LVL 0x%02x", primary_level);
+		return (buf);
+	}
+}
+
+static int
+mfi_query_disk(int fd, uint8_t target_id, struct mfi_query_disk *info)
+{
+
+	bzero(info, sizeof(*info));
+	info->array_id = target_id;
+	if (ioctl(fd, MFIIO_QUERY_DISK, info) < 0)
+		return (-1);
+	if (!info->present) {
+		errno = ENXIO;
+		return (-1);
+	}
+	return (0);
+}
+
+const char *
+mfi_volume_name(int fd, uint8_t target_id)
+{
+	static struct mfi_query_disk info;
+	static char buf[4];
+
+	if (mfi_query_disk(fd, target_id, &info) < 0) {
+		snprintf(buf, sizeof(buf), "%d", target_id);
+		return (buf);
+	}
+	return (info.devname);
+}
+
+int
+mfi_volume_busy(int fd, uint8_t target_id)
+{
+	struct mfi_query_disk info;
+
+	/* Assume it isn't mounted if we can't get information. */
+	if (mfi_query_disk(fd, target_id, &info) < 0)
+		return (0);
+	return (info.open != 0);
+}
+
+/*
+ * Check if the running kernel supports changing the RAID
+ * configuration of the mfi controller.
+ */
+int
+mfi_reconfig_supported(void)
+{
+	char mibname[64];
+	size_t len;
+	int dummy;
+
+	len = sizeof(dummy);
+	snprintf(mibname, sizeof(mibname), "dev.mfi.%d.delete_busy_volumes",
+	    mfi_unit);
+	return (sysctlbyname(mibname, &dummy, &len, NULL, 0) == 0);
+}
+
+int
+mfi_lookup_volume(int fd, const char *name, uint8_t *target_id)
+{
+	struct mfi_query_disk info;
+	struct mfi_ld_list list;
+	char *cp;
+	long val;
+	u_int i;
+
+	/* If it's a valid number, treat it as a raw target ID. */
+	val = strtol(name, &cp, 0);
+	if (*cp == '\0') {
+		*target_id = val;
+		return (0);
+	}
+
+	if (mfi_dcmd_command(fd, MFI_DCMD_LD_GET_LIST, &list, sizeof(list),
+	    NULL, 0, NULL) < 0)
+		return (-1);	
+
+	for (i = 0; i < list.ld_count; i++) {
+		if (mfi_query_disk(fd, list.ld_list[i].ld.v.target_id,
+		    &info) < 0)
+			continue;
+		if (strcmp(name, info.devname) == 0) {
+			*target_id = list.ld_list[i].ld.v.target_id;
+			return (0);
+		}
+	}
+	errno = EINVAL;
+	return (-1);
+}
+
+int
+mfi_dcmd_command(int fd, uint32_t opcode, void *buf, size_t bufsize,
+    uint8_t *mbox, size_t mboxlen, uint8_t *statusp)
+{
+	struct mfi_ioc_passthru ioc;
+	struct mfi_dcmd_frame *dcmd;
+	int r;
+
+	if ((mbox != NULL && (mboxlen == 0 || mboxlen > MFI_MBOX_SIZE)) ||
+	    (mbox == NULL && mboxlen != 0)) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	bzero(&ioc, sizeof(ioc));
+	dcmd = &ioc.ioc_frame;
+	if (mbox)
+		bcopy(mbox, dcmd->mbox, mboxlen);
+	dcmd->header.cmd = MFI_CMD_DCMD;
+	dcmd->header.timeout = 0;
+	dcmd->header.flags = 0;
+	dcmd->header.data_len = bufsize;
+	dcmd->opcode = opcode;
+
+	ioc.buf = buf;
+	ioc.buf_size = bufsize;
+	r = ioctl(fd, MFIIO_PASSTHRU, &ioc);
+	if (r < 0)
+		return (r);
+
+	if (statusp != NULL)
+		*statusp = dcmd->header.cmd_status;
+	else if (dcmd->header.cmd_status != MFI_STAT_OK) {
+		warnx("Command failed: %s",
+		    mfi_status(dcmd->header.cmd_status));
+		errno = EIO;
+		return (-1);
+	}
+	return (0);
+}
+
+int
+mfi_ctrl_get_info(int fd, struct mfi_ctrl_info *info, uint8_t *statusp)
+{
+
+	return (mfi_dcmd_command(fd, MFI_DCMD_CTRL_GETINFO, info,
+	    sizeof(struct mfi_ctrl_info), NULL, 0, statusp));
+}
+
+int
+mfi_open(int unit)
+{
+	char path[MAXPATHLEN];
+
+	snprintf(path, sizeof(path), "/dev/mfi%d", unit);
+	return (open(path, O_RDWR));
+}
+
+void
+mfi_display_progress(const char *label, struct mfi_progress *prog)
+{
+	uint seconds;
+
+	printf("%s: %.2f%% complete, after %ds", label,
+	    (float)prog->progress * 100 / 0xffff, prog->elapsed_seconds);
+	if (prog->elapsed_seconds > 10) {
+		printf(" finished in ");
+		seconds = (0x10000 * (uint32_t)prog->elapsed_seconds) /
+		    prog->progress - prog->elapsed_seconds;
+		if (seconds > 3600)
+			printf("%u:", seconds / 3600);
+		if (seconds > 60) {
+			seconds %= 3600;
+			printf("%02u:%02u", seconds / 60, seconds % 60);
+		} else
+			printf("%us", seconds);
+	}
+	printf("\n");
+}
+
+int
+mfi_table_handler(struct mfiutil_command **start, struct mfiutil_command **end,
+    int ac, char **av)
+{
+	struct mfiutil_command **cmd;
+
+	if (ac < 2) {
+		warnx("The %s command requires a sub-command.", av[0]);
+		return (EINVAL);
+	}
+	for (cmd = start; cmd < end; cmd++) {
+		if (strcmp((*cmd)->name, av[1]) == 0)
+			return ((*cmd)->handler(ac - 1, av + 1));
+	}
+
+	warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
+	return (ENOENT);
+}

Added: head/usr.sbin/mfiutil/mfi_config.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/mfiutil/mfi_config.c	Thu Aug 13 23:18:45 2009	(r196200)
@@ -0,0 +1,1164 @@
+/*-
+ * 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/types.h>
+#ifdef DEBUG
+#include <sys/sysctl.h>
+#endif
+#include <sys/errno.h>
+#include <err.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);
+
+#define powerof2(x)    ((((x)-1)&(x))==0)
+
+static long
+dehumanize(const char *value)
+{
+        char    *vtp;
+        long    iv;
+ 
+        if (value == NULL)
+                return (0);
+        iv = strtoq(value, &vtp, 0);
+        if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
+                return (0);
+        }
+        switch (vtp[0]) {
+        case 't': case 'T':
+                iv *= 1024;
+        case 'g': case 'G':
+                iv *= 1024;
+        case 'm': case 'M':
+                iv *= 1024;
+        case 'k': case 'K':
+                iv *= 1024;
+        case '\0':
+                break;
+        default:
+                return (0);
+        }
+        return (iv);
+}
+int
+mfi_config_read(int fd, struct mfi_config_data **configp)
+{
+	struct mfi_config_data *config;
+	uint32_t config_size;
+
+	/*
+	 * Keep fetching the config in a loop until we have a large enough
+	 * buffer to hold the entire configuration.
+	 */
+	config = NULL;
+	config_size = 1024;
+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)
+		return (-1);
+
+	if (config->size > config_size) {
+		config_size = config->size;
+		goto fetch;
+	}
+
+	*configp = config;
+	return (0);
+}
+
+static struct mfi_array *
+mfi_config_lookup_array(struct mfi_config_data *config, uint16_t array_ref)
+{
+	struct mfi_array *ar;
+	char *p;
+	int i;
+
+	p = (char *)config->array;
+	for (i = 0; i < config->array_count; i++) {
+		ar = (struct mfi_array *)p;
+		if (ar->array_ref == array_ref)
+			return (ar);
+		p += config->array_size;
+	}
+
+	return (NULL);
+}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list