changeset 3798:36499f71540b

6518277 need a common IPMI library 6518283 generic mechanism for detecting SP resets
author eschrock
date Sat, 10 Mar 2007 17:17:25 -0800
parents 2436612507a3
children 271cf3faf99c
files deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_plugin.h deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.c deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.h deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.c deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.h usr/src/Makefile.lint usr/src/cmd/fm/modules/common/Makefile usr/src/cmd/fm/modules/common/sp-monitor/Makefile usr/src/cmd/fm/modules/common/sp-monitor/sp-monitor.conf usr/src/cmd/fm/modules/common/sp-monitor/sp_monitor.c usr/src/cmd/fm/modules/i86pc/sfx4500-disk/Makefile usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_platform.c usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_platform.h usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_plugin.h usr/src/cmd/fm/modules/i86pc/sfx4500-disk/hotplug_mgr.c usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.c usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.h usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.c usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.h usr/src/cmd/fm/modules/i86pc/sfx4500-disk/schg_mgr.c usr/src/cmd/fm/modules/i86pc/sfx4500-disk/sfx4500-disk.c usr/src/cmd/fm/modules/i86pc/sfx4500-disk/util.h usr/src/lib/Makefile usr/src/lib/libipmi/Makefile usr/src/lib/libipmi/Makefile.com usr/src/lib/libipmi/amd64/Makefile usr/src/lib/libipmi/common/ipmi_bmc.c usr/src/lib/libipmi/common/ipmi_impl.h usr/src/lib/libipmi/common/ipmi_misc.c usr/src/lib/libipmi/common/ipmi_sdr.c usr/src/lib/libipmi/common/ipmi_sensor.c usr/src/lib/libipmi/common/ipmi_sunoem.c usr/src/lib/libipmi/common/ipmi_util.c usr/src/lib/libipmi/common/libipmi.c usr/src/lib/libipmi/common/libipmi.h usr/src/lib/libipmi/common/llib-lipmi usr/src/lib/libipmi/common/mapfile-vers usr/src/lib/libipmi/i386/Makefile usr/src/lib/libipmi/sparc/Makefile usr/src/lib/libipmi/sparcv9/Makefile usr/src/pkgdefs/SUNWarc/prototype_com usr/src/pkgdefs/SUNWarc/prototype_i386 usr/src/pkgdefs/SUNWarc/prototype_sparc usr/src/pkgdefs/SUNWcsl/prototype_com usr/src/pkgdefs/SUNWcsl/prototype_i386 usr/src/pkgdefs/SUNWcsl/prototype_sparc usr/src/pkgdefs/SUNWfmd/prototype_com usr/src/pkgdefs/SUNWhea/prototype_com usr/src/pkgdefs/etc/exception_list_sparc usr/src/uts/common/sys/Makefile usr/src/uts/common/sys/bmc_intf.h usr/src/uts/common/sys/sysevent/eventdefs.h
diffstat 52 files changed, 5280 insertions(+), 2474 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_plugin.h	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,81 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DM_PLUGIN_H
+#define	_DM_PLUGIN_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Declarations for the disk monitor plugin interface
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dm_types.h"
+
+/*
+ * The name of the symbol that is of type dm_plugin_ops_t that points to the
+ * implementation of the plugin.
+ */
+#define	DM_PLUGIN_OPS_NAME "dm_plugin_ops"
+
+#define	DM_PLUGIN_VERSION_1	1
+#define	DM_PLUGIN_VERSION DM_PLUGIN_VERSION_1
+
+typedef enum {
+	DMPE_SUCCESS,
+	DMPE_FAILURE
+} dm_plugin_error_t;
+
+typedef void *dm_plugin_action_handle_t;
+
+typedef struct dm_plugin_ops {
+	int			version;
+	dm_plugin_error_t	(*_init)(void);
+	dm_plugin_error_t	(*indicator_fru_update)(
+	    const char *actionString, dm_fru_t *frup);
+	dm_plugin_error_t	(*indicator_bind_handle)(
+	    const char *actionString, dm_plugin_action_handle_t *hdlp);
+	dm_plugin_error_t	(*indicator_execute)(
+	    dm_plugin_action_handle_t hdl);
+	dm_plugin_error_t	(*indicator_free_handle)(
+	    dm_plugin_action_handle_t *hdlp);
+	dm_plugin_error_t	(*_fini)(void);
+} dm_plugin_ops_t;
+
+extern const char *dm_plugin_prop_lookup(const char *propname);
+extern pthread_t dm_plugin_thr_create(void (*fn)(void *), void *);
+extern void dm_plugin_thr_signal(pthread_t);
+extern void dm_plugin_thr_destroy(pthread_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DM_PLUGIN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,1742 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * IPMI Plugin for the disk hotplug & fault monitor
+ */
+
+#include <sys/types.h>
+#include <sys/byteorder.h>
+#include <sys/stat.h>
+#include <sys/stropts.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include <stropts.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <ctype.h>
+#include <limits.h>
+#include <utility.h>
+#include <libnvpair.h>
+#include <sys/bmc_intf.h>
+#include <libuutil.h>
+
+#include "dm_plugin.h"
+#include "util.h"
+#include "ipmi_plugin.h"
+
+#define	BMC_CHECK_UPTIME_INTERVAL	60	/* seconds */
+#define	MESSAGE_BUFSIZE 1024
+#define	BMC_DEV "/dev/bmc"
+
+#define	STRUCT_MIN_SIZE(t, o) offsetof(t, o)
+#define	TDZMALLOC(sz) ((sz *)dzmalloc(sizeof (sz)))
+#define	TDMALLOC(sz) ((sz *)dmalloc(sizeof (sz)))
+
+/* For the purposes of disk capacity, a <X>B is 1000x, not 1024x */
+#define	ONE_KILOBYTE 1000.0
+#define	ONE_MEGABYTE (ONE_KILOBYTE * 1000)
+#define	ONE_GIGABYTE (ONE_MEGABYTE * 1000)
+#define	ONE_TERABYTE (ONE_GIGABYTE * 1000)
+#define	ONE_PETABYTE (ONE_TERABYTE * 1000)
+
+/* IPMI Command Code definitions */
+#define	IPMI_NETFN_OEM			0x2E
+#define	IPMI_CMD_GET_UPTIME		0x08
+#define	IPMI_CMD_FRU_UPDATE		0x16
+#define	IPMI_CMD_GET_SENSOR_READING	0x2d
+#define	IPMI_CMD_SET_SENSOR_READING	0x30
+#define	IPMI_CMD_ADD_SEL_ENTRY		0x44
+
+/* IPMI Request types supported by this plugin: */
+#pragma pack(1)
+struct ipmi_sensor_control {
+	uint8_t		sensor_number;
+	uint8_t		operation;	/* ASSERT_OP | DEASSERT_OP | Both */
+#define	SC_ASSERT_OP	0x20
+#define	SC_DEASSERT_OP	0x08
+	uint8_t		sensor_reading;	/* UNUSED */
+	/*
+	 * The following two fields are stored and sent to the bmc in
+	 * little-endian form
+	 */
+	uint16_t	assert_states;
+	uint16_t	deassert_states;
+#define	STATE_RESERVED_BITS ((uint16_t)0x8000)
+};
+
+/*
+ * Virtual sensor format for FRU data (Sun OEM)
+ */
+struct ipmi_fru_update {
+	uint8_t		global_id;
+	uint8_t		disk_number;	/* Disk number 0-47 on the X4500 */
+	uint8_t		data_length;
+	char		d_manuf[16];
+	char		d_model[28];
+	char		d_serial[20];
+	char		d_firmware[8];
+	char		d_capacity[16];
+};
+
+struct ipmi_sel_entry {
+	uint16_t	recid;		/* Don't care -- bmc will overwrite */
+	uint8_t		type;		/* 0xc0 = OEM SEL Entry */
+#define	SEL_TYPE_OEM	0xC0
+	uint32_t	timestamp;	/* Don't care -- bmc will overwrite */
+	uint8_t		manuf_id[3];
+	uint8_t		oem_defined[6];
+};
+
+struct ipmi_sensor_reading {
+	uint8_t		reading;
+
+	uint8_t		reserved		: 5,
+			data_unavailable	: 1,
+			scanning_enabled	: 1,
+			event_messages_enabled	: 1;
+
+	uint8_t		states_0_7;
+	uint8_t		states_8_14;	/* High bit is reserved */
+#define	sensor_reading_optional_field_start	states_0_7
+};
+
+/*
+ * The following structure's members is returned in BIG-ENDIAN form.
+ */
+struct bmc_uptime_info {
+	uint32_t	uptime_seconds;
+	uint32_t	incarnation;
+};
+#pragma pack()
+/* End of request types supported */
+
+typedef dm_plugin_error_t (*ipmi_packet_setup_fn_t)(nvlist_t *props,
+    void **databpp, int *datablen, void *arg);
+
+struct ipmi_cmd_setup {
+	const char 		*name;
+	ipmi_packet_setup_fn_t	setupfn;
+	uint8_t			netfn;
+	uint8_t			lun;
+	uint8_t			cmd;
+};
+
+typedef struct ipmi_action_handle {
+	uint8_t		netfn;
+	uint8_t		lun;
+	uint8_t		cmd;
+	void		*databp;
+	int		datablen;
+} ipmi_action_handle_t;
+
+typedef enum {
+	CACHE_ENT_FIRST,
+	CACHE_ENT_FRUINFO,
+	CACHE_ENT_SENSORCTL,
+	CACHE_ENT_LAST
+} bmc_cache_ent_type_t;
+
+typedef struct bmc_cache_ent {
+	bmc_cache_ent_type_t		type;
+	union {
+		struct ipmi_fru_update		fru_Info;
+		/*
+		 * The deasserted field is not used
+		 * to cache data in the sensor_control
+		 * structure (we cache asserted states):
+		 */
+		struct ipmi_sensor_control	sensor_Ctl;
+	} u;
+	uu_list_node_t			un_node;
+#define	fruInfo		u.fru_Info
+#define	sensorCtl	u.sensor_Ctl
+} bmc_cache_ent_t;
+
+typedef struct bmc_replay_list_ent {
+	uint8_t		netfn;
+	uint8_t		lun;
+	uint8_t		cmd;
+	uint8_t		*databp;
+	int		datablen;
+	uu_list_node_t	un_node;
+} bmc_replay_list_ent_t;
+
+/*
+ * The ipmi_mutex protects the bmc state$ and serializes bmc device access
+ */
+static pthread_mutex_t ipmi_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t ipmi_cond = PTHREAD_COND_INITIALIZER;
+static dm_plugin_error_t (*sendrecv_fn)(int fd, uint8_t netfn, uint8_t lun,
+    uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp) = NULL;
+
+
+static int bmc_method(int fd, int *if_type);
+static void dump_request(bmc_req_t *request);
+static void dump_response(bmc_rsp_t *response);
+static dm_plugin_error_t ipmi_bmc_send_cmd_ioctl(int fd, uint8_t netfn,
+    uint8_t lun, uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp);
+static dm_plugin_error_t ipmi_bmc_send_cmd_putmsg(int fd, uint8_t netfn,
+    uint8_t lun, uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp);
+static dm_plugin_error_t ipmi_bmc_send_cmd(uint8_t netfn, uint8_t lun,
+    uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp);
+
+/* IPMI Command Buffer-Setup Functions: */
+static dm_plugin_error_t fru_setupfn(nvlist_t *props, void **databpp,
+    int *datablen, void *arg);
+static dm_plugin_error_t state_setupfn(nvlist_t *props, void **databpp,
+    int *datablen, void *arg);
+static dm_plugin_error_t sel_setupfn(nvlist_t *props, void **databpp,
+    int *datablen, void *arg);
+
+/* BMC Monitor and BMC Cache functions: */
+static int bmc_cache_init(void);
+static void bmc_cache_fini(void);
+static int bmc_state_refresh(boolean_t *refreshed);
+static int bmc_state_refresh_from_cache(void);
+static bmc_cache_ent_t *bmc_state_cache_lookup(uint8_t netfn, uint8_t lun,
+    uint8_t cmd, uint8_t *databp, int datablen);
+static void bmc_state_cache_update(uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *databp, int datablen);
+static void bmc_monitor_thread(void *arg);
+
+/* BMC Replay List functions: */
+static int bmc_replay_list_init(void);
+static void bmc_replay_list_fini(void);
+static int bmc_replay_list_execute(void);
+static void bmc_replay_list_add(uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *databp, int datablen);
+
+/* IPMI commands used internally */
+static dm_plugin_error_t bmc_get_uptime(uint32_t *uptime, uint32_t *bootgen);
+static dm_plugin_error_t bmc_get_sensor(uint8_t sensor_id, uint16_t *assrtd,
+    boolean_t *updated_flag);
+
+/* plugin entry points: */
+static dm_plugin_error_t ipmi_plugin_init(void);
+static dm_plugin_error_t ipmi_plugin_fru_update(const char *actionString,
+    dm_fru_t *frup);
+static dm_plugin_error_t ipmi_plugin_bind_handle(const char *actionString,
+    dm_plugin_action_handle_t *hdlp);
+static dm_plugin_error_t ipmi_plugin_execute(dm_plugin_action_handle_t hdl);
+static dm_plugin_error_t ipmi_plugin_free_handle(
+    dm_plugin_action_handle_t *hdlp);
+static dm_plugin_error_t ipmi_plugin_fini(void);
+
+dm_plugin_ops_t ipmi_dm_plugin_ops = {
+	DM_PLUGIN_VERSION,
+	ipmi_plugin_init,
+	ipmi_plugin_fru_update,
+	ipmi_plugin_bind_handle,
+	ipmi_plugin_execute,
+	ipmi_plugin_free_handle,
+	ipmi_plugin_fini
+};
+
+static struct ipmi_cmd_setup ipmi_cmd_tab[] = {
+	{ "fru", fru_setupfn, IPMI_NETFN_OEM,
+	    0, IPMI_CMD_FRU_UPDATE },
+	{ "state", state_setupfn, BMC_NETFN_SE,
+	    0, IPMI_CMD_SET_SENSOR_READING },
+	{ "sel", sel_setupfn, BMC_NETFN_STORAGE,
+	    0, IPMI_CMD_ADD_SEL_ENTRY },
+	{ NULL, NULL, 0, 0, 0 }
+};
+
+static pthread_t g_bmcmon_tid;
+static boolean_t g_bmc_monitor_active;
+static boolean_t g_bmcmon_done;
+static boolean_t g_need_exec_replay = B_FALSE;
+static uu_list_pool_t *g_uu_pool_cache = NULL;
+static uu_list_pool_t *g_uu_pool_replay = NULL;
+static uu_list_t *g_uu_cachelist = NULL;
+static uu_list_t *g_uu_replaylist = NULL;
+static int g_BMCErrorInjectionRate = 0;
+static int g_bmc_fd = -1;
+
+/*
+ * The textual strings that are used in the actions may be one of the
+ * following forms:
+ *
+ * [1] `fru gid=<n> hdd=<m>'
+ * [2] `sensor id=<x> assert=<y> deassert=<z>'
+ *
+ * The generic parser will take a string and spit out the first token
+ * (e.g. `fru' or `sensor') and an nvlist that contains the key-value
+ * pairs in the rest of the string.  The assumption is that there are
+ * no embedded spaces or tabs in the keys or values.
+ */
+
+static boolean_t
+isnumber(const char *str)
+{
+	boolean_t hex = B_FALSE;
+	int digits = 0;
+
+	if (strncasecmp(str, "0x", 2) == 0) {
+		hex = B_TRUE;
+		str += 2;
+	} else if (*str == '-' || *str == '+') {
+		str++;
+	}
+
+	while (*str != 0) {
+		if ((hex && !isxdigit(*str)) ||
+		    (!hex && !isdigit(*str))) {
+			return (B_FALSE);
+		}
+
+		str++;
+		digits++;
+	}
+
+	return ((digits == 0) ? B_FALSE : B_TRUE);
+}
+
+static void
+tolowerString(char *str)
+{
+	while (*str != 0) {
+		*str = tolower(*str);
+		str++;
+	}
+}
+
+static boolean_t
+parse_action_string(const char *actionString, char **cmdp, nvlist_t **propsp)
+{
+	char *action;
+	char *tok, *lasts, *eq;
+	int actionlen;
+	boolean_t rv = B_TRUE;
+
+	if (nvlist_alloc(propsp, NV_UNIQUE_NAME, 0) != 0)
+		return (B_FALSE);
+
+	actionlen = strlen(actionString) + 1;
+	action = dstrdup(actionString);
+
+	*cmdp = NULL;
+
+	if ((tok = strtok_r(action, " \t", &lasts)) != NULL) {
+
+		*cmdp = dstrdup(tok);
+
+		while (rv && (tok = strtok_r(NULL, " \t", &lasts)) != NULL) {
+
+			/* Look for a name=val construct */
+			if ((eq = strchr(tok, '=')) != NULL && eq[1] != 0) {
+
+				*eq = 0;
+				eq++;
+
+				/*
+				 * Convert token to lowercase to preserve
+				 * case-insensitivity, because nvlist doesn't
+				 * do case-insensitive lookups
+				 */
+				tolowerString(tok);
+
+				if (isnumber(eq)) {
+					/* Integer property */
+
+					if (nvlist_add_uint64(*propsp, tok,
+					    strtoull(eq, NULL, 0)) != 0)
+						rv = B_FALSE;
+				} else {
+					/* String property */
+
+					if (nvlist_add_string(*propsp, tok,
+					    eq) != 0)
+						rv = B_FALSE;
+				}
+			} else if (eq == NULL) {
+				/* Boolean property */
+				if (nvlist_add_boolean(*propsp, tok) != 0)
+					rv = B_FALSE;
+			} else /* Parse error (`X=' is invalid) */
+				rv = B_FALSE;
+		}
+	} else
+		rv = B_FALSE;
+
+	dfree(action, actionlen);
+	if (!rv) {
+		if (*cmdp) {
+			dstrfree(*cmdp);
+			*cmdp = NULL;
+		}
+		nvlist_free(*propsp);
+		*propsp = NULL;
+	}
+	return (rv);
+}
+
+static ipmi_action_handle_t *
+new_ipmi_action_handle(uint8_t netfn, uint8_t lun, uint8_t cmd, void *databp,
+    int datablen)
+{
+	ipmi_action_handle_t *ret = TDMALLOC(ipmi_action_handle_t);
+
+	ret->netfn = netfn;
+	ret->lun = lun;
+	ret->cmd = cmd;
+	ret->databp = databp;
+	ret->datablen = datablen;
+
+	return (ret);
+}
+
+static void
+bmc_reopen(void)
+{
+	if (g_bmc_fd >= 0)
+		(void) close(g_bmc_fd);
+	if ((g_bmc_fd = open(BMC_DEV, O_RDWR)) <= 0) {
+		log_warn_e("Could not reopen bmc device");
+	}
+}
+
+static void
+free_ipmi_action_handle(ipmi_action_handle_t **hdlpp)
+{
+	ipmi_action_handle_t *hdlp = *hdlpp;
+
+	if (hdlp) {
+		dfree(hdlp->databp, hdlp->datablen);
+		dfree(hdlp, sizeof (ipmi_action_handle_t));
+		*hdlpp = NULL;
+	}
+}
+
+static boolean_t
+cmd_setup_entry_exists(uint8_t netfn, uint8_t lun, uint8_t cmd)
+{
+	int i;
+
+	for (i = 0; ipmi_cmd_tab[i].name != NULL; i++) {
+
+		if (ipmi_cmd_tab[i].netfn == netfn &&
+		    ipmi_cmd_tab[i].lun == lun &&
+		    ipmi_cmd_tab[i].cmd == cmd)
+			return (B_TRUE);
+	}
+	return (B_FALSE);
+}
+
+static dm_plugin_error_t
+ipmi_exec_action_with_replay(uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *databp, int datablen)
+{
+	bmc_rsp_t		rsp;
+	dm_plugin_error_t	rv;
+
+	(void) bmc_state_refresh(NULL);
+
+	if (g_need_exec_replay)
+		g_need_exec_replay = (bmc_replay_list_execute() != 0);
+
+	if (!g_need_exec_replay) {
+		rv = (ipmi_bmc_send_cmd(netfn, lun, cmd, databp, datablen, &rsp)
+		    == DMPE_SUCCESS && rsp.ccode == 0)
+		    ? DMPE_SUCCESS : DMPE_FAILURE;
+	}
+
+	/*
+	 * If the command failed (or we couldn't execute the command because
+	 * we couldn't execute the replay list), and the failure is due to a
+	 * timeout error, save the command's result for later replay
+	 */
+	if (g_need_exec_replay || (rv == DMPE_FAILURE &&
+	    rsp.ccode == BMC_IPMI_COMMAND_TIMEOUT)) {
+
+		/*
+		 * Fake the return value as success (since we queued the
+		 * command for later execution).
+		 */
+		rv = DMPE_SUCCESS;
+		bmc_replay_list_add(netfn, lun, cmd, databp, datablen);
+		g_need_exec_replay = B_TRUE;
+
+	} else if (!g_need_exec_replay && rv == DMPE_SUCCESS) {
+
+		/* Apply the command to the bmc state$ */
+		bmc_state_cache_update(netfn, lun, cmd, databp, datablen);
+	}
+
+	return (rv);
+}
+
+static dm_plugin_error_t
+exec_action_handle(ipmi_action_handle_t *hdlp)
+{
+	dm_plugin_error_t rv;
+
+	/*
+	 * Sanity check this handle -- the netfn/lun/cmd should match one
+	 * of those defined in the ipmi_cmd_tab:
+	 */
+	if (!cmd_setup_entry_exists(hdlp->netfn, hdlp->lun, hdlp->cmd)) {
+		log_warn("Possible corrupt handle @%p (netfn/lun/cmd does "
+		    "not match any known commands.\n", (void *)hdlp);
+		return (DMPE_FAILURE);
+	}
+
+	dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
+
+	rv = ipmi_exec_action_with_replay(hdlp->netfn, hdlp->lun, hdlp->cmd,
+	    hdlp->databp, hdlp->datablen);
+
+	dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
+
+	return (rv);
+}
+
+static dm_plugin_error_t
+action_do(const char *actionString, void *arg, boolean_t exec,
+    ipmi_action_handle_t **hdlpp)
+{
+	nvlist_t	*props;
+	char		*cmd;
+	int		found_index;
+	int		datablen, i;
+	void		*databp;
+	uint8_t		netfn, lun, cmdno;
+	dm_plugin_error_t rv = DMPE_FAILURE;	/* Be pessimistic */
+
+	if (parse_action_string(actionString, &cmd, &props)) {
+		for (found_index = -1, i = 0;
+		    found_index == -1 && ipmi_cmd_tab[i].name != NULL; i++) {
+			if (strcasecmp(cmd, ipmi_cmd_tab[i].name) == 0) {
+				dm_assert(ipmi_cmd_tab[i].setupfn != NULL);
+				rv = ipmi_cmd_tab[i].setupfn(props,
+				    &databp, &datablen, arg);
+				found_index = i;
+			}
+		}
+
+		dstrfree(cmd);
+		nvlist_free(props);
+
+		netfn = ipmi_cmd_tab[found_index].netfn;
+		lun = ipmi_cmd_tab[found_index].lun;
+		cmdno = ipmi_cmd_tab[found_index].cmd;
+
+		if (exec && found_index != -1 && rv == DMPE_SUCCESS) {
+
+			dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
+
+			rv = ipmi_exec_action_with_replay(netfn, lun,
+			    cmdno, databp, datablen);
+
+			dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
+
+			dfree(databp, datablen);
+
+		} else if (found_index != -1 && rv == DMPE_SUCCESS) {
+			dm_assert(hdlpp != NULL);
+
+			*hdlpp = new_ipmi_action_handle(netfn, lun, cmdno,
+			    databp, datablen);
+		}
+	}
+
+	return (rv);
+}
+
+static dm_plugin_error_t
+fru_setupfn(nvlist_t *props, void **databpp, int *datablen,
+    void *arg)
+{
+	uint64_t gid, hdd;
+	struct ipmi_fru_update *fup;
+	char *buf;
+	dm_fru_t *frup = (dm_fru_t *)arg;
+
+	/* We need 2 properties: `gid' and `hdd': */
+	if (nvlist_lookup_uint64(props, "gid", &gid) != 0 ||
+	    nvlist_lookup_uint64(props, "hdd", &hdd) != 0) {
+		return (DMPE_FAILURE);
+	}
+
+	fup = TDZMALLOC(struct ipmi_fru_update);
+	buf = (char *)dzmalloc(sizeof (fup->d_capacity) + 1);
+
+	*datablen = sizeof (struct ipmi_fru_update);
+	*databpp = fup;
+
+	fup->global_id = (uint8_t)gid;
+	fup->disk_number = (uint8_t)hdd;
+	fup->data_length = sizeof (fup->d_manuf) + sizeof (fup->d_model) +
+	    sizeof (fup->d_serial) + sizeof (fup->d_firmware) +
+	    sizeof (fup->d_capacity);
+	(void) memcpy(fup->d_manuf, frup->manuf,
+	    MIN(sizeof (fup->d_manuf), sizeof (frup->manuf)));
+	(void) memcpy(fup->d_model, frup->model,
+	    MIN(sizeof (fup->d_model), sizeof (frup->model)));
+	(void) memcpy(fup->d_serial, frup->serial,
+	    MIN(sizeof (fup->d_serial), sizeof (frup->serial)));
+	(void) memcpy(fup->d_firmware, frup->rev,
+	    MIN(sizeof (fup->d_firmware), sizeof (frup->rev)));
+	/*
+	 * Print the size of the disk to a temporary buffer whose size is
+	 * 1 more than the size of the buffer in the ipmi request data
+	 * structure, so we can get the full 8 characters (instead of 7 + NUL)
+	 */
+	(void) snprintf(buf, sizeof (fup->d_capacity) + 1,
+	    "%.1f%s",
+	    frup->size_in_bytes >= ONE_PETABYTE ?
+		(frup->size_in_bytes / ONE_PETABYTE) :
+		    (frup->size_in_bytes >= ONE_TERABYTE ?
+			    (frup->size_in_bytes / ONE_TERABYTE) :
+				(frup->size_in_bytes >= ONE_GIGABYTE ?
+				    (frup->size_in_bytes / ONE_GIGABYTE) :
+					(frup->size_in_bytes >= ONE_MEGABYTE ?
+				(frup->size_in_bytes / ONE_MEGABYTE) :
+				    (frup->size_in_bytes / ONE_KILOBYTE)))),
+
+	    frup->size_in_bytes >= ONE_PETABYTE ? "PB" :
+		    (frup->size_in_bytes >= ONE_TERABYTE ? "TB" :
+			(frup->size_in_bytes >= ONE_GIGABYTE ? "GB" :
+				(frup->size_in_bytes >= ONE_MEGABYTE ? "MB" :
+					"KB"))));
+	(void) memcpy(fup->d_capacity, buf, sizeof (fup->d_capacity));
+
+	dfree(buf, sizeof (fup->d_capacity) + 1);
+	return (DMPE_SUCCESS);
+}
+
+/*ARGSUSED*/
+static dm_plugin_error_t
+state_setupfn(nvlist_t *props, void **databpp, int *datablen,
+    void *arg)
+{
+	uint64_t assertmask = 0, deassertmask = 0, sid;
+	boolean_t am_present, dam_present;
+	struct ipmi_sensor_control *scp;
+
+	/* We need at least 2 properties: `sid' and (`amask' || `dmask'): */
+	am_present = nvlist_lookup_uint64(props, "amask", &assertmask) == 0;
+	dam_present = nvlist_lookup_uint64(props, "dmask", &deassertmask) == 0;
+
+	if (nvlist_lookup_uint64(props, "sid", &sid) != 0 ||
+	    (!am_present && !dam_present)) {
+		return (DMPE_FAILURE);
+	}
+
+	if (sid > UINT8_MAX) {
+		log_warn("IPMI Plugin: Invalid sensor id `0x%" PRIx64 "'.\n",
+		    sid);
+		return (DMPE_FAILURE);
+	} else if (assertmask > UINT16_MAX) {
+		log_warn("IPMI Plugin: Invalid assertion mask `0x%" PRIx64
+		    "'.\n", assertmask);
+		return (DMPE_FAILURE);
+	} else if (assertmask > UINT16_MAX) {
+		log_warn("IPMI Plugin: Invalid deassertion mask `0x%" PRIx64
+		    "'.\n", deassertmask);
+		return (DMPE_FAILURE);
+	}
+
+	scp = TDZMALLOC(struct ipmi_sensor_control);
+
+	scp->sensor_number = (uint8_t)sid;
+	scp->operation = (am_present ? SC_ASSERT_OP : 0) |
+	    (dam_present ? SC_DEASSERT_OP : 0);
+	scp->assert_states = (uint16_t)assertmask;
+	scp->deassert_states = (uint16_t)deassertmask;
+
+	*datablen = sizeof (struct ipmi_sensor_control);
+	*databpp = scp;
+
+	return (DMPE_SUCCESS);
+}
+
+/*ARGSUSED*/
+static dm_plugin_error_t
+sel_setupfn(nvlist_t *props, void **databpp, int *datablen,
+    void *arg)
+{
+	uint64_t oem_data, manuf_id;
+	struct ipmi_sel_entry *sep;
+
+	/* We need 2 properties: `oem' and `manu': */
+	if (nvlist_lookup_uint64(props, "oem", &oem_data) != 0 ||
+	    nvlist_lookup_uint64(props, "manu", &manuf_id) != 0) {
+
+		return (DMPE_FAILURE);
+	}
+
+	if ((manuf_id & ~0xFFFFFFULL) != 0) {
+		log_warn("IPMI Plugin: Invalid manuf field `0x%" PRIx64 "'.\n",
+		    manuf_id);
+		return (DMPE_FAILURE);
+	} else if ((oem_data & ~0xFFFFFFFFFFFFULL) != 0) {
+		log_warn("IPMI Plugin: Invalid oem field `0x%" PRIx64
+		    "'.\n", oem_data);
+		return (DMPE_FAILURE);
+	}
+
+	sep = TDZMALLOC(struct ipmi_sel_entry);
+
+	sep->type = SEL_TYPE_OEM;
+	sep->manuf_id[0] = (uint8_t)(manuf_id & 0xFFULL);
+	sep->manuf_id[1] = (uint8_t)((manuf_id & 0xFF00ULL) >> 8);
+	sep->manuf_id[2] = (uint8_t)((manuf_id & 0xFF0000ULL) >> 16);
+	sep->oem_defined[0] = (uint8_t)(oem_data & 0xFFULL);
+	sep->oem_defined[1] = (uint8_t)((oem_data & 0xFF00ULL) >> 8);
+	sep->oem_defined[2] = (uint8_t)((oem_data & 0xFF0000ULL) >> 16);
+	sep->oem_defined[3] = (uint8_t)((oem_data & 0xFF000000ULL) >> 24);
+	sep->oem_defined[4] = (uint8_t)((oem_data & 0xFF00000000ULL) >> 32);
+	sep->oem_defined[5] = (uint8_t)((oem_data & 0xFF0000000000ULL) >> 40);
+
+	*datablen = sizeof (struct ipmi_sel_entry);
+	*databpp = sep;
+
+	return (DMPE_SUCCESS);
+}
+
+static dm_plugin_error_t
+bmc_get_sensor(uint8_t sensor_id, uint16_t *assrtd, boolean_t *updated_flag)
+{
+	dm_plugin_error_t		rv;
+	bmc_rsp_t			rsp;
+	struct ipmi_sensor_reading	*srp;
+
+	rv = ipmi_bmc_send_cmd(IPMI_NETFN_OEM, 0, IPMI_CMD_GET_SENSOR_READING,
+	    &sensor_id, 1, &rsp);
+
+	/* The command must return precisely the size of the data we expect */
+	if (rsp.ccode ||
+	    rsp.datalength > sizeof (struct ipmi_sensor_reading) ||
+	    rsp.datalength < STRUCT_MIN_SIZE(struct ipmi_sensor_reading,
+	    sensor_reading_optional_field_start))
+		rv = DMPE_FAILURE;
+
+	srp = (struct ipmi_sensor_reading *)&rsp.data[0];
+
+	if (rv == DMPE_SUCCESS &&
+	    rsp.datalength == sizeof (struct ipmi_sensor_reading) &&
+	    !srp->data_unavailable && srp->scanning_enabled) {
+
+		if (assrtd) {
+			*assrtd = (srp->states_8_14 << 8) | srp->states_0_7;
+			if (updated_flag)
+				*updated_flag = B_TRUE;
+		}
+	}
+	return (rv);
+}
+
+static dm_plugin_error_t
+bmc_get_uptime(uint32_t *uptime, uint32_t *bootgen)
+{
+	dm_plugin_error_t	rv;
+	uint8_t			junk = 0;
+	bmc_rsp_t		rsp;
+	struct bmc_uptime_info	*utinfop;
+
+	rv = ipmi_bmc_send_cmd(IPMI_NETFN_OEM, 0, IPMI_CMD_GET_UPTIME, &junk,
+	    1, &rsp);
+
+	/* The command must return precisely the size of the data we expect */
+	if (rsp.ccode ||
+	    rsp.datalength != sizeof (struct bmc_uptime_info))
+		rv = DMPE_FAILURE;
+
+	if (rv == DMPE_SUCCESS) {
+		utinfop = (struct bmc_uptime_info *)&rsp.data[0];
+		if (uptime)
+			*uptime = BE_32(utinfop->uptime_seconds);
+		if (bootgen)
+			*bootgen = BE_32(utinfop->incarnation);
+	}
+	return (rv);
+}
+
+/* ****** B M C   R E P L A Y    L I S T   I M P L E M E N T A T I O N ****** */
+
+/*
+ * The reasoning behind the replay list is to try to ensure that commands are
+ * reliably sent to the BMC.  In the case of the replay list, any commands that
+ * fail because they timed out are added tothe replay list.  Then, the next time
+ * a command is attempted, the replay list is sent to the BMC first, then the
+ * new command (to preserve ordering).  Currently, the only commands that are
+ * supported by this plugin are write-oriented commands, where information is
+ * sent to the BMC.  If, if the future, read-oriented commands are desired,
+ * The replay mechanism will need to be enhanced to force all pending commands
+ * in the replay list out to the BMC before executing the read-oriented
+ * command (similar to a write cache that's flushed when a read is requested).
+ */
+
+static void
+bmc_replay_list_ent_destroy(bmc_replay_list_ent_t *p)
+{
+	if (p->databp)
+		dfree(p->databp, p->datablen);
+	dfree(p, sizeof (bmc_replay_list_ent_t));
+}
+
+static int
+bmc_replay_list_init(void)
+{
+	if ((g_uu_pool_replay = uu_list_pool_create(
+	    "bmc_replay_list_pool", sizeof (bmc_replay_list_ent_t),
+	    offsetof(bmc_replay_list_ent_t, un_node), NULL, 0)) == NULL)
+		return (DMPE_FAILURE);
+
+	if ((g_uu_replaylist = uu_list_create(g_uu_pool_replay, NULL, 0))
+	    == NULL) {
+		uu_list_pool_destroy(g_uu_pool_replay);
+		return (DMPE_FAILURE);
+	}
+
+	return (DMPE_SUCCESS);
+}
+
+static void
+bmc_replay_list_fini(void)
+{
+	void			*cookie = NULL;
+	bmc_replay_list_ent_t	*p;
+
+	while ((p = (bmc_replay_list_ent_t *)uu_list_teardown(g_uu_replaylist,
+	    &cookie)) != NULL) {
+		bmc_replay_list_ent_destroy(p);
+	}
+
+	uu_list_destroy(g_uu_replaylist);
+	uu_list_pool_destroy(g_uu_pool_replay);
+	g_uu_replaylist = NULL;
+	g_uu_pool_replay = NULL;
+}
+
+/*
+ * The caller must hold the ipmi_mutex!
+ */
+static void
+bmc_replay_list_add(uint8_t netfn, uint8_t lun, uint8_t cmd, uint8_t *databp,
+    int datablen)
+{
+	bmc_replay_list_ent_t *p = TDMALLOC(bmc_replay_list_ent_t);
+
+	p->netfn = netfn;
+	p->lun = lun;
+	p->cmd = cmd;
+	/*
+	 * Make a deep copy of the data buffer, since we can't assume
+	 * anything about when it will be deallocated.
+	 */
+	if (datablen > 0) {
+		p->databp = (uint8_t *)dmalloc(datablen);
+		(void) memcpy(p->databp, databp, datablen);
+	}
+	p->datablen = datablen;
+
+	dm_assert(g_uu_pool_replay != NULL);
+	dm_assert(g_uu_replaylist != NULL);
+	uu_list_node_init(p, &p->un_node, g_uu_pool_replay);
+	/* The replay list is a queue, so add to its tail: */
+	(void) uu_list_insert_before(g_uu_replaylist, NULL, p);
+}
+
+/*
+ * The caller must hold the ipmi_mutex!
+ *
+ * Returns < 0 if the replay list should be executed at a later time
+ * (due to transient errors)
+ */
+static int
+bmc_replay_list_execute(void)
+{
+	uu_list_walk_t		*walkp;
+	bmc_replay_list_ent_t	*p = NULL;
+	boolean_t		timedout_err = B_FALSE;
+	bmc_rsp_t		rsp;
+	dm_plugin_error_t	rv;
+
+	if ((walkp = uu_list_walk_start(g_uu_replaylist, 0)) == NULL)
+		return (-1);
+
+	/*
+	 * On the first timeout error, abort the replay; We cannot execute
+	 * commands later in the list because they may depend on the state
+	 * set by earlier commands.  We'll retry the command that failed
+	 * later. (Note that non-timeout-related failures do not cause
+	 * aborts because the assumption is that the original command caller
+	 * would not behave differently if a command were to fail.)  If this
+	 * assumption does not remain valid in the future, an enhancement to
+	 * the plugin API would be required to introduce a synchronous flag
+	 * that would result in the blocking of the calling thread until
+	 * BOTH the replay list is fully executed AND the user's current
+	 * command is executed (at which point the status can be examined
+	 * by the caller).
+	 */
+	while (!timedout_err && (p = uu_list_walk_next(walkp)) != NULL) {
+		rv = ipmi_bmc_send_cmd(p->netfn, p->lun, p->cmd, p->databp,
+		    p->datablen, &rsp);
+
+		if (rv == DMPE_SUCCESS ||
+		    (rv == DMPE_FAILURE &&
+		    rsp.ccode != BMC_IPMI_COMMAND_TIMEOUT)) {
+
+			if (rsp.ccode != 0) {
+				log_msg(MM_PLUGIN, "ipmi plugin: netfn 0x%x "
+				    "cmd 0x%x ccode=0x%x\n", p->netfn, p->cmd,
+				    rsp.ccode);
+			}
+			if (rv == DMPE_SUCCESS) {
+				/* Add the command to the bmc state$ */
+				bmc_state_cache_update(p->netfn, p->lun, p->cmd,
+				    p->databp, p->datablen);
+			}
+			uu_list_remove(g_uu_replaylist, p);
+			bmc_replay_list_ent_destroy(p);
+
+		} else if (rv == DMPE_FAILURE &&
+		    rsp.ccode == BMC_IPMI_COMMAND_TIMEOUT) {
+
+			timedout_err = B_TRUE;
+		}
+	}
+
+	uu_list_walk_end(walkp);
+	return (timedout_err ? -1 : 0);
+}
+
+/* ************** B M C  C A C H E  I M P L E M E N T A T I O N ************* */
+
+/*
+ * The reasoning behind the cache is to maintain a mirror of the BMC's state
+ * as it pertains to the commands that were sent from the plugin.  For Sun's
+ * BMC implementations, the sensor and FRU information is not currently
+ * preserved when the BMC (or service processor) is reset (or rebooted).  To
+ * maintain consistency from the user/administrator's perspective, once the
+ * BMC comes back online after a reset, the information from the state cache
+ * is sent, all at once, in particular order, to the BMC.
+ */
+
+static int
+bmc_cache_init(void)
+{
+	if ((g_uu_pool_cache = uu_list_pool_create(
+	    "bmc_cache_entry_pool", sizeof (bmc_cache_ent_t),
+	    offsetof(bmc_cache_ent_t, un_node), NULL, 0)) == NULL)
+		return (DMPE_FAILURE);
+
+	if ((g_uu_cachelist = uu_list_create(g_uu_pool_cache, NULL, 0))
+	    == NULL) {
+		uu_list_pool_destroy(g_uu_pool_cache);
+		return (DMPE_FAILURE);
+	}
+
+	return (DMPE_SUCCESS);
+}
+
+static void
+bmc_cache_fini(void)
+{
+	void	*cookie = NULL;
+	void	*p;
+
+	while ((p = uu_list_teardown(g_uu_cachelist, &cookie)) != NULL)
+		dfree(p, sizeof (bmc_cache_ent_t));
+
+	uu_list_destroy(g_uu_cachelist);
+	uu_list_pool_destroy(g_uu_pool_cache);
+
+	g_uu_cachelist = NULL;
+	g_uu_pool_cache = NULL;
+}
+
+static void
+bmc_cache_member_init_sensorctl(bmc_cache_ent_t *p, void *databp)
+{
+	struct ipmi_sensor_control	*tgt;
+	uint16_t			assrtd;
+	boolean_t			was_assrtd_updated = B_FALSE;
+
+	tgt = (struct ipmi_sensor_control *)databp;
+
+	/*
+	 * operation is initted here so that when we do the bmc update from
+	 * the cache, the structure will ready to send directly from the cache
+	 */
+	p->sensorCtl.sensor_number = tgt->sensor_number;
+	p->sensorCtl.operation = SC_ASSERT_OP;
+	p->sensorCtl.assert_states = tgt->assert_states;
+
+	/*
+	 * If the command fails, we'll still have the asserted
+	 * states that were set by the command that just finished
+	 */
+	if (bmc_get_sensor(p->sensorCtl.sensor_number, &assrtd,
+	    &was_assrtd_updated) == DMPE_SUCCESS &&
+	    was_assrtd_updated == B_TRUE) {
+
+		/*
+		 * If the states that were just asserted are not when we
+		 * check, issues a warning, but only if the verbosity is
+		 * jacked up -- this could be OK (if another user updates
+		 * the sensor's state between the time we executed the
+		 * update sensor command and the time we check the sensor's
+		 * value.
+		 */
+		if ((p->sensorCtl.assert_states & assrtd)
+		    != p->sensorCtl.assert_states) {
+
+			log_msg(MM_PLUGIN,
+			    "Asserted state(s) set before cache addition "
+			    "(0x%x) didn't stick -- caching them anyway\n",
+			    p->sensorCtl.assert_states);
+		}
+
+		p->sensorCtl.assert_states |= assrtd;
+	}
+}
+
+static void
+bmc_cache_member_update_sensorctl(bmc_cache_ent_t *p, void *databp)
+{
+	struct ipmi_sensor_control *tgt = (struct ipmi_sensor_control *)databp;
+
+	/*
+	 * It's not possible for the same bits to be set in the assert and
+	 * deassert masks- it would have cause an IPMI error when the
+	 * command was originally executed (and the cache update would
+	 * therefore not have occurred)
+	 */
+	p->sensorCtl.assert_states |= tgt->assert_states;
+	p->sensorCtl.assert_states &= ~tgt->deassert_states;
+}
+
+static boolean_t
+bmc_cache_member_match_sensorctl(bmc_cache_ent_t *p, void *databp)
+{
+	struct ipmi_sensor_control *tgt = (struct ipmi_sensor_control *)databp;
+
+	return (p->sensorCtl.sensor_number == tgt->sensor_number);
+}
+
+static void
+bmc_cache_member_bufsetup_sensorctl(bmc_cache_ent_t *p, void **bufpp,
+    int *buflenp)
+{
+	/* Mask off bits that shouldn't be set according to the spec */
+	p->sensorCtl.operation = SC_ASSERT_OP|SC_DEASSERT_OP;
+	p->sensorCtl.assert_states &= ~STATE_RESERVED_BITS;
+	p->sensorCtl.deassert_states =
+	    (~p->sensorCtl.assert_states & ~STATE_RESERVED_BITS);
+
+	*bufpp = &p->sensorCtl;
+	*buflenp = sizeof (struct ipmi_sensor_control);
+}
+
+static void
+bmc_cache_member_init_fru_update(bmc_cache_ent_t *p, void *databp)
+{
+	(void) memcpy(&p->fruInfo, databp, sizeof (struct ipmi_fru_update));
+}
+
+static void
+bmc_cache_member_update_fru_update(bmc_cache_ent_t *p, void *databp)
+{
+	(void) memcpy(&p->fruInfo, databp, sizeof (struct ipmi_fru_update));
+}
+
+
+static boolean_t
+bmc_cache_member_match_fru_update(bmc_cache_ent_t *p, void *databp)
+{
+	struct ipmi_fru_update *frup = (struct ipmi_fru_update *)databp;
+
+	return (p->fruInfo.global_id == frup->global_id &&
+	    p->fruInfo.disk_number == frup->disk_number);
+}
+
+static void
+bmc_cache_member_bufsetup_fru_update(bmc_cache_ent_t *p, void **bufpp,
+    int *buflenp)
+{
+	*bufpp = &p->fruInfo;
+	*buflenp = sizeof (struct ipmi_fru_update);
+}
+
+/*
+ * Different elements in the cache need to be restored in order
+ * (e.g. sensor state information must be populated before FRU information
+ * is populated because the FRU information won't "stick" if the right
+ * state isn't asserted)
+ * The g_restoreOrder array is indexed by cache entry type
+ */
+static const bmc_cache_ent_type_t g_restoreOrder[] = {
+	CACHE_ENT_SENSORCTL,
+	CACHE_ENT_FRUINFO,
+	CACHE_ENT_LAST
+};
+
+static struct bmc_cache_member {
+	uint8_t				netfn;
+	uint8_t				lun;
+	uint8_t				cmd;
+	int				dataszmin;
+	boolean_t			(*matchfn)(bmc_cache_ent_t *, void *);
+	void				(*updatefn)(bmc_cache_ent_t *, void *);
+	void				(*initfn)(bmc_cache_ent_t *, void *);
+	void				(*bufsetupfn)(bmc_cache_ent_t *,
+							void **, int *);
+	void				(*bufdonefn)(bmc_cache_ent_t *, void *,
+							int);
+
+} g_cachemembers[] = {
+
+	/* CACHE_ENT_FIRST */
+	{ 0, 0, 0, 0, NULL },
+
+	/* CACHE_ENT_FRUINFO */
+	{ IPMI_NETFN_OEM, 0, IPMI_CMD_FRU_UPDATE,
+	    sizeof (struct ipmi_fru_update),
+	    bmc_cache_member_match_fru_update,
+	    bmc_cache_member_update_fru_update,
+	    bmc_cache_member_init_fru_update,
+	    bmc_cache_member_bufsetup_fru_update,
+	    NULL },
+
+	/* CACHE_ENT_SENSORCTL */
+	{ BMC_NETFN_SE, 0, IPMI_CMD_SET_SENSOR_READING,
+	    sizeof (struct ipmi_sensor_control),
+	    bmc_cache_member_match_sensorctl,
+	    bmc_cache_member_update_sensorctl,
+	    bmc_cache_member_init_sensorctl,
+	    bmc_cache_member_bufsetup_sensorctl,
+	    NULL },
+
+	/* CACHE_ENT_LAST */
+	{ 0, 0, 0, 0, NULL }
+};
+
+static bmc_cache_ent_t *
+bmc_state_cache_lookup(uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *databp, int datablen)
+{
+	uu_list_walk_t		*walkp;
+	bmc_cache_ent_t		*p = NULL;
+	boolean_t		found = B_FALSE;
+
+	if ((walkp = uu_list_walk_start(g_uu_cachelist, 0)) == NULL)
+		return (NULL);
+
+	while (!found && (p = uu_list_walk_next(walkp)) != NULL) {
+
+		if (g_cachemembers[p->type].netfn == netfn &&
+		    g_cachemembers[p->type].lun == lun &&
+		    g_cachemembers[p->type].cmd == cmd &&
+		    datablen >= g_cachemembers[p->type].dataszmin &&
+		    (*(g_cachemembers[p->type].matchfn))(p, databp) == B_TRUE) {
+
+				found = B_TRUE;
+		}
+	}
+
+	uu_list_walk_end(walkp);
+	return (found ? p : NULL);
+}
+
+static void
+bmc_state_cache_add(uint8_t netfn, uint8_t lun, uint8_t cmd, uint8_t *databp,
+    int datablen)
+{
+	boolean_t	found_initfn = B_FALSE;
+	int		i;
+	bmc_cache_ent_t	*p;
+
+	p = (bmc_cache_ent_t *)dzmalloc(sizeof (bmc_cache_ent_t));
+	for (i = CACHE_ENT_FIRST + 1; !found_initfn && i < CACHE_ENT_LAST;
+	    i++) {
+
+		if (g_cachemembers[i].netfn == netfn &&
+		    g_cachemembers[i].lun == lun &&
+		    g_cachemembers[i].cmd == cmd &&
+		    datablen >= g_cachemembers[i].dataszmin) {
+
+			p->type = i;
+			(*(g_cachemembers[i].initfn))(p, databp);
+			found_initfn = B_TRUE;
+		}
+	}
+
+	if (found_initfn) {
+
+		dm_assert(g_uu_pool_cache != NULL);
+		dm_assert(g_uu_cachelist != NULL);
+		uu_list_node_init(p, &p->un_node, g_uu_pool_cache);
+		uu_list_insert(g_uu_cachelist, p, 0);
+
+	} else {
+		log_msg(MM_PLUGIN, "Not adding netfn=0x%x cmd=0x%x to the "
+		    "bmc$\n", netfn, cmd);
+
+		dfree(p, sizeof (bmc_cache_ent_t));
+	}
+}
+
+/*
+ * The caller must hold the ipmi_mutex!
+ */
+static void
+bmc_state_cache_update(uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *databp, int datablen)
+{
+	bmc_cache_ent_t			*p;
+
+	/*
+	 * Do a lookup to see if we have an entry for this entity.
+	 * If so, update it, otherwise, create a new entry in the cache.
+	 */
+
+
+	if ((p = bmc_state_cache_lookup(netfn, lun, cmd, databp, datablen))
+	    != NULL) {
+
+		/* Update the cache with the command payload */
+		(*(g_cachemembers[p->type].updatefn))(p, databp);
+
+	} else {
+
+		/* Add the item to the cache */
+		bmc_state_cache_add(netfn, lun, cmd, databp, datablen);
+	}
+}
+
+/*
+ * Caller MUST hold the ipmi_lock
+ */
+static int
+bmc_state_refresh_from_cache(void)
+{
+	int			i;
+	uu_list_walk_t		*walkp;
+	bmc_cache_ent_t		*p = NULL;
+	boolean_t		bail = B_FALSE;
+	void			*databp;
+	int			datablen;
+	dm_plugin_error_t	rv;
+	bmc_rsp_t		rsp;
+
+	/*
+	 * Since cached state needs to be restored in a particular
+	 * order, make several passes through the cache list, restoring
+	 * the state in pass-order. If this becomes performance-limiting,
+	 * the cache list can be populated in sorted order (in pass order)
+	 */
+	for (i = 0; !bail && g_restoreOrder[i] != CACHE_ENT_LAST; i++) {
+
+		if ((walkp = uu_list_walk_start(g_uu_cachelist, 0)) == NULL)
+			return (-1);
+
+		while (!bail && (p = uu_list_walk_next(walkp)) != NULL) {
+
+			if (p->type == g_restoreOrder[i]) {
+
+				(*(g_cachemembers[p->type].bufsetupfn))
+				    (p, &databp, &datablen);
+
+				rv = ipmi_bmc_send_cmd(
+				    g_cachemembers[p->type].netfn,
+				    g_cachemembers[p->type].lun,
+				    g_cachemembers[p->type].cmd,
+				    databp, datablen, &rsp);
+
+				if (rv == DMPE_FAILURE &&
+				    rsp.ccode != BMC_IPMI_COMMAND_TIMEOUT)
+					bail = B_TRUE;
+
+				if (g_cachemembers[p->type].bufdonefn)
+					(*(g_cachemembers[p->type].bufdonefn))
+					    (p, databp, datablen);
+			}
+		}
+
+		uu_list_walk_end(walkp);
+	}
+
+	return (bail ? -1 : 0);
+}
+
+/*
+ * Caller MUST hold the ipmi_lock
+ */
+static int
+bmc_state_refresh(boolean_t *refreshed)
+{
+	static uint32_t		last_utime = 0;
+	static uint32_t		last_iter = 0;
+	static boolean_t	initted = B_FALSE;
+	uint32_t		utime;
+	uint32_t		iter;
+	dm_plugin_error_t	rv;
+
+	if (!g_bmc_monitor_active)
+		return (0);
+
+	rv = bmc_get_uptime(&utime, &iter);
+
+	if (refreshed)
+		*refreshed = B_FALSE;
+
+	if (rv == DMPE_SUCCESS) {
+
+		/*
+		 * This also handles the wrap-around case (when utime is
+		 * less than last_utime, but iter == last_iter), and
+		 * also the case when the BMC's configuration is
+		 * reset after a reboot (e.g. the reboot iteration #
+		 * is reset to 0).
+		 */
+		if (initted &&
+		    (utime < last_utime || iter != last_iter)) {
+			/* BMC Reboot/Reset Detected */
+			log_msg(MM_PLUGIN, "BMC refresh in progress...");
+			if (bmc_state_refresh_from_cache() < 0) {
+				log_msg(MM_PLUGIN, "BMC refresh failed!\n");
+				return (-1);
+			} else {
+				if (refreshed)
+					*refreshed = B_TRUE;
+			}
+		}
+
+		last_utime = utime;
+		last_iter = iter;
+		initted = B_TRUE;
+	}
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static void
+bmc_monitor_thread(void *arg)
+{
+	struct timespec 	tspec;
+	boolean_t		refreshed;
+
+	dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
+	while (!g_bmcmon_done) {
+
+		if (bmc_state_refresh(&refreshed) == 0 && refreshed) {
+			/*
+			 * If the state was successfully refreshed, and there's
+			 * replay list, execute that list.
+			 */
+			if (g_need_exec_replay) {
+				g_need_exec_replay =
+				    (bmc_replay_list_execute() != 0);
+			}
+
+			log_msg(MM_PLUGIN, "BMC successfully refreshed with "
+				    "cached state!\n");
+		}
+
+		/* Poll the BMC for any changes in its state every minute */
+		tspec.tv_sec = time(0) + BMC_CHECK_UPTIME_INTERVAL;
+		tspec.tv_nsec = 0;
+
+		(void) pthread_cond_timedwait(&ipmi_cond,
+		    &ipmi_mutex, &tspec);
+	}
+	dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
+
+	log_msg(MM_PLUGIN, "BMC monitoring thread exiting...");
+}
+
+/* ***************** P L U G I N  E N T R Y  P O I N T S ******************* */
+
+static dm_plugin_error_t
+ipmi_plugin_init(void)
+{
+	int method;
+	const char *monpropval =
+	    dm_plugin_prop_lookup(GLOBAL_PROP_IPMI_BMC_MON);
+	const char *errinjprop =
+	    dm_plugin_prop_lookup(GLOBAL_PROP_IPMI_ERR_INJ);
+	boolean_t bmcmon_enabled;
+
+	if ((g_bmc_fd = open(BMC_DEV, O_RDWR)) <= 0) {
+		log_warn_e("Could not open bmc device");
+		return (DMPE_FAILURE);
+	}
+
+	if (bmc_method(g_bmc_fd, &method) < 0) {
+		(void) close(g_bmc_fd);
+		log_warn("IPMI plugin: Could not determine bmc messaging "
+		    "interface!\n");
+		return (DMPE_FAILURE);
+	}
+
+	/*
+	 * Keep the bmc device open to prevent the driver from unloading
+	 * at a critical moment (e.g. when the BMC is not available).  If
+	 * we didn't do this, subsequent attempt at opening the bmc device
+	 * would fail because the bmc driver would not be able to find
+	 * the BMC (if it's resetting), and once the bmc's probe fails,
+	 * the system will not reload it automatically.
+	 */
+
+	sendrecv_fn = (method == BMC_PUTMSG_METHOD) ?
+	    ipmi_bmc_send_cmd_putmsg : ipmi_bmc_send_cmd_ioctl;
+
+	if (bmc_replay_list_init() != 0) {
+		return (DMPE_FAILURE);
+	}
+
+	if (errinjprop != NULL)
+		g_BMCErrorInjectionRate = strtol(errinjprop, 0, 0);
+
+	bmcmon_enabled = (monpropval != NULL && strtol(monpropval, 0, 0) != 0);
+
+	/*
+	 * Check to see if the BMC supports the Sun OEM uptime command
+	 * If it does, spawn a monitoring thread that will periodically poll
+	 * the bmc and check for bmc resets (since the bmc does not retain
+	 * the state across resets)
+	 */
+	if (bmcmon_enabled && bmc_get_uptime(NULL, NULL) == 0) {
+		if (bmc_cache_init() != 0) {
+			bmc_replay_list_fini();
+			return (DMPE_FAILURE);
+		}
+
+		g_bmc_monitor_active = B_TRUE;
+		g_bmcmon_done = B_FALSE;
+		g_bmcmon_tid = dm_plugin_thr_create(bmc_monitor_thread, NULL);
+	} else
+		g_bmc_monitor_active = B_FALSE;
+
+	return (DMPE_SUCCESS);
+}
+
+static dm_plugin_error_t
+ipmi_plugin_fru_update(const char *actionString, dm_fru_t *frup)
+{
+	return (action_do(actionString, frup, B_TRUE, NULL));
+}
+
+static dm_plugin_error_t
+ipmi_plugin_bind_handle(const char *actionString,
+    dm_plugin_action_handle_t *hdlp)
+{
+	return (action_do(actionString, NULL, B_FALSE,
+	    (ipmi_action_handle_t **)hdlp));
+}
+
+static dm_plugin_error_t
+ipmi_plugin_execute(dm_plugin_action_handle_t hdl)
+{
+	return (exec_action_handle((ipmi_action_handle_t *)hdl));
+}
+
+static dm_plugin_error_t
+ipmi_plugin_free_handle(dm_plugin_action_handle_t *hdlp)
+{
+	free_ipmi_action_handle((ipmi_action_handle_t **)hdlp);
+	return (DMPE_SUCCESS);
+}
+
+static dm_plugin_error_t
+ipmi_plugin_fini(void)
+{
+	if (g_bmc_monitor_active) {
+		g_bmcmon_done = B_TRUE;
+		dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
+		(void) pthread_cond_broadcast(&ipmi_cond);
+		dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
+
+		/* Signal the thread just in case it's blocked doing BMC I/O */
+		dm_plugin_thr_signal(g_bmcmon_tid);
+		dm_plugin_thr_destroy(g_bmcmon_tid);
+
+		/* Clean up cache lists */
+		bmc_cache_fini();
+	}
+	bmc_replay_list_fini();
+	(void) close(g_bmc_fd);
+	return (DMPE_SUCCESS);
+}
+
+/* ************** I P M I  S U P P O R T  F U N C T I O N S **************** */
+
+static dm_plugin_error_t
+ipmi_bmc_send_cmd(uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *datap, int datalen, bmc_rsp_t *rspp)
+{
+	dm_plugin_error_t rv;
+	static int inject_rep = 0;
+
+	if (g_BMCErrorInjectionRate > 0 &&
+	    (++inject_rep % g_BMCErrorInjectionRate) == 0) {
+		inject_rep = 0;
+		rspp->ccode = BMC_IPMI_COMMAND_TIMEOUT;
+		return (DMPE_FAILURE);
+	}
+
+	if (g_bmc_fd < 0)
+		bmc_reopen();
+
+	/* sendrecv_fn cannot be NULL at this point */
+	dm_assert(sendrecv_fn != NULL);
+	rv = (*sendrecv_fn)(g_bmc_fd, netfn, lun, cmd, datap, datalen, rspp);
+
+	return (rv);
+}
+
+static dm_plugin_error_t
+ipmi_bmc_send_cmd_ioctl(int fd, uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *datap, int datalen, bmc_rsp_t *rspp)
+{
+	struct strioctl istr;
+	struct bmc_reqrsp reqrsp;
+
+	if (datalen > SEND_MAX_PAYLOAD_SIZE) {
+		log_warn("IPMI Plugin: Data payload length (%d) is too "
+		    "large; it cannot be processed by this version of "
+		    "the bmc driver.\n", datalen);
+		return (DMPE_FAILURE);
+	}
+
+	(void) memset(&reqrsp, 0, sizeof (reqrsp));
+	reqrsp.req.fn = netfn;
+	reqrsp.req.lun = lun;
+	reqrsp.req.cmd = cmd;
+	reqrsp.req.datalength = (uint8_t)datalen;
+	(void) memcpy(reqrsp.req.data, datap, datalen);
+	reqrsp.rsp.datalength = RECV_MAX_PAYLOAD_SIZE;
+
+	istr.ic_cmd = IOCTL_IPMI_KCS_ACTION;
+	istr.ic_timout = 0;
+	istr.ic_dp = (char *)&reqrsp;
+	istr.ic_len = sizeof (struct bmc_reqrsp);
+
+	log_msg(MM_PLUGIN, "--\n");
+		dump_request(&reqrsp.req);
+	log_msg(MM_PLUGIN, "--\n");
+
+	if (ioctl(fd, I_STR, &istr) < 0) {
+		log_warn_e("IPMI Plugin: ioctl failure");
+		return (DMPE_FAILURE);
+	}
+
+	dump_response(&reqrsp.rsp);
+	log_msg(MM_PLUGIN, "--\n");
+
+	(void) memcpy(rspp, &reqrsp.rsp, sizeof (bmc_rsp_t));
+
+	/* Decrement for sizeof lun, cmd and ccode */
+	if (rspp->ccode || rspp->datalength == 0)
+		(void) memset(rspp->data, 0, sizeof (rspp->data));
+	else if (rspp->datalength > 3)
+		rspp->datalength -= 3;
+
+	return (DMPE_SUCCESS);
+}
+
+static dm_plugin_error_t
+ipmi_bmc_send_cmd_putmsg(int fd, uint8_t netfn, uint8_t lun, uint8_t cmd,
+    uint8_t *datap, int datalen, bmc_rsp_t *rspp)
+{
+	struct strbuf sb;
+	int flags = 0;
+	static uint32_t msg_seq = 0;
+
+	/*
+	 * The length of the message structure is equal to the size of the
+	 * bmc_req_t structure, PLUS any additional data space in excess of
+	 * the data space already reserved in the data member + <n> for
+	 * the rest of the members in the bmc_msg_t structure.
+	 */
+	int msgsz = offsetof(bmc_msg_t, msg) + sizeof (bmc_req_t) +
+		((datalen > SEND_MAX_PAYLOAD_SIZE) ?
+			(datalen - SEND_MAX_PAYLOAD_SIZE) : 0);
+	bmc_msg_t *msg = (bmc_msg_t *)dzmalloc(msgsz);
+	bmc_req_t *request = (bmc_req_t *)&msg->msg[0];
+	bmc_rsp_t *response;
+
+	msg->m_type = BMC_MSG_REQUEST;
+	msg->m_id = msg_seq++;
+	request->fn = netfn;
+	request->lun = lun;
+	request->cmd = cmd;
+	request->datalength = (uint8_t)datalen;
+	(void) memcpy(request->data, datap, datalen);
+
+	sb.len = msgsz;
+	sb.buf = (char *)msg;
+
+	log_msg(MM_PLUGIN, "--\n");
+	dump_request(request);
+	log_msg(MM_PLUGIN, "--\n");
+
+	if (putmsg(fd, NULL, &sb, 0) < 0) {
+		log_warn_e("IPMI Plugin: putmsg failure");
+		dfree(msg, msgsz);
+
+		/*
+		 * As a workaround for a bug in bmc, if an error was returned
+		 * from putmsg, we need to close the fd and reopen it to clear
+		 * the error state.
+		 */
+		bmc_reopen();
+
+		return (DMPE_FAILURE);
+	}
+
+	dfree(msg, msgsz);
+
+	sb.buf = dzmalloc(MESSAGE_BUFSIZE);
+	sb.maxlen = MESSAGE_BUFSIZE;
+
+	if (getmsg(fd, NULL, &sb, &flags) < 0) {
+		log_warn_e("IPMI Plugin: getmsg failure");
+		dfree(sb.buf, MESSAGE_BUFSIZE);
+		return (DMPE_FAILURE);
+	}
+
+	/*LINTED*/
+	msg = (bmc_msg_t *)sb.buf;
+
+	log_msg(MM_PLUGIN, "Got msg (id 0x%x) type 0x%x\n", msg->m_id,
+	    msg->m_type);
+
+
+	/* Did we get an error back from the stream? */
+	switch (msg->m_type) {
+
+	case BMC_MSG_RESPONSE:
+		response = (bmc_rsp_t *)&msg->msg[0];
+
+		dump_response(response);
+		log_msg(MM_PLUGIN, "--\n");
+
+		(void) memcpy(rspp, response, sizeof (bmc_rsp_t));
+
+		if (rspp->ccode || rspp->datalength == 0)
+			(void) memset(rspp->data, 0, sizeof (rspp->data));
+
+		break;
+
+	case BMC_MSG_ERROR:
+		/* In case of an error, msg->msg[0] has the error code */
+		log_warn("IPMI Plugin: bmc_send_cmd error: %s\n",
+		    strerror(msg->msg[0]));
+		break;
+
+	}
+
+	dfree(sb.buf, MESSAGE_BUFSIZE);
+	return (DMPE_SUCCESS);
+}
+
+/*
+ * Determine which interface to use.  Returns the interface method
+ * to use.
+ */
+static int
+bmc_method(int fd, int *if_type)
+{
+	struct strioctl istr;
+	int retval = 0;
+	uint8_t method = BMC_PUTMSG_METHOD;
+
+	istr.ic_cmd = IOCTL_IPMI_INTERFACE_METHOD;
+	istr.ic_timout = 0;
+	istr.ic_dp = (char *)&method;
+	istr.ic_len = 1;
+
+	/*
+	 * If the ioctl doesn't exist, we should get an EINVAL back.
+	 * Bail out on any other error.
+	 */
+	if (ioctl(fd, I_STR, &istr) < 0) {
+
+		if (errno != EINVAL)
+			retval = -1;
+		else
+			method = BMC_IOCTL_METHOD;
+	}
+
+	if (retval == 0)
+		*if_type = method;
+
+	return (retval);
+}
+
+static void
+dump_request(bmc_req_t *request)
+{
+	int i;
+
+	log_msg(MM_PLUGIN, "BMC req.fn         : 0x%x\n", request->fn);
+	log_msg(MM_PLUGIN, "BMC req.lun        : 0x%x\n", request->lun);
+	log_msg(MM_PLUGIN, "BMC req.cmd        : 0x%x\n", request->cmd);
+	log_msg(MM_PLUGIN, "BMC req.datalength : 0x%x\n", request->datalength);
+	log_msg(MM_PLUGIN, "BMC req.data       : ");
+
+	if (request->datalength > 0) {
+		for (i = 0; i < request->datalength; i++)
+			log_msg(MM_PLUGIN, "0x%x ", request->data[i]);
+	} else {
+		log_msg(MM_PLUGIN, "<NONE>");
+	}
+	log_msg(MM_PLUGIN, "\n");
+}
+
+static void
+dump_response(bmc_rsp_t *response)
+{
+	int i;
+
+	log_msg(MM_PLUGIN, "BMC rsp.fn         : 0x%x\n", response->fn);
+	log_msg(MM_PLUGIN, "BMC rsp.lun        : 0x%x\n", response->lun);
+	log_msg(MM_PLUGIN, "BMC rsp.cmd        : 0x%x\n", response->cmd);
+	log_msg(MM_PLUGIN, "BMC rsp.ccode      : 0x%x\n", response->ccode);
+	log_msg(MM_PLUGIN, "BMC rsp.datalength : 0x%x\n", response->datalength);
+	log_msg(MM_PLUGIN, "BMC rsp.data       : ");
+
+	if (response->datalength > 0) {
+		for (i = 0; i < response->datalength; i++)
+			log_msg(MM_PLUGIN, "0x%x ", response->data[i]);
+	} else {
+		log_msg(MM_PLUGIN, "<NONE>");
+	}
+	log_msg(MM_PLUGIN, "\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.h	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IPMI_PLUGIN_H
+#define	_IPMI_PLUGIN_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * IPMI Plugin definitions
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Controls whether to fire-up a thread to monitor the BMC's state
+ * and to update it with cached state information when a BMC reset
+ * is detected.
+ */
+#define	GLOBAL_PROP_IPMI_BMC_MON "ipmi-bmc-monitor-enable"
+#define	GLOBAL_PROP_IPMI_ERR_INJ "ipmi-error-inj-rate"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPMI_PLUGIN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,475 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Block comment that describes the contents of this file.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <pthread.h>
+
+#include "util.h"
+#include "sfx4500-disk.h"
+#include "plugin_mgr.h"
+
+static dm_plugin_t *plugin_list = NULL;
+static pthread_mutex_t plugin_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static dm_plugin_action_handle_impl_t *handle_list = NULL;
+static pthread_mutex_t handle_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static boolean_t
+safe_protocol_string(const char *protocol)
+{
+	while (*protocol != 0) {
+
+		if (!isalnum(*protocol))
+			return (B_FALSE);
+
+		protocol++;
+	}
+	return (B_TRUE);
+}
+
+/*
+ * Initialize the plugin.
+ * Returns DMPE_SUCCESS if the _init entry point of the plugin
+ * executed successfully, otherwise returns DMPE_FAILURE.
+ */
+static dm_plugin_error_t
+init_dm_plugin(dm_plugin_t *dmpip)
+{
+	dm_plugin_error_t ec;
+
+	if (dmpip->state != DMPS_INITED && dmpip->ops->_init) {
+		if ((ec = dmpip->ops->_init()) == DMPE_SUCCESS) {
+			dmpip->state = DMPS_INITED;
+		} else {
+			log_warn("_init failed for %s plugin; unloading it\n",
+			    dmpip->protocol);
+		}
+	} else if (dmpip->ops->_init == NULL)	/* No _init, no problem */
+		dmpip->state = DMPS_INITED;
+
+	return (ec);
+}
+
+static dm_plugin_t *
+new_dm_plugin(const char *protocol)
+{
+	dm_plugin_t *newpi = (dm_plugin_t *)dmalloc(sizeof (dm_plugin_t));
+
+	newpi->protocol = dstrdup(protocol);
+	newpi->state = DMPS_NONE;
+	newpi->ops = NULL;
+	newpi->next = NULL;
+
+	return (newpi);
+}
+
+static void
+unload_dm_plugin(dm_plugin_t *pluginp)
+{
+	pluginp->ops = NULL;
+}
+
+static void
+free_dm_plugin(dm_plugin_t **dmpipp)
+{
+	dm_plugin_t *dmpip = *dmpipp;
+	dm_plugin_error_t ec;
+
+	if (dmpip) {
+		if (dmpip->state == DMPS_INITED && dmpip->ops->_fini) {
+			ec = dmpip->ops->_fini();
+			if (ec != DMPE_SUCCESS) {
+				log_warn("_fini failed for plugin %s.\n",
+				    dmpip->protocol);
+			}
+		}
+
+		unload_dm_plugin(dmpip);
+
+		if (dmpip->protocol)
+			dstrfree(dmpip->protocol);
+
+		dmpip->state = DMPS_NONE;
+		dmpip->ops = NULL;
+
+		dfree(dmpip, sizeof (dm_plugin_t));
+		*dmpipp = NULL;
+	}
+}
+
+static boolean_t
+do_load_dm_plugin(dm_plugin_t *dmpip)
+{
+	boolean_t plugin_loaded = B_FALSE;
+	int len;
+	char *buf;
+
+	len = strlen(dmpip->protocol) + strlen(DM_PLUGIN_OPS_NAME) + 2;
+	buf = (char *)dmalloc(len);
+
+	/*
+	 * Currently, plugins are baked into the module, and the name of the
+	 * ops structure is formed by concatenating the plugin's protocol
+	 * with a static string:
+	 */
+
+	(void) snprintf(buf, len, "%s_%s", dmpip->protocol,
+	    DM_PLUGIN_OPS_NAME);
+
+	dmpip->ops = (dm_plugin_ops_t *)dlsym(RTLD_SELF, buf);
+
+	if (dmpip->ops != NULL) {
+		if (dmpip->ops->version > DM_PLUGIN_VERSION) {
+			log_warn("Plugin error: cannot handle "
+			    "plugin %s with version %d.\n",
+			    dmpip->protocol, dmpip->ops->version);
+		} else
+			plugin_loaded = B_TRUE;
+	} else {
+		log_warn("Plugin error: dlsym(%s) = NULL\n",
+		    buf);
+		unload_dm_plugin(dmpip);
+	}
+
+	dfree(buf, len);
+	return (plugin_loaded);
+}
+
+static dm_plugin_t *
+load_dm_plugin(const char *protocol)
+{
+	dm_plugin_t *dmpip = NULL;
+	boolean_t plugin_loaded = B_FALSE;
+
+	/*
+	 * Validate the protocol string -- if there are any non-alphanumeric
+	 * characters, it's not a valid protocol string.
+	 */
+	if (safe_protocol_string(protocol) == B_FALSE) {
+		log_warn("Invalid characters in plugin protocol `%s'.\n",
+		    protocol);
+		goto fpi_out;
+	}
+
+	dmpip = new_dm_plugin(protocol);
+
+	plugin_loaded = do_load_dm_plugin(dmpip);
+
+fpi_out:
+	if (plugin_loaded) {
+		dm_assert(dmpip != NULL);
+		dmpip->state = DMPS_LOADED;
+	} else if (!plugin_loaded && dmpip != NULL)
+		free_dm_plugin(&dmpip);
+
+	return (dmpip);
+}
+
+static char *
+extract_protocol(const char *action)
+{
+	char *s = strchr(action, PROTOCOL_SEPARATOR);
+	char *proto = NULL;
+	int len;
+	int i = 0;
+
+	/* The protocol is the string before the separator, but in lower-case */
+	if (s) {
+		len = (uintptr_t)s - (uintptr_t)action;
+		proto = (char *)dmalloc(len + 1);
+		while (i < len) {
+			proto[i] = tolower(action[i]);
+			i++;
+		}
+		proto[len] = 0;
+	}
+
+	return (proto);
+}
+
+static char *
+extract_action(const char *action)
+{
+	/* The action is the string after the separator */
+	char *s = strchr(action, PROTOCOL_SEPARATOR);
+
+	return (s ? (s + 1) : NULL);
+}
+
+static dm_plugin_t *
+load_and_init_dm_plugin(const char *protocol)
+{
+	dm_plugin_t *plugin = load_dm_plugin(protocol);
+
+	if (plugin) {
+		/* If _init succeeded, add the plugin to the list */
+		if (init_dm_plugin(plugin) == DMPE_SUCCESS) {
+			plugin->next = plugin_list;
+			plugin_list = plugin;
+		} else {
+			/* Otherwise, free it. */
+			free_dm_plugin(&plugin);
+		}
+	} else {
+		log_warn("Could not load `%s' plugin!\n",
+		    protocol);
+	}
+
+	return (plugin);
+}
+
+static dm_plugin_t *
+protocol_to_dm_plugin(const char *protocol)
+{
+	dm_plugin_t *plugin;
+
+	/*
+	 * Traversing the plugin list must be atomic with
+	 * respect to plugin loads
+	 */
+	dm_assert(pthread_mutex_lock(&plugin_list_mutex) == 0);
+
+	plugin = plugin_list;
+
+	while (plugin != NULL) {
+		if (strcmp(plugin->protocol, protocol) == 0) {
+			break;
+		}
+
+		plugin = plugin->next;
+	}
+
+	/* Wasn't found -- load, initialize, and return it */
+	plugin = (plugin == NULL) ? load_and_init_dm_plugin(protocol) :
+	    plugin;
+
+	dm_assert(pthread_mutex_unlock(&plugin_list_mutex) == 0);
+
+	return (plugin);
+}
+
+static dm_plugin_action_handle_impl_t *
+new_action_handle(const char *action, dm_plugin_t *pluginp)
+{
+	dm_plugin_action_handle_impl_t *hip;
+
+	hip = (dm_plugin_action_handle_impl_t *)dmalloc(
+	    sizeof (dm_plugin_action_handle_impl_t));
+
+	hip->actionString = dstrdup(action);
+	hip->plugin = pluginp;
+	hip->handle = (dm_plugin_action_handle_t)NULL;
+
+	/* Add the handle to the global list */
+	dm_assert(pthread_mutex_lock(&handle_list_mutex) == 0);
+	hip->next = handle_list;
+	handle_list = hip;
+	dm_assert(pthread_mutex_unlock(&handle_list_mutex) == 0);
+
+	return (hip);
+}
+
+static void
+free_action_handle(dm_plugin_action_handle_impl_t **hipp)
+{
+	dm_plugin_action_handle_impl_t *hip = *hipp;
+	dm_plugin_t *dmpip;
+
+	if (hip) {
+		if (hip->actionString)
+			dstrfree(hip->actionString);
+
+		dmpip = hip->plugin;
+
+		if (dmpip->state == DMPS_INITED &&
+		    dmpip->ops->indicator_free_handle)
+			if (dmpip->ops->indicator_free_handle(&hip->handle)
+			    != DMPE_SUCCESS) {
+				log_warn("indicator_free_handle failed for %s"
+				    " plugin\n",
+				    dmpip->protocol);
+			}
+
+		dfree(hip, sizeof (dm_plugin_action_handle_impl_t));
+		*hipp = NULL;
+	}
+}
+
+static dm_plugin_action_handle_impl_t *
+lookup_handle_by_action(const char *action)
+{
+	dm_plugin_action_handle_impl_t *handle;
+
+	dm_assert(pthread_mutex_lock(&handle_list_mutex) == 0);
+
+	handle = handle_list;
+
+	while (handle != NULL) {
+		if (strcmp(handle->actionString, action) == 0)
+			break;
+
+		handle = handle->next;
+	}
+
+	dm_assert(pthread_mutex_unlock(&handle_list_mutex) == 0);
+
+	return (handle);
+}
+
+int
+init_plugin_manager(void)
+{
+	return (0);
+}
+
+void
+cleanup_plugin_manager(void)
+{
+	dm_plugin_t *next_plugin;
+	dm_plugin_action_handle_impl_t *next_handle;
+
+	while (handle_list != NULL) {
+		next_handle = handle_list->next;
+
+		free_action_handle(&handle_list);
+
+		handle_list = next_handle;
+	}
+
+	while (plugin_list != NULL) {
+
+		next_plugin = plugin_list->next;
+
+		free_dm_plugin(&plugin_list);
+
+		plugin_list = next_plugin;
+	}
+}
+
+static dm_plugin_error_t
+bind_action_handle(dm_plugin_t *dmpip, const char *action,
+    dm_plugin_action_handle_t *hdlp)
+{
+	dm_plugin_action_handle_impl_t *hip;
+
+	hip = new_action_handle(action, dmpip);
+	*hdlp = hip;
+
+	dm_assert(dmpip->state == DMPS_INITED);
+	if (dmpip->ops->indicator_bind_handle)
+		return (dmpip->ops->indicator_bind_handle(action,
+		    &hip->handle));
+
+	return (DMPE_FAILURE);
+}
+
+dm_plugin_error_t
+dm_pm_update_fru(const char *action, dm_fru_t *frup)
+{
+	char *protocol = extract_protocol(action);	/* mem alloced here */
+	char *actionp = extract_action(action);
+	dm_plugin_t *dmpip;
+
+	if (protocol == NULL) {
+		log_warn("FRU update: Invalid protocol specified in action "
+		    "`%s'\n", action);
+		return (DMPE_FAILURE);
+	}
+
+	dmpip = protocol_to_dm_plugin(protocol);
+	dstrfree(protocol);
+
+	if (dmpip != NULL) {
+		dm_assert(dmpip->state == DMPS_INITED);
+		if (dmpip->ops->indicator_fru_update)
+			return (dmpip->ops->indicator_fru_update(actionp,
+			    frup));
+	}
+
+	return (DMPE_FAILURE);
+}
+
+dm_plugin_error_t
+dm_pm_indicator_execute(const char *action)
+{
+	dm_plugin_t *dmpip;
+	char *protocol = extract_protocol(action); /* memory allocated here */
+	char *actionp = extract_action(action);
+	dm_plugin_action_handle_impl_t *hip;
+
+	dmpip = protocol_to_dm_plugin(protocol);
+	dstrfree(protocol);
+
+	if (dmpip != NULL) {
+
+		if ((hip = lookup_handle_by_action(actionp)) == NULL) {
+			if (bind_action_handle(dmpip, actionp,
+			    (dm_plugin_action_handle_t *)&hip) != DMPE_SUCCESS)
+				return (DMPE_FAILURE);
+		}
+
+		dm_assert(dmpip->state == DMPS_INITED);
+		if (dmpip->ops->indicator_execute)
+			return (dmpip->ops->indicator_execute(hip->handle));
+	}
+
+	return (DMPE_FAILURE);
+}
+
+pthread_t
+dm_plugin_thr_create(void (*fn)(void *), void *arg)
+{
+	return (fmd_thr_create(g_fm_hdl, fn, arg));
+}
+
+void
+dm_plugin_thr_signal(pthread_t tid)
+{
+	fmd_thr_signal(g_fm_hdl, tid);
+}
+
+void
+dm_plugin_thr_destroy(pthread_t tid)
+{
+	fmd_thr_destroy(g_fm_hdl, tid);
+}
+
+const char *
+dm_plugin_prop_lookup(const char *propname)
+{
+	return (dm_prop_lookup(dm_global_proplist(), propname));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.h	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PLUGIN_MGR_H
+#define	_PLUGIN_MGR_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Declarations for the disk monitor plugin manager
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "dm_plugin.h"
+#include "ipmi_plugin.h"
+
+#define	DM_PLUGIN_DIR "/usr/lib/fm/fmd/plugins/dm"
+#define	DM_PLUGIN_PREFIX "dmpi_"
+#define	PROTOCOL_SEPARATOR ':'
+
+typedef enum {
+	DMPS_NONE,
+	DMPS_LOADED,
+	DMPS_INITED
+} dm_plugin_state_t;
+
+typedef struct dm_plugin {
+	char			*protocol;
+	dm_plugin_state_t	state;
+	dm_plugin_ops_t		*ops;
+	pthread_mutex_t		*mutex;
+	struct dm_plugin	*next;
+} dm_plugin_t;
+
+typedef struct dm_plugin_action_handle_impl {
+	dm_plugin_t				*plugin;
+	char					*actionString;
+	dm_plugin_action_handle_t		handle;
+	struct dm_plugin_action_handle_impl	*next;
+} dm_plugin_action_handle_impl_t;
+
+extern int init_plugin_manager(void);
+extern void cleanup_plugin_manager(void);
+
+extern dm_plugin_error_t dm_pm_update_fru(const char *action, dm_fru_t *frup);
+extern dm_plugin_error_t dm_pm_indicator_execute(const char *action);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PLUGIN_MGR_H */
--- a/usr/src/Makefile.lint	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/Makefile.lint	Sat Mar 10 17:17:25 2007 -0800
@@ -330,6 +330,7 @@
 	lib/libinetcfg \
 	lib/libinetsvc \
 	lib/libinetutil \
+	lib/libipmi \
 	lib/libipmp \
 	lib/libipp \
 	lib/libipsecutil \
--- a/usr/src/cmd/fm/modules/common/Makefile	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/cmd/fm/modules/common/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -20,13 +20,20 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
 
-SUBDIRS = cpumem-retire eversholt io-retire ip-transport snmp-trapgen	\
-	syslog-msgs zfs-diagnosis zfs-retire
+SUBDIRS = cpumem-retire		\
+	eversholt		\
+	io-retire		\
+	ip-transport		\
+	snmp-trapgen		\
+	sp-monitor		\
+	syslog-msgs		\
+	zfs-diagnosis		\
+	zfs-retire
 
 include ../../Makefile.subdirs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fm/modules/common/sp-monitor/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+MODULE = sp-monitor
+CLASS = common
+SRCS = sp_monitor.c
+
+include ../../Makefile.plugin
+
+LDLIBS += -lipmi -lsysevent
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fm/modules/common/sp-monitor/sp-monitor.conf	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,25 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fm/modules/common/sp-monitor/sp_monitor.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,205 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * /dev/bmc IPMI monitor
+ *
+ * The purpose of this module is to monitor the connection between the system
+ * and the service processor attached via /dev/bmc.  The module assumes the SP
+ * supports the Sun OEM uptime IPMI command.  If the BMC connection does not
+ * exist, or the uptime function is not implemented, then the module unloads
+ * without doing anything.
+ *
+ * When the module is first loaded, or a reset is detected, the module will
+ * generate the ESC_PLATFORM_SP_RESET sysevent as a system-wide notification to
+ * indicate that this event has occurred.
+ *
+ * Note that this event generation is not guaranteed to have a one-to-one
+ * correspondence with an SP reset.  There is no persistence, so if fmd is
+ * restarted we will generate this event again.  Thus the event only indicates
+ * the possibility that the SP has been reset.  This could be enhanced using fmd
+ * checkpoints to have some persistent state to avoid this scenario.  However,
+ * it currently serves the useful dual purpose of notifying consumers of system
+ * startup as well as SP reset through a single channel.
+ */
+
+#include <errno.h>
+#include <libipmi.h>
+#include <libsysevent.h>
+#include <string.h>
+#include <fm/fmd_api.h>
+#include <sys/sysevent/eventdefs.h>
+
+typedef struct sp_monitor {
+	ipmi_handle_t	*sm_hdl;
+	uint32_t	sm_seconds;
+	uint32_t	sm_generation;
+	hrtime_t	sm_interval;
+} sp_monitor_t;
+
+static void
+sp_post_sysevent(fmd_hdl_t *hdl)
+{
+	sp_monitor_t *smp = fmd_hdl_getspecific(hdl);
+	sysevent_id_t eid;
+
+	fmd_hdl_debug(hdl, "SP reset detected, posting sysevent");
+
+	if (sysevent_post_event(EC_PLATFORM, ESC_PLATFORM_SP_RESET,
+	    SUNW_VENDOR, "fmd", NULL, &eid) != 0) {
+		fmd_hdl_debug(hdl, "failed to send sysevent: %s",
+		    strerror(errno));
+		/*
+		 * We reset the seconds and generation so that the next time
+		 * through we will try to post the sysevent again.
+		 */
+		smp->sm_seconds = -1U;
+		smp->sm_generation = -1U;
+	}
+}
+
+/*ARGSUSED*/
+static void
+sp_timeout(fmd_hdl_t *hdl, id_t id, void *data)
+{
+	sp_monitor_t *smp = fmd_hdl_getspecific(hdl);
+	uint32_t seconds, generation;
+
+	if (ipmi_sunoem_uptime(smp->sm_hdl, &seconds, &generation) != 0) {
+		/*
+		 * Ignore uptime failures.  We will generate the appropriate
+		 * event when it comes back online.
+		 */
+		fmd_hdl_debug(hdl, "failed to get uptime: %s",
+		    ipmi_errmsg(smp->sm_hdl));
+	} else {
+		/*
+		 * We want to catch cases where the generation number is
+		 * explicitly reset, or when the SP configuration is reset after
+		 * a reboot (and the generation number is 0).  We also post a
+		 * sysevent when the module initially loads, since we can't be
+		 * sure if we missed a SP reset or not.
+		 */
+		if (seconds < smp->sm_seconds ||
+		    generation != smp->sm_generation ||
+		    smp->sm_seconds == 0)
+			sp_post_sysevent(hdl);
+
+		smp->sm_seconds = seconds;
+		smp->sm_generation = generation;
+	}
+
+	(void) fmd_timer_install(hdl, NULL, NULL, smp->sm_interval);
+}
+
+static const fmd_hdl_ops_t fmd_ops = {
+	NULL,		/* fmdo_recv */
+	sp_timeout,	/* fmdo_timeout */
+	NULL,		/* fmdo_close */
+	NULL,		/* fmdo_stats */
+	NULL,		/* fmdo_gc */
+};
+
+static const fmd_prop_t fmd_props[] = {
+	{ "interval", FMD_TYPE_TIME, "60sec" },
+	{ NULL, 0, NULL }
+};
+
+static const fmd_hdl_info_t fmd_info = {
+	"Service Processor Monitor", "1.0", &fmd_ops, fmd_props
+};
+
+void
+_fmd_init(fmd_hdl_t *hdl)
+{
+	sp_monitor_t *smp;
+	int error;
+	char *msg;
+
+	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
+		return;
+
+	smp = fmd_hdl_zalloc(hdl, sizeof (sp_monitor_t), FMD_SLEEP);
+	fmd_hdl_setspecific(hdl, smp);
+
+	if ((smp->sm_hdl = ipmi_open(&error, &msg)) == NULL) {
+		/*
+		 * If /dev/bmc doesn't exist on the system, then unload the
+		 * module without doing anything.
+		 */
+		if (error != EIPMI_BMC_OPEN_FAILED)
+			fmd_hdl_abort(hdl, "failed to initialize IPMI "
+			    "connection: %s\n", msg);
+		fmd_hdl_debug(hdl, "failed to load: no IPMI connection "
+		    "present");
+		fmd_hdl_free(hdl, smp, sizeof (sp_monitor_t));
+		fmd_hdl_unregister(hdl);
+		return;
+	}
+
+	/*
+	 * Attempt an initial uptime() call.  If the IPMI command is
+	 * unrecognized, then this is an unsupported platform and the module
+	 * should be unloaded.  Any other error is treated is transient failure.
+	 */
+	if ((error = ipmi_sunoem_uptime(smp->sm_hdl, &smp->sm_seconds,
+	    &smp->sm_generation)) != 0 &&
+	    ipmi_errno(smp->sm_hdl) == EIPMI_INVALID_COMMAND) {
+		fmd_hdl_debug(hdl, "failed to load: uptime command "
+		    "not supported");
+		ipmi_close(smp->sm_hdl);
+		fmd_hdl_free(hdl, smp, sizeof (sp_monitor_t));
+		fmd_hdl_unregister(hdl);
+		return;
+	}
+
+	smp->sm_interval = fmd_prop_get_int64(hdl, "interval");
+
+	if (error == 0)
+		fmd_hdl_debug(hdl, "successfully loaded, uptime = %u seconds "
+		    "(generation %u)", smp->sm_seconds, smp->sm_generation);
+	else
+		fmd_hdl_debug(hdl, "successfully loaded, but uptime call "
+		    "failed: %s", ipmi_errmsg(smp->sm_hdl));
+
+	/*
+	 * Setup the recurring timer.
+	 */
+	(void) fmd_timer_install(hdl, NULL, NULL, 0);
+}
+
+void
+_fmd_fini(fmd_hdl_t *hdl)
+{
+	sp_monitor_t *smp = fmd_hdl_getspecific(hdl);
+
+	if (smp) {
+		ipmi_close(smp->sm_hdl);
+		fmd_hdl_free(hdl, smp, sizeof (sp_monitor_t));
+	}
+}
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/Makefile	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -28,11 +28,11 @@
 CLASS = arch
 ARCH = i86pc
 SRCS = sfx4500-disk.c diskmon_conf.c topo_gather.c \
-	fault_mgr.c hotplug_mgr.c ipmi_plugin.c \
-	plugin_mgr.c schg_mgr.c fault_analyze.c scsi_util.c util.c
+	fault_mgr.c hotplug_mgr.c dm_platform.c \
+	schg_mgr.c fault_analyze.c scsi_util.c util.c
 
 include ../../Makefile.plugin
 LINTFLAGS += -I. -I$(SRC)/lib/fm/topo/modules/i86pc/sata -L$(ROOT)/usr/lib/fm
 CFLAGS += -I. -I$(SRC)/lib/fm/topo/modules/i86pc/sata
-LDLIBS += -lsysevent -lnvpair -lsmbios -lcfgadm -ltopo -luutil
+LDLIBS += -lsysevent -lnvpair -lsmbios -lcfgadm -ltopo -luutil -lipmi
 LDFLAGS += -L$(ROOT)/usr/lib/fm -R/usr/lib/fm
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_platform.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,487 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <ctype.h>
+#include <libipmi.h>
+#include <libnvpair.h>
+#include <libuutil.h>
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "diskmon_conf.h"
+#include "dm_platform.h"
+#include "util.h"
+
+/* For the purposes of disk capacity, a <X>B is 1000x, not 1024x */
+#define	ONE_KILOBYTE 1000.0
+#define	ONE_MEGABYTE (ONE_KILOBYTE * 1000)
+#define	ONE_GIGABYTE (ONE_MEGABYTE * 1000)
+#define	ONE_TERABYTE (ONE_GIGABYTE * 1000)
+#define	ONE_PETABYTE (ONE_TERABYTE * 1000)
+
+static ipmi_handle_t *g_ipmi_hdl;
+
+typedef enum {
+	IPMI_CACHE_SENSOR,
+	IPMI_CACHE_FRU
+} ipmi_cache_type_t;
+
+typedef struct ipmi_cache_entry {
+	ipmi_cache_type_t			ic_type;
+	uu_list_node_t				ic_node;
+	union {
+		ipmi_set_sensor_reading_t	ic_sensor;
+		ipmi_sunoem_fru_t		ic_fru;
+	} ic_data;
+} ipmi_cache_entry_t;
+
+static pthread_mutex_t g_ipmi_mtx = PTHREAD_MUTEX_INITIALIZER;
+static uu_list_pool_t *g_ipmi_cache_pool;
+static uu_list_t *g_ipmi_cache;
+
+/*
+ * The textual strings that are used in the actions may be one of the
+ * following forms:
+ *
+ * [1] `fru gid=<n> hdd=<m>'
+ * [2] `sensor id=<x> assert=<y> deassert=<z>'
+ *
+ * The generic parser will take a string and spit out the first token
+ * (e.g. `fru' or `sensor') and an nvlist that contains the key-value
+ * pairs in the rest of the string.  The assumption is that there are
+ * no embedded spaces or tabs in the keys or values.
+ */
+
+static boolean_t
+isnumber(const char *str)
+{
+	boolean_t hex = B_FALSE;
+	int digits = 0;
+
+	if (strncasecmp(str, "0x", 2) == 0) {
+		hex = B_TRUE;
+		str += 2;
+	} else if (*str == '-' || *str == '+') {
+		str++;
+	}
+
+	while (*str != 0) {
+		if ((hex && !isxdigit(*str)) ||
+		    (!hex && !isdigit(*str))) {
+			return (B_FALSE);
+		}
+
+		str++;
+		digits++;
+	}
+
+	return ((digits == 0) ? B_FALSE : B_TRUE);
+}
+
+static void
+tolowerString(char *str)
+{
+	while (*str != 0) {
+		*str = tolower(*str);
+		str++;
+	}
+}
+
+static boolean_t
+parse_action_string(const char *actionString, char **cmdp, nvlist_t **propsp)
+{
+	char *action;
+	char *tok, *lasts, *eq;
+	int actionlen;
+	boolean_t rv = B_TRUE;
+
+	if (nvlist_alloc(propsp, NV_UNIQUE_NAME, 0) != 0)
+		return (B_FALSE);
+
+	actionlen = strlen(actionString) + 1;
+	action = dstrdup(actionString);
+
+	*cmdp = NULL;
+
+	if ((tok = strtok_r(action, " \t", &lasts)) != NULL) {
+
+		*cmdp = dstrdup(tok);
+
+		while (rv && (tok = strtok_r(NULL, " \t", &lasts)) != NULL) {
+
+			/* Look for a name=val construct */
+			if ((eq = strchr(tok, '=')) != NULL && eq[1] != 0) {
+
+				*eq = 0;
+				eq++;
+
+				/*
+				 * Convert token to lowercase to preserve
+				 * case-insensitivity, because nvlist doesn't
+				 * do case-insensitive lookups
+				 */
+				tolowerString(tok);
+
+				if (isnumber(eq)) {
+					/* Integer property */
+
+					if (nvlist_add_uint64(*propsp, tok,
+					    strtoull(eq, NULL, 0)) != 0)
+						rv = B_FALSE;
+				} else {
+					/* String property */
+
+					if (nvlist_add_string(*propsp, tok,
+					    eq) != 0)
+						rv = B_FALSE;
+				}
+			} else if (eq == NULL) {
+				/* Boolean property */
+				if (nvlist_add_boolean(*propsp, tok) != 0)
+					rv = B_FALSE;
+			} else /* Parse error (`X=' is invalid) */
+				rv = B_FALSE;
+		}
+	} else
+		rv = B_FALSE;
+
+	dfree(action, actionlen);
+	if (!rv) {
+		if (*cmdp) {
+			dstrfree(*cmdp);
+			*cmdp = NULL;
+		}
+		nvlist_free(*propsp);
+		*propsp = NULL;
+	}
+	return (rv);
+}
+
+static int
+platform_update_fru(nvlist_t *props, dm_fru_t *frup)
+{
+	uint64_t gid, hdd;
+	ipmi_sunoem_fru_t fru;
+	char *buf;
+	ipmi_cache_entry_t *entry;
+
+	if (nvlist_lookup_uint64(props, "gid", &gid) != 0 ||
+	    nvlist_lookup_uint64(props, "hdd", &hdd) != 0) {
+		return (-1);
+	}
+
+	fru.isf_type = (uint8_t)gid;
+	fru.isf_id = (uint8_t)hdd;
+
+	buf = (char *)dzmalloc(sizeof (fru.isf_data.disk.isf_capacity) + 1);
+
+	(void) memcpy(fru.isf_data.disk.isf_manufacturer, frup->manuf,
+	    MIN(sizeof (fru.isf_data.disk.isf_manufacturer),
+	    sizeof (frup->manuf)));
+	(void) memcpy(fru.isf_data.disk.isf_model, frup->model,
+	    MIN(sizeof (fru.isf_data.disk.isf_model), sizeof (frup->model)));
+	(void) memcpy(fru.isf_data.disk.isf_serial, frup->serial,
+	    MIN(sizeof (fru.isf_data.disk.isf_serial), sizeof (frup->serial)));
+	(void) memcpy(fru.isf_data.disk.isf_version, frup->rev,
+	    MIN(sizeof (fru.isf_data.disk.isf_version), sizeof (frup->rev)));
+	/*
+	 * Print the size of the disk to a temporary buffer whose size is
+	 * 1 more than the size of the buffer in the ipmi request data
+	 * structure, so we can get the full 8 characters (instead of 7 + NUL)
+	 */
+	(void) snprintf(buf, sizeof (fru.isf_data.disk.isf_capacity) + 1,
+	    "%.1f%s",
+	    frup->size_in_bytes >= ONE_PETABYTE ?
+	    (frup->size_in_bytes / ONE_PETABYTE) :
+	    (frup->size_in_bytes >= ONE_TERABYTE ?
+	    (frup->size_in_bytes / ONE_TERABYTE) :
+	    (frup->size_in_bytes >= ONE_GIGABYTE ?
+	    (frup->size_in_bytes / ONE_GIGABYTE) :
+	    (frup->size_in_bytes >= ONE_MEGABYTE ?
+	    (frup->size_in_bytes / ONE_MEGABYTE) :
+	    (frup->size_in_bytes / ONE_KILOBYTE)))),
+
+	    frup->size_in_bytes >= ONE_PETABYTE ? "PB" :
+	    (frup->size_in_bytes >= ONE_TERABYTE ? "TB" :
+	    (frup->size_in_bytes >= ONE_GIGABYTE ? "GB" :
+	    (frup->size_in_bytes >= ONE_MEGABYTE ? "MB" :
+	    "KB"))));
+	(void) memcpy(fru.isf_data.disk.isf_capacity, buf,
+	    sizeof (fru.isf_data.disk.isf_capacity));
+
+	dfree(buf, sizeof (fru.isf_data.disk.isf_capacity) + 1);
+
+	if (ipmi_sunoem_update_fru(g_ipmi_hdl, &fru) != 0)
+		return (-1);
+
+	/* find a cache entry or create one if necessary */
+	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
+	    entry = uu_list_next(g_ipmi_cache, entry)) {
+		if (entry->ic_type == IPMI_CACHE_FRU &&
+		    entry->ic_data.ic_fru.isf_type == gid &&
+		    entry->ic_data.ic_fru.isf_id == hdd)
+			break;
+	}
+
+	if (entry == NULL) {
+		entry = dzmalloc(sizeof (ipmi_cache_entry_t));
+		entry->ic_type = IPMI_CACHE_FRU;
+		(void) uu_list_insert_before(g_ipmi_cache, NULL, entry);
+	}
+
+	(void) memcpy(&entry->ic_data.ic_fru, &fru, sizeof (fru));
+
+	return (0);
+}
+
+static int
+platform_set_sensor(nvlist_t *props)
+{
+	uint64_t assertmask = 0, deassertmask = 0, sid;
+	boolean_t am_present, dam_present;
+	ipmi_set_sensor_reading_t sr, *sp;
+	ipmi_cache_entry_t *entry;
+	int ret;
+
+	/* We need at least 2 properties: `sid' and (`amask' || `dmask'): */
+	am_present = nvlist_lookup_uint64(props, "amask", &assertmask) == 0;
+	dam_present = nvlist_lookup_uint64(props, "dmask", &deassertmask) == 0;
+
+	if (nvlist_lookup_uint64(props, "sid", &sid) != 0 ||
+	    (!am_present && !dam_present)) {
+		return (-1);
+	}
+
+	if (sid > UINT8_MAX) {
+		log_warn("IPMI Plugin: Invalid sensor id `0x%llx'.\n",
+		    (longlong_t)sid);
+		return (-1);
+	} else if (assertmask > UINT16_MAX) {
+		log_warn("IPMI Plugin: Invalid assertion mask `0x%llx'.\n",
+		    (longlong_t)assertmask);
+		return (-1);
+	} else if (assertmask > UINT16_MAX) {
+		log_warn("IPMI Plugin: Invalid deassertion mask `0x%llx'.\n",
+		    (longlong_t)deassertmask);
+		return (-1);
+	}
+
+	(void) memset(&sr, '\0', sizeof (sr));
+	sr.iss_id = (uint8_t)sid;
+	if (am_present) {
+		sr.iss_assert_op = IPMI_SENSOR_OP_SET;
+		sr.iss_assert_state = (uint16_t)assertmask;
+	}
+	if (dam_present) {
+		sr.iss_deassrt_op = IPMI_SENSOR_OP_SET;
+		sr.iss_deassert_state = (uint16_t)deassertmask;
+	}
+
+	ret = ipmi_set_sensor_reading(g_ipmi_hdl, &sr);
+
+	/* find a cache entry or create one if necessary */
+	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
+	    entry = uu_list_next(g_ipmi_cache, entry)) {
+		if (entry->ic_type == IPMI_CACHE_SENSOR &&
+		    entry->ic_data.ic_sensor.iss_id == (uint8_t)sid)
+			break;
+	}
+
+	if (entry == NULL) {
+		entry = dzmalloc(sizeof (ipmi_cache_entry_t));
+		entry->ic_type = IPMI_CACHE_SENSOR;
+		(void) uu_list_insert_before(g_ipmi_cache, NULL, entry);
+		entry->ic_data.ic_sensor.iss_id = (uint8_t)sid;
+		entry->ic_data.ic_sensor.iss_assert_op = IPMI_SENSOR_OP_SET;
+		entry->ic_data.ic_sensor.iss_deassrt_op = IPMI_SENSOR_OP_SET;
+	}
+	sp = &entry->ic_data.ic_sensor;
+
+	if (am_present) {
+		sp->iss_assert_state |= assertmask;
+		sp->iss_deassert_state &= ~assertmask;
+	}
+	if (dam_present) {
+		sp->iss_deassert_state |= deassertmask;
+		sp->iss_assert_state &= ~deassertmask;
+	}
+
+	return (ret);
+}
+
+#define	PROTOCOL_SEPARATOR ':'
+
+static char *
+extract_protocol(const char *action)
+{
+	char *s = strchr(action, PROTOCOL_SEPARATOR);
+	char *proto = NULL;
+	int len;
+	int i = 0;
+
+	/* The protocol is the string before the separator, but in lower-case */
+	if (s) {
+		len = (uintptr_t)s - (uintptr_t)action;
+		proto = (char *)dmalloc(len + 1);
+		while (i < len) {
+			proto[i] = tolower(action[i]);
+			i++;
+		}
+		proto[len] = 0;
+	}
+
+	return (proto);
+}
+
+static char *
+extract_action(const char *action)
+{
+	/* The action is the string after the separator */
+	char *s = strchr(action, PROTOCOL_SEPARATOR);
+
+	return (s ? (s + 1) : NULL);
+}
+
+static int
+do_action(const char *action, dm_fru_t *fru)
+{
+	nvlist_t	*props;
+	char		*cmd;
+	int rv = -1;
+	char		*protocol = extract_protocol(action);
+	char		*actionp = extract_action(action);
+
+	if (strcmp(protocol, "ipmi") != 0) {
+		log_err("unknown protocol '%s'\n", protocol);
+		dstrfree(protocol);
+		return (-1);
+	}
+
+	dstrfree(protocol);
+
+	(void) pthread_mutex_lock(&g_ipmi_mtx);
+	if (parse_action_string(actionp, &cmd, &props)) {
+		if (strcmp(cmd, "fru") == 0) {
+			rv = platform_update_fru(props, fru);
+		} else if (strcmp(cmd, "state") == 0) {
+			rv = platform_set_sensor(props);
+		} else {
+			log_err("unknown platform action '%s'\n", cmd);
+		}
+		dstrfree(cmd);
+		nvlist_free(props);
+	}
+	(void) pthread_mutex_unlock(&g_ipmi_mtx);
+
+	return (rv);
+}
+
+int
+dm_platform_update_fru(const char *action, dm_fru_t *fru)
+{
+	return (do_action(action, fru));
+}
+
+int
+dm_platform_indicator_execute(const char *action)
+{
+	return (do_action(action, NULL));
+}
+
+int
+dm_platform_resync(void)
+{
+	ipmi_cache_entry_t *entry;
+	int rv = 0;
+
+	(void) pthread_mutex_lock(&g_ipmi_mtx);
+
+	/*
+	 * Called when the SP is reset, as the sensor/FRU state is not
+	 * maintained across reboots.  Note that we must update the FRU
+	 * information first, as certain sensor states prevent this from
+	 * working.
+	 */
+	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
+	    entry = uu_list_next(g_ipmi_cache, entry)) {
+		if (entry->ic_type == IPMI_CACHE_FRU)
+			rv |= ipmi_sunoem_update_fru(g_ipmi_hdl,
+			    &entry->ic_data.ic_fru);
+	}
+
+	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
+	    entry = uu_list_next(g_ipmi_cache, entry)) {
+		if (entry->ic_type == IPMI_CACHE_SENSOR)
+			rv |= ipmi_set_sensor_reading(g_ipmi_hdl,
+			    &entry->ic_data.ic_sensor);
+	}
+
+	(void) pthread_mutex_unlock(&g_ipmi_mtx);
+	return (rv);
+}
+
+int
+dm_platform_init(void)
+{
+	int err;
+	char *msg;
+
+	if ((g_ipmi_hdl = ipmi_open(&err, &msg)) == NULL) {
+		log_warn("Failed to load libipmi: %s\n", msg);
+		return (-1);
+	}
+
+	if ((g_ipmi_cache_pool = uu_list_pool_create(
+	    "ipmi_cache", sizeof (ipmi_cache_entry_t),
+	    offsetof(ipmi_cache_entry_t, ic_node), NULL, 0)) == NULL)
+		return (-1);
+
+	if ((g_ipmi_cache = uu_list_create(g_ipmi_cache_pool, NULL, 0))
+	    == NULL)
+		return (-1);
+
+	return (0);
+}
+
+void
+dm_platform_fini(void)
+{
+	if (g_ipmi_hdl)
+		ipmi_close(g_ipmi_hdl);
+	if (g_ipmi_cache) {
+		ipmi_cache_entry_t *entry;
+
+		while ((entry = uu_list_first(g_ipmi_cache)) != NULL) {
+			uu_list_remove(g_ipmi_cache, entry);
+			dfree(entry, sizeof (*entry));
+		}
+		uu_list_destroy(g_ipmi_cache);
+	}
+	if (g_ipmi_cache_pool)
+		uu_list_pool_destroy(g_ipmi_cache_pool);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_platform.h	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,48 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_DM_PLATFORM_H
+#define	_DM_PLATFORM_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "dm_types.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int dm_platform_update_fru(const char *action, dm_fru_t *fru);
+int dm_platform_indicator_execute(const char *action);
+int dm_platform_resync(void);
+
+int dm_platform_init(void);
+void dm_platform_fini(void);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _DM_PLATFORM_H */
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/dm_plugin.h	Sat Mar 10 06:42:50 2007 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _DM_PLUGIN_H
-#define	_DM_PLUGIN_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * Declarations for the disk monitor plugin interface
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "dm_types.h"
-
-/*
- * The name of the symbol that is of type dm_plugin_ops_t that points to the
- * implementation of the plugin.
- */
-#define	DM_PLUGIN_OPS_NAME "dm_plugin_ops"
-
-#define	DM_PLUGIN_VERSION_1	1
-#define	DM_PLUGIN_VERSION DM_PLUGIN_VERSION_1
-
-typedef enum {
-	DMPE_SUCCESS,
-	DMPE_FAILURE
-} dm_plugin_error_t;
-
-typedef void *dm_plugin_action_handle_t;
-
-typedef struct dm_plugin_ops {
-	int			version;
-	dm_plugin_error_t	(*_init)(void);
-	dm_plugin_error_t	(*indicator_fru_update)(
-	    const char *actionString, dm_fru_t *frup);
-	dm_plugin_error_t	(*indicator_bind_handle)(
-	    const char *actionString, dm_plugin_action_handle_t *hdlp);
-	dm_plugin_error_t	(*indicator_execute)(
-	    dm_plugin_action_handle_t hdl);
-	dm_plugin_error_t	(*indicator_free_handle)(
-	    dm_plugin_action_handle_t *hdlp);
-	dm_plugin_error_t	(*_fini)(void);
-} dm_plugin_ops_t;
-
-extern const char *dm_plugin_prop_lookup(const char *propname);
-extern pthread_t dm_plugin_thr_create(void (*fn)(void *), void *);
-extern void dm_plugin_thr_signal(pthread_t);
-extern void dm_plugin_thr_destroy(pthread_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DM_PLUGIN_H */
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/hotplug_mgr.c	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/hotplug_mgr.c	Sat Mar 10 17:17:25 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -48,6 +48,7 @@
 #include "sfx4500-disk.h"
 #include "hotplug_mgr.h"
 #include "schg_mgr.h"
+#include "dm_platform.h"
 
 typedef struct sysevent_event {
 	sysevent_t	*evp;
@@ -434,16 +435,24 @@
 {
 	char		*class_name;
 	char		*pub;
+	char		*subclass = sysevent_get_subclass_name(dupev);
 	diskmon_t	*diskp;
 
 	class_name = sysevent_get_class_name(dupev);
 	log_msg(MM_HPMGR, "****EVENT: %s %s (by %s)\n", class_name,
-	    sysevent_get_subclass_name(dupev),
+	    subclass,
 	    ((pub = sysevent_get_pub_name(dupev)) != NULL) ? pub : "UNKNOWN");
 
 	if (pub)
 		free(pub);
 
+	if (strcmp(class_name, EC_PLATFORM) == 0 &&
+	    strcmp(subclass, ESC_PLATFORM_SP_RESET) == 0) {
+		if (dm_platform_resync() != 0)
+			log_warn("failed to resync SP platform\n");
+		return;
+	}
+
 	/*
 	 * We will handle this event if the event's target matches one of the
 	 * disks we're monitoring
@@ -538,6 +547,9 @@
 	const char *dr_subclasses[] = {
 		ESC_DR_AP_STATE_CHANGE
 	};
+	const char *platform_subclasses[] = {
+		ESC_PLATFORM_SP_RESET
+	};
 
 	if ((sysevent_handle = sysevent_bind_handle(event_handler)) == NULL) {
 		rv = errno;
@@ -565,8 +577,20 @@
 		fini_sysevents();
 
 		rv = -1;
+	} else if (sysevent_subscribe_event(sysevent_handle, EC_PLATFORM,
+	    platform_subclasses, 1) != 0) {
+
+		log_err("Could not initialize the hotplug manager "
+		    "sysevent_subscribe_event(event class = EC_PLATFORM) "
+		    "failure");
+
+		/* Unsubscribe from all sysevents in the event of a failure */
+		fini_sysevents();
+
+		rv = -1;
 	}
 
+
 	return (rv);
 }
 
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.c	Sat Mar 10 06:42:50 2007 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1742 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * IPMI Plugin for the disk hotplug & fault monitor
- */
-
-#include <sys/types.h>
-#include <sys/byteorder.h>
-#include <sys/stat.h>
-#include <sys/stropts.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stddef.h>
-#include <stropts.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <pthread.h>
-#include <ctype.h>
-#include <limits.h>
-#include <utility.h>
-#include <libnvpair.h>
-#include <sys/bmc_intf.h>
-#include <libuutil.h>
-
-#include "dm_plugin.h"
-#include "util.h"
-#include "ipmi_plugin.h"
-
-#define	BMC_CHECK_UPTIME_INTERVAL	60	/* seconds */
-#define	MESSAGE_BUFSIZE 1024
-#define	BMC_DEV "/dev/bmc"
-
-#define	STRUCT_MIN_SIZE(t, o) offsetof(t, o)
-#define	TDZMALLOC(sz) ((sz *)dzmalloc(sizeof (sz)))
-#define	TDMALLOC(sz) ((sz *)dmalloc(sizeof (sz)))
-
-/* For the purposes of disk capacity, a <X>B is 1000x, not 1024x */
-#define	ONE_KILOBYTE 1000.0
-#define	ONE_MEGABYTE (ONE_KILOBYTE * 1000)
-#define	ONE_GIGABYTE (ONE_MEGABYTE * 1000)
-#define	ONE_TERABYTE (ONE_GIGABYTE * 1000)
-#define	ONE_PETABYTE (ONE_TERABYTE * 1000)
-
-/* IPMI Command Code definitions */
-#define	IPMI_NETFN_OEM			0x2E
-#define	IPMI_CMD_GET_UPTIME		0x08
-#define	IPMI_CMD_FRU_UPDATE		0x16
-#define	IPMI_CMD_GET_SENSOR_READING	0x2d
-#define	IPMI_CMD_SET_SENSOR_READING	0x30
-#define	IPMI_CMD_ADD_SEL_ENTRY		0x44
-
-/* IPMI Request types supported by this plugin: */
-#pragma pack(1)
-struct ipmi_sensor_control {
-	uint8_t		sensor_number;
-	uint8_t		operation;	/* ASSERT_OP | DEASSERT_OP | Both */
-#define	SC_ASSERT_OP	0x20
-#define	SC_DEASSERT_OP	0x08
-	uint8_t		sensor_reading;	/* UNUSED */
-	/*
-	 * The following two fields are stored and sent to the bmc in
-	 * little-endian form
-	 */
-	uint16_t	assert_states;
-	uint16_t	deassert_states;
-#define	STATE_RESERVED_BITS ((uint16_t)0x8000)
-};
-
-/*
- * Virtual sensor format for FRU data (Sun OEM)
- */
-struct ipmi_fru_update {
-	uint8_t		global_id;
-	uint8_t		disk_number;	/* Disk number 0-47 on the X4500 */
-	uint8_t		data_length;
-	char		d_manuf[16];
-	char		d_model[28];
-	char		d_serial[20];
-	char		d_firmware[8];
-	char		d_capacity[16];
-};
-
-struct ipmi_sel_entry {
-	uint16_t	recid;		/* Don't care -- bmc will overwrite */
-	uint8_t		type;		/* 0xc0 = OEM SEL Entry */
-#define	SEL_TYPE_OEM	0xC0
-	uint32_t	timestamp;	/* Don't care -- bmc will overwrite */
-	uint8_t		manuf_id[3];
-	uint8_t		oem_defined[6];
-};
-
-struct ipmi_sensor_reading {
-	uint8_t		reading;
-
-	uint8_t		reserved		: 5,
-			data_unavailable	: 1,
-			scanning_enabled	: 1,
-			event_messages_enabled	: 1;
-
-	uint8_t		states_0_7;
-	uint8_t		states_8_14;	/* High bit is reserved */
-#define	sensor_reading_optional_field_start	states_0_7
-};
-
-/*
- * The following structure's members is returned in BIG-ENDIAN form.
- */
-struct bmc_uptime_info {
-	uint32_t	uptime_seconds;
-	uint32_t	incarnation;
-};
-#pragma pack()
-/* End of request types supported */
-
-typedef dm_plugin_error_t (*ipmi_packet_setup_fn_t)(nvlist_t *props,
-    void **databpp, int *datablen, void *arg);
-
-struct ipmi_cmd_setup {
-	const char 		*name;
-	ipmi_packet_setup_fn_t	setupfn;
-	uint8_t			netfn;
-	uint8_t			lun;
-	uint8_t			cmd;
-};
-
-typedef struct ipmi_action_handle {
-	uint8_t		netfn;
-	uint8_t		lun;
-	uint8_t		cmd;
-	void		*databp;
-	int		datablen;
-} ipmi_action_handle_t;
-
-typedef enum {
-	CACHE_ENT_FIRST,
-	CACHE_ENT_FRUINFO,
-	CACHE_ENT_SENSORCTL,
-	CACHE_ENT_LAST
-} bmc_cache_ent_type_t;
-
-typedef struct bmc_cache_ent {
-	bmc_cache_ent_type_t		type;
-	union {
-		struct ipmi_fru_update		fru_Info;
-		/*
-		 * The deasserted field is not used
-		 * to cache data in the sensor_control
-		 * structure (we cache asserted states):
-		 */
-		struct ipmi_sensor_control	sensor_Ctl;
-	} u;
-	uu_list_node_t			un_node;
-#define	fruInfo		u.fru_Info
-#define	sensorCtl	u.sensor_Ctl
-} bmc_cache_ent_t;
-
-typedef struct bmc_replay_list_ent {
-	uint8_t		netfn;
-	uint8_t		lun;
-	uint8_t		cmd;
-	uint8_t		*databp;
-	int		datablen;
-	uu_list_node_t	un_node;
-} bmc_replay_list_ent_t;
-
-/*
- * The ipmi_mutex protects the bmc state$ and serializes bmc device access
- */
-static pthread_mutex_t ipmi_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t ipmi_cond = PTHREAD_COND_INITIALIZER;
-static dm_plugin_error_t (*sendrecv_fn)(int fd, uint8_t netfn, uint8_t lun,
-    uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp) = NULL;
-
-
-static int bmc_method(int fd, int *if_type);
-static void dump_request(bmc_req_t *request);
-static void dump_response(bmc_rsp_t *response);
-static dm_plugin_error_t ipmi_bmc_send_cmd_ioctl(int fd, uint8_t netfn,
-    uint8_t lun, uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp);
-static dm_plugin_error_t ipmi_bmc_send_cmd_putmsg(int fd, uint8_t netfn,
-    uint8_t lun, uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp);
-static dm_plugin_error_t ipmi_bmc_send_cmd(uint8_t netfn, uint8_t lun,
-    uint8_t cmd, uint8_t *datap, int datalen, bmc_rsp_t *rspp);
-
-/* IPMI Command Buffer-Setup Functions: */
-static dm_plugin_error_t fru_setupfn(nvlist_t *props, void **databpp,
-    int *datablen, void *arg);
-static dm_plugin_error_t state_setupfn(nvlist_t *props, void **databpp,
-    int *datablen, void *arg);
-static dm_plugin_error_t sel_setupfn(nvlist_t *props, void **databpp,
-    int *datablen, void *arg);
-
-/* BMC Monitor and BMC Cache functions: */
-static int bmc_cache_init(void);
-static void bmc_cache_fini(void);
-static int bmc_state_refresh(boolean_t *refreshed);
-static int bmc_state_refresh_from_cache(void);
-static bmc_cache_ent_t *bmc_state_cache_lookup(uint8_t netfn, uint8_t lun,
-    uint8_t cmd, uint8_t *databp, int datablen);
-static void bmc_state_cache_update(uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *databp, int datablen);
-static void bmc_monitor_thread(void *arg);
-
-/* BMC Replay List functions: */
-static int bmc_replay_list_init(void);
-static void bmc_replay_list_fini(void);
-static int bmc_replay_list_execute(void);
-static void bmc_replay_list_add(uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *databp, int datablen);
-
-/* IPMI commands used internally */
-static dm_plugin_error_t bmc_get_uptime(uint32_t *uptime, uint32_t *bootgen);
-static dm_plugin_error_t bmc_get_sensor(uint8_t sensor_id, uint16_t *assrtd,
-    boolean_t *updated_flag);
-
-/* plugin entry points: */
-static dm_plugin_error_t ipmi_plugin_init(void);
-static dm_plugin_error_t ipmi_plugin_fru_update(const char *actionString,
-    dm_fru_t *frup);
-static dm_plugin_error_t ipmi_plugin_bind_handle(const char *actionString,
-    dm_plugin_action_handle_t *hdlp);
-static dm_plugin_error_t ipmi_plugin_execute(dm_plugin_action_handle_t hdl);
-static dm_plugin_error_t ipmi_plugin_free_handle(
-    dm_plugin_action_handle_t *hdlp);
-static dm_plugin_error_t ipmi_plugin_fini(void);
-
-dm_plugin_ops_t ipmi_dm_plugin_ops = {
-	DM_PLUGIN_VERSION,
-	ipmi_plugin_init,
-	ipmi_plugin_fru_update,
-	ipmi_plugin_bind_handle,
-	ipmi_plugin_execute,
-	ipmi_plugin_free_handle,
-	ipmi_plugin_fini
-};
-
-static struct ipmi_cmd_setup ipmi_cmd_tab[] = {
-	{ "fru", fru_setupfn, IPMI_NETFN_OEM,
-	    0, IPMI_CMD_FRU_UPDATE },
-	{ "state", state_setupfn, BMC_NETFN_SE,
-	    0, IPMI_CMD_SET_SENSOR_READING },
-	{ "sel", sel_setupfn, BMC_NETFN_STORAGE,
-	    0, IPMI_CMD_ADD_SEL_ENTRY },
-	{ NULL, NULL, 0, 0, 0 }
-};
-
-static pthread_t g_bmcmon_tid;
-static boolean_t g_bmc_monitor_active;
-static boolean_t g_bmcmon_done;
-static boolean_t g_need_exec_replay = B_FALSE;
-static uu_list_pool_t *g_uu_pool_cache = NULL;
-static uu_list_pool_t *g_uu_pool_replay = NULL;
-static uu_list_t *g_uu_cachelist = NULL;
-static uu_list_t *g_uu_replaylist = NULL;
-static int g_BMCErrorInjectionRate = 0;
-static int g_bmc_fd = -1;
-
-/*
- * The textual strings that are used in the actions may be one of the
- * following forms:
- *
- * [1] `fru gid=<n> hdd=<m>'
- * [2] `sensor id=<x> assert=<y> deassert=<z>'
- *
- * The generic parser will take a string and spit out the first token
- * (e.g. `fru' or `sensor') and an nvlist that contains the key-value
- * pairs in the rest of the string.  The assumption is that there are
- * no embedded spaces or tabs in the keys or values.
- */
-
-static boolean_t
-isnumber(const char *str)
-{
-	boolean_t hex = B_FALSE;
-	int digits = 0;
-
-	if (strncasecmp(str, "0x", 2) == 0) {
-		hex = B_TRUE;
-		str += 2;
-	} else if (*str == '-' || *str == '+') {
-		str++;
-	}
-
-	while (*str != 0) {
-		if ((hex && !isxdigit(*str)) ||
-		    (!hex && !isdigit(*str))) {
-			return (B_FALSE);
-		}
-
-		str++;
-		digits++;
-	}
-
-	return ((digits == 0) ? B_FALSE : B_TRUE);
-}
-
-static void
-tolowerString(char *str)
-{
-	while (*str != 0) {
-		*str = tolower(*str);
-		str++;
-	}
-}
-
-static boolean_t
-parse_action_string(const char *actionString, char **cmdp, nvlist_t **propsp)
-{
-	char *action;
-	char *tok, *lasts, *eq;
-	int actionlen;
-	boolean_t rv = B_TRUE;
-
-	if (nvlist_alloc(propsp, NV_UNIQUE_NAME, 0) != 0)
-		return (B_FALSE);
-
-	actionlen = strlen(actionString) + 1;
-	action = dstrdup(actionString);
-
-	*cmdp = NULL;
-
-	if ((tok = strtok_r(action, " \t", &lasts)) != NULL) {
-
-		*cmdp = dstrdup(tok);
-
-		while (rv && (tok = strtok_r(NULL, " \t", &lasts)) != NULL) {
-
-			/* Look for a name=val construct */
-			if ((eq = strchr(tok, '=')) != NULL && eq[1] != 0) {
-
-				*eq = 0;
-				eq++;
-
-				/*
-				 * Convert token to lowercase to preserve
-				 * case-insensitivity, because nvlist doesn't
-				 * do case-insensitive lookups
-				 */
-				tolowerString(tok);
-
-				if (isnumber(eq)) {
-					/* Integer property */
-
-					if (nvlist_add_uint64(*propsp, tok,
-					    strtoull(eq, NULL, 0)) != 0)
-						rv = B_FALSE;
-				} else {
-					/* String property */
-
-					if (nvlist_add_string(*propsp, tok,
-					    eq) != 0)
-						rv = B_FALSE;
-				}
-			} else if (eq == NULL) {
-				/* Boolean property */
-				if (nvlist_add_boolean(*propsp, tok) != 0)
-					rv = B_FALSE;
-			} else /* Parse error (`X=' is invalid) */
-				rv = B_FALSE;
-		}
-	} else
-		rv = B_FALSE;
-
-	dfree(action, actionlen);
-	if (!rv) {
-		if (*cmdp) {
-			dstrfree(*cmdp);
-			*cmdp = NULL;
-		}
-		nvlist_free(*propsp);
-		*propsp = NULL;
-	}
-	return (rv);
-}
-
-static ipmi_action_handle_t *
-new_ipmi_action_handle(uint8_t netfn, uint8_t lun, uint8_t cmd, void *databp,
-    int datablen)
-{
-	ipmi_action_handle_t *ret = TDMALLOC(ipmi_action_handle_t);
-
-	ret->netfn = netfn;
-	ret->lun = lun;
-	ret->cmd = cmd;
-	ret->databp = databp;
-	ret->datablen = datablen;
-
-	return (ret);
-}
-
-static void
-bmc_reopen(void)
-{
-	if (g_bmc_fd >= 0)
-		(void) close(g_bmc_fd);
-	if ((g_bmc_fd = open(BMC_DEV, O_RDWR)) <= 0) {
-		log_warn_e("Could not reopen bmc device");
-	}
-}
-
-static void
-free_ipmi_action_handle(ipmi_action_handle_t **hdlpp)
-{
-	ipmi_action_handle_t *hdlp = *hdlpp;
-
-	if (hdlp) {
-		dfree(hdlp->databp, hdlp->datablen);
-		dfree(hdlp, sizeof (ipmi_action_handle_t));
-		*hdlpp = NULL;
-	}
-}
-
-static boolean_t
-cmd_setup_entry_exists(uint8_t netfn, uint8_t lun, uint8_t cmd)
-{
-	int i;
-
-	for (i = 0; ipmi_cmd_tab[i].name != NULL; i++) {
-
-		if (ipmi_cmd_tab[i].netfn == netfn &&
-		    ipmi_cmd_tab[i].lun == lun &&
-		    ipmi_cmd_tab[i].cmd == cmd)
-			return (B_TRUE);
-	}
-	return (B_FALSE);
-}
-
-static dm_plugin_error_t
-ipmi_exec_action_with_replay(uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *databp, int datablen)
-{
-	bmc_rsp_t		rsp;
-	dm_plugin_error_t	rv;
-
-	(void) bmc_state_refresh(NULL);
-
-	if (g_need_exec_replay)
-		g_need_exec_replay = (bmc_replay_list_execute() != 0);
-
-	if (!g_need_exec_replay) {
-		rv = (ipmi_bmc_send_cmd(netfn, lun, cmd, databp, datablen, &rsp)
-		    == DMPE_SUCCESS && rsp.ccode == 0)
-		    ? DMPE_SUCCESS : DMPE_FAILURE;
-	}
-
-	/*
-	 * If the command failed (or we couldn't execute the command because
-	 * we couldn't execute the replay list), and the failure is due to a
-	 * timeout error, save the command's result for later replay
-	 */
-	if (g_need_exec_replay || (rv == DMPE_FAILURE &&
-	    rsp.ccode == BMC_IPMI_COMMAND_TIMEOUT)) {
-
-		/*
-		 * Fake the return value as success (since we queued the
-		 * command for later execution).
-		 */
-		rv = DMPE_SUCCESS;
-		bmc_replay_list_add(netfn, lun, cmd, databp, datablen);
-		g_need_exec_replay = B_TRUE;
-
-	} else if (!g_need_exec_replay && rv == DMPE_SUCCESS) {
-
-		/* Apply the command to the bmc state$ */
-		bmc_state_cache_update(netfn, lun, cmd, databp, datablen);
-	}
-
-	return (rv);
-}
-
-static dm_plugin_error_t
-exec_action_handle(ipmi_action_handle_t *hdlp)
-{
-	dm_plugin_error_t rv;
-
-	/*
-	 * Sanity check this handle -- the netfn/lun/cmd should match one
-	 * of those defined in the ipmi_cmd_tab:
-	 */
-	if (!cmd_setup_entry_exists(hdlp->netfn, hdlp->lun, hdlp->cmd)) {
-		log_warn("Possible corrupt handle @%p (netfn/lun/cmd does "
-		    "not match any known commands.\n", (void *)hdlp);
-		return (DMPE_FAILURE);
-	}
-
-	dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
-
-	rv = ipmi_exec_action_with_replay(hdlp->netfn, hdlp->lun, hdlp->cmd,
-	    hdlp->databp, hdlp->datablen);
-
-	dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
-
-	return (rv);
-}
-
-static dm_plugin_error_t
-action_do(const char *actionString, void *arg, boolean_t exec,
-    ipmi_action_handle_t **hdlpp)
-{
-	nvlist_t	*props;
-	char		*cmd;
-	int		found_index;
-	int		datablen, i;
-	void		*databp;
-	uint8_t		netfn, lun, cmdno;
-	dm_plugin_error_t rv = DMPE_FAILURE;	/* Be pessimistic */
-
-	if (parse_action_string(actionString, &cmd, &props)) {
-		for (found_index = -1, i = 0;
-		    found_index == -1 && ipmi_cmd_tab[i].name != NULL; i++) {
-			if (strcasecmp(cmd, ipmi_cmd_tab[i].name) == 0) {
-				dm_assert(ipmi_cmd_tab[i].setupfn != NULL);
-				rv = ipmi_cmd_tab[i].setupfn(props,
-				    &databp, &datablen, arg);
-				found_index = i;
-			}
-		}
-
-		dstrfree(cmd);
-		nvlist_free(props);
-
-		netfn = ipmi_cmd_tab[found_index].netfn;
-		lun = ipmi_cmd_tab[found_index].lun;
-		cmdno = ipmi_cmd_tab[found_index].cmd;
-
-		if (exec && found_index != -1 && rv == DMPE_SUCCESS) {
-
-			dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
-
-			rv = ipmi_exec_action_with_replay(netfn, lun,
-			    cmdno, databp, datablen);
-
-			dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
-
-			dfree(databp, datablen);
-
-		} else if (found_index != -1 && rv == DMPE_SUCCESS) {
-			dm_assert(hdlpp != NULL);
-
-			*hdlpp = new_ipmi_action_handle(netfn, lun, cmdno,
-			    databp, datablen);
-		}
-	}
-
-	return (rv);
-}
-
-static dm_plugin_error_t
-fru_setupfn(nvlist_t *props, void **databpp, int *datablen,
-    void *arg)
-{
-	uint64_t gid, hdd;
-	struct ipmi_fru_update *fup;
-	char *buf;
-	dm_fru_t *frup = (dm_fru_t *)arg;
-
-	/* We need 2 properties: `gid' and `hdd': */
-	if (nvlist_lookup_uint64(props, "gid", &gid) != 0 ||
-	    nvlist_lookup_uint64(props, "hdd", &hdd) != 0) {
-		return (DMPE_FAILURE);
-	}
-
-	fup = TDZMALLOC(struct ipmi_fru_update);
-	buf = (char *)dzmalloc(sizeof (fup->d_capacity) + 1);
-
-	*datablen = sizeof (struct ipmi_fru_update);
-	*databpp = fup;
-
-	fup->global_id = (uint8_t)gid;
-	fup->disk_number = (uint8_t)hdd;
-	fup->data_length = sizeof (fup->d_manuf) + sizeof (fup->d_model) +
-	    sizeof (fup->d_serial) + sizeof (fup->d_firmware) +
-	    sizeof (fup->d_capacity);
-	(void) memcpy(fup->d_manuf, frup->manuf,
-	    MIN(sizeof (fup->d_manuf), sizeof (frup->manuf)));
-	(void) memcpy(fup->d_model, frup->model,
-	    MIN(sizeof (fup->d_model), sizeof (frup->model)));
-	(void) memcpy(fup->d_serial, frup->serial,
-	    MIN(sizeof (fup->d_serial), sizeof (frup->serial)));
-	(void) memcpy(fup->d_firmware, frup->rev,
-	    MIN(sizeof (fup->d_firmware), sizeof (frup->rev)));
-	/*
-	 * Print the size of the disk to a temporary buffer whose size is
-	 * 1 more than the size of the buffer in the ipmi request data
-	 * structure, so we can get the full 8 characters (instead of 7 + NUL)
-	 */
-	(void) snprintf(buf, sizeof (fup->d_capacity) + 1,
-	    "%.1f%s",
-	    frup->size_in_bytes >= ONE_PETABYTE ?
-		(frup->size_in_bytes / ONE_PETABYTE) :
-		    (frup->size_in_bytes >= ONE_TERABYTE ?
-			    (frup->size_in_bytes / ONE_TERABYTE) :
-				(frup->size_in_bytes >= ONE_GIGABYTE ?
-				    (frup->size_in_bytes / ONE_GIGABYTE) :
-					(frup->size_in_bytes >= ONE_MEGABYTE ?
-				(frup->size_in_bytes / ONE_MEGABYTE) :
-				    (frup->size_in_bytes / ONE_KILOBYTE)))),
-
-	    frup->size_in_bytes >= ONE_PETABYTE ? "PB" :
-		    (frup->size_in_bytes >= ONE_TERABYTE ? "TB" :
-			(frup->size_in_bytes >= ONE_GIGABYTE ? "GB" :
-				(frup->size_in_bytes >= ONE_MEGABYTE ? "MB" :
-					"KB"))));
-	(void) memcpy(fup->d_capacity, buf, sizeof (fup->d_capacity));
-
-	dfree(buf, sizeof (fup->d_capacity) + 1);
-	return (DMPE_SUCCESS);
-}
-
-/*ARGSUSED*/
-static dm_plugin_error_t
-state_setupfn(nvlist_t *props, void **databpp, int *datablen,
-    void *arg)
-{
-	uint64_t assertmask = 0, deassertmask = 0, sid;
-	boolean_t am_present, dam_present;
-	struct ipmi_sensor_control *scp;
-
-	/* We need at least 2 properties: `sid' and (`amask' || `dmask'): */
-	am_present = nvlist_lookup_uint64(props, "amask", &assertmask) == 0;
-	dam_present = nvlist_lookup_uint64(props, "dmask", &deassertmask) == 0;
-
-	if (nvlist_lookup_uint64(props, "sid", &sid) != 0 ||
-	    (!am_present && !dam_present)) {
-		return (DMPE_FAILURE);
-	}
-
-	if (sid > UINT8_MAX) {
-		log_warn("IPMI Plugin: Invalid sensor id `0x%" PRIx64 "'.\n",
-		    sid);
-		return (DMPE_FAILURE);
-	} else if (assertmask > UINT16_MAX) {
-		log_warn("IPMI Plugin: Invalid assertion mask `0x%" PRIx64
-		    "'.\n", assertmask);
-		return (DMPE_FAILURE);
-	} else if (assertmask > UINT16_MAX) {
-		log_warn("IPMI Plugin: Invalid deassertion mask `0x%" PRIx64
-		    "'.\n", deassertmask);
-		return (DMPE_FAILURE);
-	}
-
-	scp = TDZMALLOC(struct ipmi_sensor_control);
-
-	scp->sensor_number = (uint8_t)sid;
-	scp->operation = (am_present ? SC_ASSERT_OP : 0) |
-	    (dam_present ? SC_DEASSERT_OP : 0);
-	scp->assert_states = (uint16_t)assertmask;
-	scp->deassert_states = (uint16_t)deassertmask;
-
-	*datablen = sizeof (struct ipmi_sensor_control);
-	*databpp = scp;
-
-	return (DMPE_SUCCESS);
-}
-
-/*ARGSUSED*/
-static dm_plugin_error_t
-sel_setupfn(nvlist_t *props, void **databpp, int *datablen,
-    void *arg)
-{
-	uint64_t oem_data, manuf_id;
-	struct ipmi_sel_entry *sep;
-
-	/* We need 2 properties: `oem' and `manu': */
-	if (nvlist_lookup_uint64(props, "oem", &oem_data) != 0 ||
-	    nvlist_lookup_uint64(props, "manu", &manuf_id) != 0) {
-
-		return (DMPE_FAILURE);
-	}
-
-	if ((manuf_id & ~0xFFFFFFULL) != 0) {
-		log_warn("IPMI Plugin: Invalid manuf field `0x%" PRIx64 "'.\n",
-		    manuf_id);
-		return (DMPE_FAILURE);
-	} else if ((oem_data & ~0xFFFFFFFFFFFFULL) != 0) {
-		log_warn("IPMI Plugin: Invalid oem field `0x%" PRIx64
-		    "'.\n", oem_data);
-		return (DMPE_FAILURE);
-	}
-
-	sep = TDZMALLOC(struct ipmi_sel_entry);
-
-	sep->type = SEL_TYPE_OEM;
-	sep->manuf_id[0] = (uint8_t)(manuf_id & 0xFFULL);
-	sep->manuf_id[1] = (uint8_t)((manuf_id & 0xFF00ULL) >> 8);
-	sep->manuf_id[2] = (uint8_t)((manuf_id & 0xFF0000ULL) >> 16);
-	sep->oem_defined[0] = (uint8_t)(oem_data & 0xFFULL);
-	sep->oem_defined[1] = (uint8_t)((oem_data & 0xFF00ULL) >> 8);
-	sep->oem_defined[2] = (uint8_t)((oem_data & 0xFF0000ULL) >> 16);
-	sep->oem_defined[3] = (uint8_t)((oem_data & 0xFF000000ULL) >> 24);
-	sep->oem_defined[4] = (uint8_t)((oem_data & 0xFF00000000ULL) >> 32);
-	sep->oem_defined[5] = (uint8_t)((oem_data & 0xFF0000000000ULL) >> 40);
-
-	*datablen = sizeof (struct ipmi_sel_entry);
-	*databpp = sep;
-
-	return (DMPE_SUCCESS);
-}
-
-static dm_plugin_error_t
-bmc_get_sensor(uint8_t sensor_id, uint16_t *assrtd, boolean_t *updated_flag)
-{
-	dm_plugin_error_t		rv;
-	bmc_rsp_t			rsp;
-	struct ipmi_sensor_reading	*srp;
-
-	rv = ipmi_bmc_send_cmd(IPMI_NETFN_OEM, 0, IPMI_CMD_GET_SENSOR_READING,
-	    &sensor_id, 1, &rsp);
-
-	/* The command must return precisely the size of the data we expect */
-	if (rsp.ccode ||
-	    rsp.datalength > sizeof (struct ipmi_sensor_reading) ||
-	    rsp.datalength < STRUCT_MIN_SIZE(struct ipmi_sensor_reading,
-	    sensor_reading_optional_field_start))
-		rv = DMPE_FAILURE;
-
-	srp = (struct ipmi_sensor_reading *)&rsp.data[0];
-
-	if (rv == DMPE_SUCCESS &&
-	    rsp.datalength == sizeof (struct ipmi_sensor_reading) &&
-	    !srp->data_unavailable && srp->scanning_enabled) {
-
-		if (assrtd) {
-			*assrtd = (srp->states_8_14 << 8) | srp->states_0_7;
-			if (updated_flag)
-				*updated_flag = B_TRUE;
-		}
-	}
-	return (rv);
-}
-
-static dm_plugin_error_t
-bmc_get_uptime(uint32_t *uptime, uint32_t *bootgen)
-{
-	dm_plugin_error_t	rv;
-	uint8_t			junk = 0;
-	bmc_rsp_t		rsp;
-	struct bmc_uptime_info	*utinfop;
-
-	rv = ipmi_bmc_send_cmd(IPMI_NETFN_OEM, 0, IPMI_CMD_GET_UPTIME, &junk,
-	    1, &rsp);
-
-	/* The command must return precisely the size of the data we expect */
-	if (rsp.ccode ||
-	    rsp.datalength != sizeof (struct bmc_uptime_info))
-		rv = DMPE_FAILURE;
-
-	if (rv == DMPE_SUCCESS) {
-		utinfop = (struct bmc_uptime_info *)&rsp.data[0];
-		if (uptime)
-			*uptime = BE_32(utinfop->uptime_seconds);
-		if (bootgen)
-			*bootgen = BE_32(utinfop->incarnation);
-	}
-	return (rv);
-}
-
-/* ****** B M C   R E P L A Y    L I S T   I M P L E M E N T A T I O N ****** */
-
-/*
- * The reasoning behind the replay list is to try to ensure that commands are
- * reliably sent to the BMC.  In the case of the replay list, any commands that
- * fail because they timed out are added tothe replay list.  Then, the next time
- * a command is attempted, the replay list is sent to the BMC first, then the
- * new command (to preserve ordering).  Currently, the only commands that are
- * supported by this plugin are write-oriented commands, where information is
- * sent to the BMC.  If, if the future, read-oriented commands are desired,
- * The replay mechanism will need to be enhanced to force all pending commands
- * in the replay list out to the BMC before executing the read-oriented
- * command (similar to a write cache that's flushed when a read is requested).
- */
-
-static void
-bmc_replay_list_ent_destroy(bmc_replay_list_ent_t *p)
-{
-	if (p->databp)
-		dfree(p->databp, p->datablen);
-	dfree(p, sizeof (bmc_replay_list_ent_t));
-}
-
-static int
-bmc_replay_list_init(void)
-{
-	if ((g_uu_pool_replay = uu_list_pool_create(
-	    "bmc_replay_list_pool", sizeof (bmc_replay_list_ent_t),
-	    offsetof(bmc_replay_list_ent_t, un_node), NULL, 0)) == NULL)
-		return (DMPE_FAILURE);
-
-	if ((g_uu_replaylist = uu_list_create(g_uu_pool_replay, NULL, 0))
-	    == NULL) {
-		uu_list_pool_destroy(g_uu_pool_replay);
-		return (DMPE_FAILURE);
-	}
-
-	return (DMPE_SUCCESS);
-}
-
-static void
-bmc_replay_list_fini(void)
-{
-	void			*cookie = NULL;
-	bmc_replay_list_ent_t	*p;
-
-	while ((p = (bmc_replay_list_ent_t *)uu_list_teardown(g_uu_replaylist,
-	    &cookie)) != NULL) {
-		bmc_replay_list_ent_destroy(p);
-	}
-
-	uu_list_destroy(g_uu_replaylist);
-	uu_list_pool_destroy(g_uu_pool_replay);
-	g_uu_replaylist = NULL;
-	g_uu_pool_replay = NULL;
-}
-
-/*
- * The caller must hold the ipmi_mutex!
- */
-static void
-bmc_replay_list_add(uint8_t netfn, uint8_t lun, uint8_t cmd, uint8_t *databp,
-    int datablen)
-{
-	bmc_replay_list_ent_t *p = TDMALLOC(bmc_replay_list_ent_t);
-
-	p->netfn = netfn;
-	p->lun = lun;
-	p->cmd = cmd;
-	/*
-	 * Make a deep copy of the data buffer, since we can't assume
-	 * anything about when it will be deallocated.
-	 */
-	if (datablen > 0) {
-		p->databp = (uint8_t *)dmalloc(datablen);
-		(void) memcpy(p->databp, databp, datablen);
-	}
-	p->datablen = datablen;
-
-	dm_assert(g_uu_pool_replay != NULL);
-	dm_assert(g_uu_replaylist != NULL);
-	uu_list_node_init(p, &p->un_node, g_uu_pool_replay);
-	/* The replay list is a queue, so add to its tail: */
-	(void) uu_list_insert_before(g_uu_replaylist, NULL, p);
-}
-
-/*
- * The caller must hold the ipmi_mutex!
- *
- * Returns < 0 if the replay list should be executed at a later time
- * (due to transient errors)
- */
-static int
-bmc_replay_list_execute(void)
-{
-	uu_list_walk_t		*walkp;
-	bmc_replay_list_ent_t	*p = NULL;
-	boolean_t		timedout_err = B_FALSE;
-	bmc_rsp_t		rsp;
-	dm_plugin_error_t	rv;
-
-	if ((walkp = uu_list_walk_start(g_uu_replaylist, 0)) == NULL)
-		return (-1);
-
-	/*
-	 * On the first timeout error, abort the replay; We cannot execute
-	 * commands later in the list because they may depend on the state
-	 * set by earlier commands.  We'll retry the command that failed
-	 * later. (Note that non-timeout-related failures do not cause
-	 * aborts because the assumption is that the original command caller
-	 * would not behave differently if a command were to fail.)  If this
-	 * assumption does not remain valid in the future, an enhancement to
-	 * the plugin API would be required to introduce a synchronous flag
-	 * that would result in the blocking of the calling thread until
-	 * BOTH the replay list is fully executed AND the user's current
-	 * command is executed (at which point the status can be examined
-	 * by the caller).
-	 */
-	while (!timedout_err && (p = uu_list_walk_next(walkp)) != NULL) {
-		rv = ipmi_bmc_send_cmd(p->netfn, p->lun, p->cmd, p->databp,
-		    p->datablen, &rsp);
-
-		if (rv == DMPE_SUCCESS ||
-		    (rv == DMPE_FAILURE &&
-		    rsp.ccode != BMC_IPMI_COMMAND_TIMEOUT)) {
-
-			if (rsp.ccode != 0) {
-				log_msg(MM_PLUGIN, "ipmi plugin: netfn 0x%x "
-				    "cmd 0x%x ccode=0x%x\n", p->netfn, p->cmd,
-				    rsp.ccode);
-			}
-			if (rv == DMPE_SUCCESS) {
-				/* Add the command to the bmc state$ */
-				bmc_state_cache_update(p->netfn, p->lun, p->cmd,
-				    p->databp, p->datablen);
-			}
-			uu_list_remove(g_uu_replaylist, p);
-			bmc_replay_list_ent_destroy(p);
-
-		} else if (rv == DMPE_FAILURE &&
-		    rsp.ccode == BMC_IPMI_COMMAND_TIMEOUT) {
-
-			timedout_err = B_TRUE;
-		}
-	}
-
-	uu_list_walk_end(walkp);
-	return (timedout_err ? -1 : 0);
-}
-
-/* ************** B M C  C A C H E  I M P L E M E N T A T I O N ************* */
-
-/*
- * The reasoning behind the cache is to maintain a mirror of the BMC's state
- * as it pertains to the commands that were sent from the plugin.  For Sun's
- * BMC implementations, the sensor and FRU information is not currently
- * preserved when the BMC (or service processor) is reset (or rebooted).  To
- * maintain consistency from the user/administrator's perspective, once the
- * BMC comes back online after a reset, the information from the state cache
- * is sent, all at once, in particular order, to the BMC.
- */
-
-static int
-bmc_cache_init(void)
-{
-	if ((g_uu_pool_cache = uu_list_pool_create(
-	    "bmc_cache_entry_pool", sizeof (bmc_cache_ent_t),
-	    offsetof(bmc_cache_ent_t, un_node), NULL, 0)) == NULL)
-		return (DMPE_FAILURE);
-
-	if ((g_uu_cachelist = uu_list_create(g_uu_pool_cache, NULL, 0))
-	    == NULL) {
-		uu_list_pool_destroy(g_uu_pool_cache);
-		return (DMPE_FAILURE);
-	}
-
-	return (DMPE_SUCCESS);
-}
-
-static void
-bmc_cache_fini(void)
-{
-	void	*cookie = NULL;
-	void	*p;
-
-	while ((p = uu_list_teardown(g_uu_cachelist, &cookie)) != NULL)
-		dfree(p, sizeof (bmc_cache_ent_t));
-
-	uu_list_destroy(g_uu_cachelist);
-	uu_list_pool_destroy(g_uu_pool_cache);
-
-	g_uu_cachelist = NULL;
-	g_uu_pool_cache = NULL;
-}
-
-static void
-bmc_cache_member_init_sensorctl(bmc_cache_ent_t *p, void *databp)
-{
-	struct ipmi_sensor_control	*tgt;
-	uint16_t			assrtd;
-	boolean_t			was_assrtd_updated = B_FALSE;
-
-	tgt = (struct ipmi_sensor_control *)databp;
-
-	/*
-	 * operation is initted here so that when we do the bmc update from
-	 * the cache, the structure will ready to send directly from the cache
-	 */
-	p->sensorCtl.sensor_number = tgt->sensor_number;
-	p->sensorCtl.operation = SC_ASSERT_OP;
-	p->sensorCtl.assert_states = tgt->assert_states;
-
-	/*
-	 * If the command fails, we'll still have the asserted
-	 * states that were set by the command that just finished
-	 */
-	if (bmc_get_sensor(p->sensorCtl.sensor_number, &assrtd,
-	    &was_assrtd_updated) == DMPE_SUCCESS &&
-	    was_assrtd_updated == B_TRUE) {
-
-		/*
-		 * If the states that were just asserted are not when we
-		 * check, issues a warning, but only if the verbosity is
-		 * jacked up -- this could be OK (if another user updates
-		 * the sensor's state between the time we executed the
-		 * update sensor command and the time we check the sensor's
-		 * value.
-		 */
-		if ((p->sensorCtl.assert_states & assrtd)
-		    != p->sensorCtl.assert_states) {
-
-			log_msg(MM_PLUGIN,
-			    "Asserted state(s) set before cache addition "
-			    "(0x%x) didn't stick -- caching them anyway\n",
-			    p->sensorCtl.assert_states);
-		}
-
-		p->sensorCtl.assert_states |= assrtd;
-	}
-}
-
-static void
-bmc_cache_member_update_sensorctl(bmc_cache_ent_t *p, void *databp)
-{
-	struct ipmi_sensor_control *tgt = (struct ipmi_sensor_control *)databp;
-
-	/*
-	 * It's not possible for the same bits to be set in the assert and
-	 * deassert masks- it would have cause an IPMI error when the
-	 * command was originally executed (and the cache update would
-	 * therefore not have occurred)
-	 */
-	p->sensorCtl.assert_states |= tgt->assert_states;
-	p->sensorCtl.assert_states &= ~tgt->deassert_states;
-}
-
-static boolean_t
-bmc_cache_member_match_sensorctl(bmc_cache_ent_t *p, void *databp)
-{
-	struct ipmi_sensor_control *tgt = (struct ipmi_sensor_control *)databp;
-
-	return (p->sensorCtl.sensor_number == tgt->sensor_number);
-}
-
-static void
-bmc_cache_member_bufsetup_sensorctl(bmc_cache_ent_t *p, void **bufpp,
-    int *buflenp)
-{
-	/* Mask off bits that shouldn't be set according to the spec */
-	p->sensorCtl.operation = SC_ASSERT_OP|SC_DEASSERT_OP;
-	p->sensorCtl.assert_states &= ~STATE_RESERVED_BITS;
-	p->sensorCtl.deassert_states =
-	    (~p->sensorCtl.assert_states & ~STATE_RESERVED_BITS);
-
-	*bufpp = &p->sensorCtl;
-	*buflenp = sizeof (struct ipmi_sensor_control);
-}
-
-static void
-bmc_cache_member_init_fru_update(bmc_cache_ent_t *p, void *databp)
-{
-	(void) memcpy(&p->fruInfo, databp, sizeof (struct ipmi_fru_update));
-}
-
-static void
-bmc_cache_member_update_fru_update(bmc_cache_ent_t *p, void *databp)
-{
-	(void) memcpy(&p->fruInfo, databp, sizeof (struct ipmi_fru_update));
-}
-
-
-static boolean_t
-bmc_cache_member_match_fru_update(bmc_cache_ent_t *p, void *databp)
-{
-	struct ipmi_fru_update *frup = (struct ipmi_fru_update *)databp;
-
-	return (p->fruInfo.global_id == frup->global_id &&
-	    p->fruInfo.disk_number == frup->disk_number);
-}
-
-static void
-bmc_cache_member_bufsetup_fru_update(bmc_cache_ent_t *p, void **bufpp,
-    int *buflenp)
-{
-	*bufpp = &p->fruInfo;
-	*buflenp = sizeof (struct ipmi_fru_update);
-}
-
-/*
- * Different elements in the cache need to be restored in order
- * (e.g. sensor state information must be populated before FRU information
- * is populated because the FRU information won't "stick" if the right
- * state isn't asserted)
- * The g_restoreOrder array is indexed by cache entry type
- */
-static const bmc_cache_ent_type_t g_restoreOrder[] = {
-	CACHE_ENT_SENSORCTL,
-	CACHE_ENT_FRUINFO,
-	CACHE_ENT_LAST
-};
-
-static struct bmc_cache_member {
-	uint8_t				netfn;
-	uint8_t				lun;
-	uint8_t				cmd;
-	int				dataszmin;
-	boolean_t			(*matchfn)(bmc_cache_ent_t *, void *);
-	void				(*updatefn)(bmc_cache_ent_t *, void *);
-	void				(*initfn)(bmc_cache_ent_t *, void *);
-	void				(*bufsetupfn)(bmc_cache_ent_t *,
-							void **, int *);
-	void				(*bufdonefn)(bmc_cache_ent_t *, void *,
-							int);
-
-} g_cachemembers[] = {
-
-	/* CACHE_ENT_FIRST */
-	{ 0, 0, 0, 0, NULL },
-
-	/* CACHE_ENT_FRUINFO */
-	{ IPMI_NETFN_OEM, 0, IPMI_CMD_FRU_UPDATE,
-	    sizeof (struct ipmi_fru_update),
-	    bmc_cache_member_match_fru_update,
-	    bmc_cache_member_update_fru_update,
-	    bmc_cache_member_init_fru_update,
-	    bmc_cache_member_bufsetup_fru_update,
-	    NULL },
-
-	/* CACHE_ENT_SENSORCTL */
-	{ BMC_NETFN_SE, 0, IPMI_CMD_SET_SENSOR_READING,
-	    sizeof (struct ipmi_sensor_control),
-	    bmc_cache_member_match_sensorctl,
-	    bmc_cache_member_update_sensorctl,
-	    bmc_cache_member_init_sensorctl,
-	    bmc_cache_member_bufsetup_sensorctl,
-	    NULL },
-
-	/* CACHE_ENT_LAST */
-	{ 0, 0, 0, 0, NULL }
-};
-
-static bmc_cache_ent_t *
-bmc_state_cache_lookup(uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *databp, int datablen)
-{
-	uu_list_walk_t		*walkp;
-	bmc_cache_ent_t		*p = NULL;
-	boolean_t		found = B_FALSE;
-
-	if ((walkp = uu_list_walk_start(g_uu_cachelist, 0)) == NULL)
-		return (NULL);
-
-	while (!found && (p = uu_list_walk_next(walkp)) != NULL) {
-
-		if (g_cachemembers[p->type].netfn == netfn &&
-		    g_cachemembers[p->type].lun == lun &&
-		    g_cachemembers[p->type].cmd == cmd &&
-		    datablen >= g_cachemembers[p->type].dataszmin &&
-		    (*(g_cachemembers[p->type].matchfn))(p, databp) == B_TRUE) {
-
-				found = B_TRUE;
-		}
-	}
-
-	uu_list_walk_end(walkp);
-	return (found ? p : NULL);
-}
-
-static void
-bmc_state_cache_add(uint8_t netfn, uint8_t lun, uint8_t cmd, uint8_t *databp,
-    int datablen)
-{
-	boolean_t	found_initfn = B_FALSE;
-	int		i;
-	bmc_cache_ent_t	*p;
-
-	p = (bmc_cache_ent_t *)dzmalloc(sizeof (bmc_cache_ent_t));
-	for (i = CACHE_ENT_FIRST + 1; !found_initfn && i < CACHE_ENT_LAST;
-	    i++) {
-
-		if (g_cachemembers[i].netfn == netfn &&
-		    g_cachemembers[i].lun == lun &&
-		    g_cachemembers[i].cmd == cmd &&
-		    datablen >= g_cachemembers[i].dataszmin) {
-
-			p->type = i;
-			(*(g_cachemembers[i].initfn))(p, databp);
-			found_initfn = B_TRUE;
-		}
-	}
-
-	if (found_initfn) {
-
-		dm_assert(g_uu_pool_cache != NULL);
-		dm_assert(g_uu_cachelist != NULL);
-		uu_list_node_init(p, &p->un_node, g_uu_pool_cache);
-		uu_list_insert(g_uu_cachelist, p, 0);
-
-	} else {
-		log_msg(MM_PLUGIN, "Not adding netfn=0x%x cmd=0x%x to the "
-		    "bmc$\n", netfn, cmd);
-
-		dfree(p, sizeof (bmc_cache_ent_t));
-	}
-}
-
-/*
- * The caller must hold the ipmi_mutex!
- */
-static void
-bmc_state_cache_update(uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *databp, int datablen)
-{
-	bmc_cache_ent_t			*p;
-
-	/*
-	 * Do a lookup to see if we have an entry for this entity.
-	 * If so, update it, otherwise, create a new entry in the cache.
-	 */
-
-
-	if ((p = bmc_state_cache_lookup(netfn, lun, cmd, databp, datablen))
-	    != NULL) {
-
-		/* Update the cache with the command payload */
-		(*(g_cachemembers[p->type].updatefn))(p, databp);
-
-	} else {
-
-		/* Add the item to the cache */
-		bmc_state_cache_add(netfn, lun, cmd, databp, datablen);
-	}
-}
-
-/*
- * Caller MUST hold the ipmi_lock
- */
-static int
-bmc_state_refresh_from_cache(void)
-{
-	int			i;
-	uu_list_walk_t		*walkp;
-	bmc_cache_ent_t		*p = NULL;
-	boolean_t		bail = B_FALSE;
-	void			*databp;
-	int			datablen;
-	dm_plugin_error_t	rv;
-	bmc_rsp_t		rsp;
-
-	/*
-	 * Since cached state needs to be restored in a particular
-	 * order, make several passes through the cache list, restoring
-	 * the state in pass-order. If this becomes performance-limiting,
-	 * the cache list can be populated in sorted order (in pass order)
-	 */
-	for (i = 0; !bail && g_restoreOrder[i] != CACHE_ENT_LAST; i++) {
-
-		if ((walkp = uu_list_walk_start(g_uu_cachelist, 0)) == NULL)
-			return (-1);
-
-		while (!bail && (p = uu_list_walk_next(walkp)) != NULL) {
-
-			if (p->type == g_restoreOrder[i]) {
-
-				(*(g_cachemembers[p->type].bufsetupfn))
-				    (p, &databp, &datablen);
-
-				rv = ipmi_bmc_send_cmd(
-				    g_cachemembers[p->type].netfn,
-				    g_cachemembers[p->type].lun,
-				    g_cachemembers[p->type].cmd,
-				    databp, datablen, &rsp);
-
-				if (rv == DMPE_FAILURE &&
-				    rsp.ccode != BMC_IPMI_COMMAND_TIMEOUT)
-					bail = B_TRUE;
-
-				if (g_cachemembers[p->type].bufdonefn)
-					(*(g_cachemembers[p->type].bufdonefn))
-					    (p, databp, datablen);
-			}
-		}
-
-		uu_list_walk_end(walkp);
-	}
-
-	return (bail ? -1 : 0);
-}
-
-/*
- * Caller MUST hold the ipmi_lock
- */
-static int
-bmc_state_refresh(boolean_t *refreshed)
-{
-	static uint32_t		last_utime = 0;
-	static uint32_t		last_iter = 0;
-	static boolean_t	initted = B_FALSE;
-	uint32_t		utime;
-	uint32_t		iter;
-	dm_plugin_error_t	rv;
-
-	if (!g_bmc_monitor_active)
-		return (0);
-
-	rv = bmc_get_uptime(&utime, &iter);
-
-	if (refreshed)
-		*refreshed = B_FALSE;
-
-	if (rv == DMPE_SUCCESS) {
-
-		/*
-		 * This also handles the wrap-around case (when utime is
-		 * less than last_utime, but iter == last_iter), and
-		 * also the case when the BMC's configuration is
-		 * reset after a reboot (e.g. the reboot iteration #
-		 * is reset to 0).
-		 */
-		if (initted &&
-		    (utime < last_utime || iter != last_iter)) {
-			/* BMC Reboot/Reset Detected */
-			log_msg(MM_PLUGIN, "BMC refresh in progress...");
-			if (bmc_state_refresh_from_cache() < 0) {
-				log_msg(MM_PLUGIN, "BMC refresh failed!\n");
-				return (-1);
-			} else {
-				if (refreshed)
-					*refreshed = B_TRUE;
-			}
-		}
-
-		last_utime = utime;
-		last_iter = iter;
-		initted = B_TRUE;
-	}
-
-	return (0);
-}
-
-/*ARGSUSED*/
-static void
-bmc_monitor_thread(void *arg)
-{
-	struct timespec 	tspec;
-	boolean_t		refreshed;
-
-	dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
-	while (!g_bmcmon_done) {
-
-		if (bmc_state_refresh(&refreshed) == 0 && refreshed) {
-			/*
-			 * If the state was successfully refreshed, and there's
-			 * replay list, execute that list.
-			 */
-			if (g_need_exec_replay) {
-				g_need_exec_replay =
-				    (bmc_replay_list_execute() != 0);
-			}
-
-			log_msg(MM_PLUGIN, "BMC successfully refreshed with "
-				    "cached state!\n");
-		}
-
-		/* Poll the BMC for any changes in its state every minute */
-		tspec.tv_sec = time(0) + BMC_CHECK_UPTIME_INTERVAL;
-		tspec.tv_nsec = 0;
-
-		(void) pthread_cond_timedwait(&ipmi_cond,
-		    &ipmi_mutex, &tspec);
-	}
-	dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
-
-	log_msg(MM_PLUGIN, "BMC monitoring thread exiting...");
-}
-
-/* ***************** P L U G I N  E N T R Y  P O I N T S ******************* */
-
-static dm_plugin_error_t
-ipmi_plugin_init(void)
-{
-	int method;
-	const char *monpropval =
-	    dm_plugin_prop_lookup(GLOBAL_PROP_IPMI_BMC_MON);
-	const char *errinjprop =
-	    dm_plugin_prop_lookup(GLOBAL_PROP_IPMI_ERR_INJ);
-	boolean_t bmcmon_enabled;
-
-	if ((g_bmc_fd = open(BMC_DEV, O_RDWR)) <= 0) {
-		log_warn_e("Could not open bmc device");
-		return (DMPE_FAILURE);
-	}
-
-	if (bmc_method(g_bmc_fd, &method) < 0) {
-		(void) close(g_bmc_fd);
-		log_warn("IPMI plugin: Could not determine bmc messaging "
-		    "interface!\n");
-		return (DMPE_FAILURE);
-	}
-
-	/*
-	 * Keep the bmc device open to prevent the driver from unloading
-	 * at a critical moment (e.g. when the BMC is not available).  If
-	 * we didn't do this, subsequent attempt at opening the bmc device
-	 * would fail because the bmc driver would not be able to find
-	 * the BMC (if it's resetting), and once the bmc's probe fails,
-	 * the system will not reload it automatically.
-	 */
-
-	sendrecv_fn = (method == BMC_PUTMSG_METHOD) ?
-	    ipmi_bmc_send_cmd_putmsg : ipmi_bmc_send_cmd_ioctl;
-
-	if (bmc_replay_list_init() != 0) {
-		return (DMPE_FAILURE);
-	}
-
-	if (errinjprop != NULL)
-		g_BMCErrorInjectionRate = strtol(errinjprop, 0, 0);
-
-	bmcmon_enabled = (monpropval != NULL && strtol(monpropval, 0, 0) != 0);
-
-	/*
-	 * Check to see if the BMC supports the Sun OEM uptime command
-	 * If it does, spawn a monitoring thread that will periodically poll
-	 * the bmc and check for bmc resets (since the bmc does not retain
-	 * the state across resets)
-	 */
-	if (bmcmon_enabled && bmc_get_uptime(NULL, NULL) == 0) {
-		if (bmc_cache_init() != 0) {
-			bmc_replay_list_fini();
-			return (DMPE_FAILURE);
-		}
-
-		g_bmc_monitor_active = B_TRUE;
-		g_bmcmon_done = B_FALSE;
-		g_bmcmon_tid = dm_plugin_thr_create(bmc_monitor_thread, NULL);
-	} else
-		g_bmc_monitor_active = B_FALSE;
-
-	return (DMPE_SUCCESS);
-}
-
-static dm_plugin_error_t
-ipmi_plugin_fru_update(const char *actionString, dm_fru_t *frup)
-{
-	return (action_do(actionString, frup, B_TRUE, NULL));
-}
-
-static dm_plugin_error_t
-ipmi_plugin_bind_handle(const char *actionString,
-    dm_plugin_action_handle_t *hdlp)
-{
-	return (action_do(actionString, NULL, B_FALSE,
-	    (ipmi_action_handle_t **)hdlp));
-}
-
-static dm_plugin_error_t
-ipmi_plugin_execute(dm_plugin_action_handle_t hdl)
-{
-	return (exec_action_handle((ipmi_action_handle_t *)hdl));
-}
-
-static dm_plugin_error_t
-ipmi_plugin_free_handle(dm_plugin_action_handle_t *hdlp)
-{
-	free_ipmi_action_handle((ipmi_action_handle_t **)hdlp);
-	return (DMPE_SUCCESS);
-}
-
-static dm_plugin_error_t
-ipmi_plugin_fini(void)
-{
-	if (g_bmc_monitor_active) {
-		g_bmcmon_done = B_TRUE;
-		dm_assert(pthread_mutex_lock(&ipmi_mutex) == 0);
-		(void) pthread_cond_broadcast(&ipmi_cond);
-		dm_assert(pthread_mutex_unlock(&ipmi_mutex) == 0);
-
-		/* Signal the thread just in case it's blocked doing BMC I/O */
-		dm_plugin_thr_signal(g_bmcmon_tid);
-		dm_plugin_thr_destroy(g_bmcmon_tid);
-
-		/* Clean up cache lists */
-		bmc_cache_fini();
-	}
-	bmc_replay_list_fini();
-	(void) close(g_bmc_fd);
-	return (DMPE_SUCCESS);
-}
-
-/* ************** I P M I  S U P P O R T  F U N C T I O N S **************** */
-
-static dm_plugin_error_t
-ipmi_bmc_send_cmd(uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *datap, int datalen, bmc_rsp_t *rspp)
-{
-	dm_plugin_error_t rv;
-	static int inject_rep = 0;
-
-	if (g_BMCErrorInjectionRate > 0 &&
-	    (++inject_rep % g_BMCErrorInjectionRate) == 0) {
-		inject_rep = 0;
-		rspp->ccode = BMC_IPMI_COMMAND_TIMEOUT;
-		return (DMPE_FAILURE);
-	}
-
-	if (g_bmc_fd < 0)
-		bmc_reopen();
-
-	/* sendrecv_fn cannot be NULL at this point */
-	dm_assert(sendrecv_fn != NULL);
-	rv = (*sendrecv_fn)(g_bmc_fd, netfn, lun, cmd, datap, datalen, rspp);
-
-	return (rv);
-}
-
-static dm_plugin_error_t
-ipmi_bmc_send_cmd_ioctl(int fd, uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *datap, int datalen, bmc_rsp_t *rspp)
-{
-	struct strioctl istr;
-	struct bmc_reqrsp reqrsp;
-
-	if (datalen > SEND_MAX_PAYLOAD_SIZE) {
-		log_warn("IPMI Plugin: Data payload length (%d) is too "
-		    "large; it cannot be processed by this version of "
-		    "the bmc driver.\n", datalen);
-		return (DMPE_FAILURE);
-	}
-
-	(void) memset(&reqrsp, 0, sizeof (reqrsp));
-	reqrsp.req.fn = netfn;
-	reqrsp.req.lun = lun;
-	reqrsp.req.cmd = cmd;
-	reqrsp.req.datalength = (uint8_t)datalen;
-	(void) memcpy(reqrsp.req.data, datap, datalen);
-	reqrsp.rsp.datalength = RECV_MAX_PAYLOAD_SIZE;
-
-	istr.ic_cmd = IOCTL_IPMI_KCS_ACTION;
-	istr.ic_timout = 0;
-	istr.ic_dp = (char *)&reqrsp;
-	istr.ic_len = sizeof (struct bmc_reqrsp);
-
-	log_msg(MM_PLUGIN, "--\n");
-		dump_request(&reqrsp.req);
-	log_msg(MM_PLUGIN, "--\n");
-
-	if (ioctl(fd, I_STR, &istr) < 0) {
-		log_warn_e("IPMI Plugin: ioctl failure");
-		return (DMPE_FAILURE);
-	}
-
-	dump_response(&reqrsp.rsp);
-	log_msg(MM_PLUGIN, "--\n");
-
-	(void) memcpy(rspp, &reqrsp.rsp, sizeof (bmc_rsp_t));
-
-	/* Decrement for sizeof lun, cmd and ccode */
-	if (rspp->ccode || rspp->datalength == 0)
-		(void) memset(rspp->data, 0, sizeof (rspp->data));
-	else if (rspp->datalength > 3)
-		rspp->datalength -= 3;
-
-	return (DMPE_SUCCESS);
-}
-
-static dm_plugin_error_t
-ipmi_bmc_send_cmd_putmsg(int fd, uint8_t netfn, uint8_t lun, uint8_t cmd,
-    uint8_t *datap, int datalen, bmc_rsp_t *rspp)
-{
-	struct strbuf sb;
-	int flags = 0;
-	static uint32_t msg_seq = 0;
-
-	/*
-	 * The length of the message structure is equal to the size of the
-	 * bmc_req_t structure, PLUS any additional data space in excess of
-	 * the data space already reserved in the data member + <n> for
-	 * the rest of the members in the bmc_msg_t structure.
-	 */
-	int msgsz = offsetof(bmc_msg_t, msg) + sizeof (bmc_req_t) +
-		((datalen > SEND_MAX_PAYLOAD_SIZE) ?
-			(datalen - SEND_MAX_PAYLOAD_SIZE) : 0);
-	bmc_msg_t *msg = (bmc_msg_t *)dzmalloc(msgsz);
-	bmc_req_t *request = (bmc_req_t *)&msg->msg[0];
-	bmc_rsp_t *response;
-
-	msg->m_type = BMC_MSG_REQUEST;
-	msg->m_id = msg_seq++;
-	request->fn = netfn;
-	request->lun = lun;
-	request->cmd = cmd;
-	request->datalength = (uint8_t)datalen;
-	(void) memcpy(request->data, datap, datalen);
-
-	sb.len = msgsz;
-	sb.buf = (char *)msg;
-
-	log_msg(MM_PLUGIN, "--\n");
-	dump_request(request);
-	log_msg(MM_PLUGIN, "--\n");
-
-	if (putmsg(fd, NULL, &sb, 0) < 0) {
-		log_warn_e("IPMI Plugin: putmsg failure");
-		dfree(msg, msgsz);
-
-		/*
-		 * As a workaround for a bug in bmc, if an error was returned
-		 * from putmsg, we need to close the fd and reopen it to clear
-		 * the error state.
-		 */
-		bmc_reopen();
-
-		return (DMPE_FAILURE);
-	}
-
-	dfree(msg, msgsz);
-
-	sb.buf = dzmalloc(MESSAGE_BUFSIZE);
-	sb.maxlen = MESSAGE_BUFSIZE;
-
-	if (getmsg(fd, NULL, &sb, &flags) < 0) {
-		log_warn_e("IPMI Plugin: getmsg failure");
-		dfree(sb.buf, MESSAGE_BUFSIZE);
-		return (DMPE_FAILURE);
-	}
-
-	/*LINTED*/
-	msg = (bmc_msg_t *)sb.buf;
-
-	log_msg(MM_PLUGIN, "Got msg (id 0x%x) type 0x%x\n", msg->m_id,
-	    msg->m_type);
-
-
-	/* Did we get an error back from the stream? */
-	switch (msg->m_type) {
-
-	case BMC_MSG_RESPONSE:
-		response = (bmc_rsp_t *)&msg->msg[0];
-
-		dump_response(response);
-		log_msg(MM_PLUGIN, "--\n");
-
-		(void) memcpy(rspp, response, sizeof (bmc_rsp_t));
-
-		if (rspp->ccode || rspp->datalength == 0)
-			(void) memset(rspp->data, 0, sizeof (rspp->data));
-
-		break;
-
-	case BMC_MSG_ERROR:
-		/* In case of an error, msg->msg[0] has the error code */
-		log_warn("IPMI Plugin: bmc_send_cmd error: %s\n",
-		    strerror(msg->msg[0]));
-		break;
-
-	}
-
-	dfree(sb.buf, MESSAGE_BUFSIZE);
-	return (DMPE_SUCCESS);
-}
-
-/*
- * Determine which interface to use.  Returns the interface method
- * to use.
- */
-static int
-bmc_method(int fd, int *if_type)
-{
-	struct strioctl istr;
-	int retval = 0;
-	uint8_t method = BMC_PUTMSG_METHOD;
-
-	istr.ic_cmd = IOCTL_IPMI_INTERFACE_METHOD;
-	istr.ic_timout = 0;
-	istr.ic_dp = (char *)&method;
-	istr.ic_len = 1;
-
-	/*
-	 * If the ioctl doesn't exist, we should get an EINVAL back.
-	 * Bail out on any other error.
-	 */
-	if (ioctl(fd, I_STR, &istr) < 0) {
-
-		if (errno != EINVAL)
-			retval = -1;
-		else
-			method = BMC_IOCTL_METHOD;
-	}
-
-	if (retval == 0)
-		*if_type = method;
-
-	return (retval);
-}
-
-static void
-dump_request(bmc_req_t *request)
-{
-	int i;
-
-	log_msg(MM_PLUGIN, "BMC req.fn         : 0x%x\n", request->fn);
-	log_msg(MM_PLUGIN, "BMC req.lun        : 0x%x\n", request->lun);
-	log_msg(MM_PLUGIN, "BMC req.cmd        : 0x%x\n", request->cmd);
-	log_msg(MM_PLUGIN, "BMC req.datalength : 0x%x\n", request->datalength);
-	log_msg(MM_PLUGIN, "BMC req.data       : ");
-
-	if (request->datalength > 0) {
-		for (i = 0; i < request->datalength; i++)
-			log_msg(MM_PLUGIN, "0x%x ", request->data[i]);
-	} else {
-		log_msg(MM_PLUGIN, "<NONE>");
-	}
-	log_msg(MM_PLUGIN, "\n");
-}
-
-static void
-dump_response(bmc_rsp_t *response)
-{
-	int i;
-
-	log_msg(MM_PLUGIN, "BMC rsp.fn         : 0x%x\n", response->fn);
-	log_msg(MM_PLUGIN, "BMC rsp.lun        : 0x%x\n", response->lun);
-	log_msg(MM_PLUGIN, "BMC rsp.cmd        : 0x%x\n", response->cmd);
-	log_msg(MM_PLUGIN, "BMC rsp.ccode      : 0x%x\n", response->ccode);
-	log_msg(MM_PLUGIN, "BMC rsp.datalength : 0x%x\n", response->datalength);
-	log_msg(MM_PLUGIN, "BMC rsp.data       : ");
-
-	if (response->datalength > 0) {
-		for (i = 0; i < response->datalength; i++)
-			log_msg(MM_PLUGIN, "0x%x ", response->data[i]);
-	} else {
-		log_msg(MM_PLUGIN, "<NONE>");
-	}
-	log_msg(MM_PLUGIN, "\n");
-}
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/ipmi_plugin.h	Sat Mar 10 06:42:50 2007 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _IPMI_PLUGIN_H
-#define	_IPMI_PLUGIN_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * IPMI Plugin definitions
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Controls whether to fire-up a thread to monitor the BMC's state
- * and to update it with cached state information when a BMC reset
- * is detected.
- */
-#define	GLOBAL_PROP_IPMI_BMC_MON "ipmi-bmc-monitor-enable"
-#define	GLOBAL_PROP_IPMI_ERR_INJ "ipmi-error-inj-rate"
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _IPMI_PLUGIN_H */
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.c	Sat Mar 10 06:42:50 2007 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,475 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * Block comment that describes the contents of this file.
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <link.h>
-#include <pthread.h>
-
-#include "util.h"
-#include "sfx4500-disk.h"
-#include "plugin_mgr.h"
-
-static dm_plugin_t *plugin_list = NULL;
-static pthread_mutex_t plugin_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-static dm_plugin_action_handle_impl_t *handle_list = NULL;
-static pthread_mutex_t handle_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static boolean_t
-safe_protocol_string(const char *protocol)
-{
-	while (*protocol != 0) {
-
-		if (!isalnum(*protocol))
-			return (B_FALSE);
-
-		protocol++;
-	}
-	return (B_TRUE);
-}
-
-/*
- * Initialize the plugin.
- * Returns DMPE_SUCCESS if the _init entry point of the plugin
- * executed successfully, otherwise returns DMPE_FAILURE.
- */
-static dm_plugin_error_t
-init_dm_plugin(dm_plugin_t *dmpip)
-{
-	dm_plugin_error_t ec;
-
-	if (dmpip->state != DMPS_INITED && dmpip->ops->_init) {
-		if ((ec = dmpip->ops->_init()) == DMPE_SUCCESS) {
-			dmpip->state = DMPS_INITED;
-		} else {
-			log_warn("_init failed for %s plugin; unloading it\n",
-			    dmpip->protocol);
-		}
-	} else if (dmpip->ops->_init == NULL)	/* No _init, no problem */
-		dmpip->state = DMPS_INITED;
-
-	return (ec);
-}
-
-static dm_plugin_t *
-new_dm_plugin(const char *protocol)
-{
-	dm_plugin_t *newpi = (dm_plugin_t *)dmalloc(sizeof (dm_plugin_t));
-
-	newpi->protocol = dstrdup(protocol);
-	newpi->state = DMPS_NONE;
-	newpi->ops = NULL;
-	newpi->next = NULL;
-
-	return (newpi);
-}
-
-static void
-unload_dm_plugin(dm_plugin_t *pluginp)
-{
-	pluginp->ops = NULL;
-}
-
-static void
-free_dm_plugin(dm_plugin_t **dmpipp)
-{
-	dm_plugin_t *dmpip = *dmpipp;
-	dm_plugin_error_t ec;
-
-	if (dmpip) {
-		if (dmpip->state == DMPS_INITED && dmpip->ops->_fini) {
-			ec = dmpip->ops->_fini();
-			if (ec != DMPE_SUCCESS) {
-				log_warn("_fini failed for plugin %s.\n",
-				    dmpip->protocol);
-			}
-		}
-
-		unload_dm_plugin(dmpip);
-
-		if (dmpip->protocol)
-			dstrfree(dmpip->protocol);
-
-		dmpip->state = DMPS_NONE;
-		dmpip->ops = NULL;
-
-		dfree(dmpip, sizeof (dm_plugin_t));
-		*dmpipp = NULL;
-	}
-}
-
-static boolean_t
-do_load_dm_plugin(dm_plugin_t *dmpip)
-{
-	boolean_t plugin_loaded = B_FALSE;
-	int len;
-	char *buf;
-
-	len = strlen(dmpip->protocol) + strlen(DM_PLUGIN_OPS_NAME) + 2;
-	buf = (char *)dmalloc(len);
-
-	/*
-	 * Currently, plugins are baked into the module, and the name of the
-	 * ops structure is formed by concatenating the plugin's protocol
-	 * with a static string:
-	 */
-
-	(void) snprintf(buf, len, "%s_%s", dmpip->protocol,
-	    DM_PLUGIN_OPS_NAME);
-
-	dmpip->ops = (dm_plugin_ops_t *)dlsym(RTLD_SELF, buf);
-
-	if (dmpip->ops != NULL) {
-		if (dmpip->ops->version > DM_PLUGIN_VERSION) {
-			log_warn("Plugin error: cannot handle "
-			    "plugin %s with version %d.\n",
-			    dmpip->protocol, dmpip->ops->version);
-		} else
-			plugin_loaded = B_TRUE;
-	} else {
-		log_warn("Plugin error: dlsym(%s) = NULL\n",
-		    buf);
-		unload_dm_plugin(dmpip);
-	}
-
-	dfree(buf, len);
-	return (plugin_loaded);
-}
-
-static dm_plugin_t *
-load_dm_plugin(const char *protocol)
-{
-	dm_plugin_t *dmpip = NULL;
-	boolean_t plugin_loaded = B_FALSE;
-
-	/*
-	 * Validate the protocol string -- if there are any non-alphanumeric
-	 * characters, it's not a valid protocol string.
-	 */
-	if (safe_protocol_string(protocol) == B_FALSE) {
-		log_warn("Invalid characters in plugin protocol `%s'.\n",
-		    protocol);
-		goto fpi_out;
-	}
-
-	dmpip = new_dm_plugin(protocol);
-
-	plugin_loaded = do_load_dm_plugin(dmpip);
-
-fpi_out:
-	if (plugin_loaded) {
-		dm_assert(dmpip != NULL);
-		dmpip->state = DMPS_LOADED;
-	} else if (!plugin_loaded && dmpip != NULL)
-		free_dm_plugin(&dmpip);
-
-	return (dmpip);
-}
-
-static char *
-extract_protocol(const char *action)
-{
-	char *s = strchr(action, PROTOCOL_SEPARATOR);
-	char *proto = NULL;
-	int len;
-	int i = 0;
-
-	/* The protocol is the string before the separator, but in lower-case */
-	if (s) {
-		len = (uintptr_t)s - (uintptr_t)action;
-		proto = (char *)dmalloc(len + 1);
-		while (i < len) {
-			proto[i] = tolower(action[i]);
-			i++;
-		}
-		proto[len] = 0;
-	}
-
-	return (proto);
-}
-
-static char *
-extract_action(const char *action)
-{
-	/* The action is the string after the separator */
-	char *s = strchr(action, PROTOCOL_SEPARATOR);
-
-	return (s ? (s + 1) : NULL);
-}
-
-static dm_plugin_t *
-load_and_init_dm_plugin(const char *protocol)
-{
-	dm_plugin_t *plugin = load_dm_plugin(protocol);
-
-	if (plugin) {
-		/* If _init succeeded, add the plugin to the list */
-		if (init_dm_plugin(plugin) == DMPE_SUCCESS) {
-			plugin->next = plugin_list;
-			plugin_list = plugin;
-		} else {
-			/* Otherwise, free it. */
-			free_dm_plugin(&plugin);
-		}
-	} else {
-		log_warn("Could not load `%s' plugin!\n",
-		    protocol);
-	}
-
-	return (plugin);
-}
-
-static dm_plugin_t *
-protocol_to_dm_plugin(const char *protocol)
-{
-	dm_plugin_t *plugin;
-
-	/*
-	 * Traversing the plugin list must be atomic with
-	 * respect to plugin loads
-	 */
-	dm_assert(pthread_mutex_lock(&plugin_list_mutex) == 0);
-
-	plugin = plugin_list;
-
-	while (plugin != NULL) {
-		if (strcmp(plugin->protocol, protocol) == 0) {
-			break;
-		}
-
-		plugin = plugin->next;
-	}
-
-	/* Wasn't found -- load, initialize, and return it */
-	plugin = (plugin == NULL) ? load_and_init_dm_plugin(protocol) :
-	    plugin;
-
-	dm_assert(pthread_mutex_unlock(&plugin_list_mutex) == 0);
-
-	return (plugin);
-}
-
-static dm_plugin_action_handle_impl_t *
-new_action_handle(const char *action, dm_plugin_t *pluginp)
-{
-	dm_plugin_action_handle_impl_t *hip;
-
-	hip = (dm_plugin_action_handle_impl_t *)dmalloc(
-	    sizeof (dm_plugin_action_handle_impl_t));
-
-	hip->actionString = dstrdup(action);
-	hip->plugin = pluginp;
-	hip->handle = (dm_plugin_action_handle_t)NULL;
-
-	/* Add the handle to the global list */
-	dm_assert(pthread_mutex_lock(&handle_list_mutex) == 0);
-	hip->next = handle_list;
-	handle_list = hip;
-	dm_assert(pthread_mutex_unlock(&handle_list_mutex) == 0);
-
-	return (hip);
-}
-
-static void
-free_action_handle(dm_plugin_action_handle_impl_t **hipp)
-{
-	dm_plugin_action_handle_impl_t *hip = *hipp;
-	dm_plugin_t *dmpip;
-
-	if (hip) {
-		if (hip->actionString)
-			dstrfree(hip->actionString);
-
-		dmpip = hip->plugin;
-
-		if (dmpip->state == DMPS_INITED &&
-		    dmpip->ops->indicator_free_handle)
-			if (dmpip->ops->indicator_free_handle(&hip->handle)
-			    != DMPE_SUCCESS) {
-				log_warn("indicator_free_handle failed for %s"
-				    " plugin\n",
-				    dmpip->protocol);
-			}
-
-		dfree(hip, sizeof (dm_plugin_action_handle_impl_t));
-		*hipp = NULL;
-	}
-}
-
-static dm_plugin_action_handle_impl_t *
-lookup_handle_by_action(const char *action)
-{
-	dm_plugin_action_handle_impl_t *handle;
-
-	dm_assert(pthread_mutex_lock(&handle_list_mutex) == 0);
-
-	handle = handle_list;
-
-	while (handle != NULL) {
-		if (strcmp(handle->actionString, action) == 0)
-			break;
-
-		handle = handle->next;
-	}
-
-	dm_assert(pthread_mutex_unlock(&handle_list_mutex) == 0);
-
-	return (handle);
-}
-
-int
-init_plugin_manager(void)
-{
-	return (0);
-}
-
-void
-cleanup_plugin_manager(void)
-{
-	dm_plugin_t *next_plugin;
-	dm_plugin_action_handle_impl_t *next_handle;
-
-	while (handle_list != NULL) {
-		next_handle = handle_list->next;
-
-		free_action_handle(&handle_list);
-
-		handle_list = next_handle;
-	}
-
-	while (plugin_list != NULL) {
-
-		next_plugin = plugin_list->next;
-
-		free_dm_plugin(&plugin_list);
-
-		plugin_list = next_plugin;
-	}
-}
-
-static dm_plugin_error_t
-bind_action_handle(dm_plugin_t *dmpip, const char *action,
-    dm_plugin_action_handle_t *hdlp)
-{
-	dm_plugin_action_handle_impl_t *hip;
-
-	hip = new_action_handle(action, dmpip);
-	*hdlp = hip;
-
-	dm_assert(dmpip->state == DMPS_INITED);
-	if (dmpip->ops->indicator_bind_handle)
-		return (dmpip->ops->indicator_bind_handle(action,
-		    &hip->handle));
-
-	return (DMPE_FAILURE);
-}
-
-dm_plugin_error_t
-dm_pm_update_fru(const char *action, dm_fru_t *frup)
-{
-	char *protocol = extract_protocol(action);	/* mem alloced here */
-	char *actionp = extract_action(action);
-	dm_plugin_t *dmpip;
-
-	if (protocol == NULL) {
-		log_warn("FRU update: Invalid protocol specified in action "
-		    "`%s'\n", action);
-		return (DMPE_FAILURE);
-	}
-
-	dmpip = protocol_to_dm_plugin(protocol);
-	dstrfree(protocol);
-
-	if (dmpip != NULL) {
-		dm_assert(dmpip->state == DMPS_INITED);
-		if (dmpip->ops->indicator_fru_update)
-			return (dmpip->ops->indicator_fru_update(actionp,
-			    frup));
-	}
-
-	return (DMPE_FAILURE);
-}
-
-dm_plugin_error_t
-dm_pm_indicator_execute(const char *action)
-{
-	dm_plugin_t *dmpip;
-	char *protocol = extract_protocol(action); /* memory allocated here */
-	char *actionp = extract_action(action);
-	dm_plugin_action_handle_impl_t *hip;
-
-	dmpip = protocol_to_dm_plugin(protocol);
-	dstrfree(protocol);
-
-	if (dmpip != NULL) {
-
-		if ((hip = lookup_handle_by_action(actionp)) == NULL) {
-			if (bind_action_handle(dmpip, actionp,
-			    (dm_plugin_action_handle_t *)&hip) != DMPE_SUCCESS)
-				return (DMPE_FAILURE);
-		}
-
-		dm_assert(dmpip->state == DMPS_INITED);
-		if (dmpip->ops->indicator_execute)
-			return (dmpip->ops->indicator_execute(hip->handle));
-	}
-
-	return (DMPE_FAILURE);
-}
-
-pthread_t
-dm_plugin_thr_create(void (*fn)(void *), void *arg)
-{
-	return (fmd_thr_create(g_fm_hdl, fn, arg));
-}
-
-void
-dm_plugin_thr_signal(pthread_t tid)
-{
-	fmd_thr_signal(g_fm_hdl, tid);
-}
-
-void
-dm_plugin_thr_destroy(pthread_t tid)
-{
-	fmd_thr_destroy(g_fm_hdl, tid);
-}
-
-const char *
-dm_plugin_prop_lookup(const char *propname)
-{
-	return (dm_prop_lookup(dm_global_proplist(), propname));
-}
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/plugin_mgr.h	Sat Mar 10 06:42:50 2007 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _PLUGIN_MGR_H
-#define	_PLUGIN_MGR_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * Declarations for the disk monitor plugin manager
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "dm_plugin.h"
-#include "ipmi_plugin.h"
-
-#define	DM_PLUGIN_DIR "/usr/lib/fm/fmd/plugins/dm"
-#define	DM_PLUGIN_PREFIX "dmpi_"
-#define	PROTOCOL_SEPARATOR ':'
-
-typedef enum {
-	DMPS_NONE,
-	DMPS_LOADED,
-	DMPS_INITED
-} dm_plugin_state_t;
-
-typedef struct dm_plugin {
-	char			*protocol;
-	dm_plugin_state_t	state;
-	dm_plugin_ops_t		*ops;
-	pthread_mutex_t		*mutex;
-	struct dm_plugin	*next;
-} dm_plugin_t;
-
-typedef struct dm_plugin_action_handle_impl {
-	dm_plugin_t				*plugin;
-	char					*actionString;
-	dm_plugin_action_handle_t		handle;
-	struct dm_plugin_action_handle_impl	*next;
-} dm_plugin_action_handle_impl_t;
-
-extern int init_plugin_manager(void);
-extern void cleanup_plugin_manager(void);
-
-extern dm_plugin_error_t dm_pm_update_fru(const char *action, dm_fru_t *frup);
-extern dm_plugin_error_t dm_pm_indicator_execute(const char *action);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PLUGIN_MGR_H */
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/schg_mgr.c	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/schg_mgr.c	Sat Mar 10 17:17:25 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,11 +35,11 @@
 #include "sfx4500-disk.h"
 #include "schg_mgr.h"
 #include "hotplug_mgr.h"
-#include "plugin_mgr.h"
 #include "fault_mgr.h"
 #include "fault_analyze.h"
 #include "topo_gather.h"
 #include "fm_disk_events.h"
+#include "dm_platform.h"
 
 /* State-change event processing thread data */
 static pthread_t	g_schg_tid;
@@ -131,8 +131,7 @@
 	if (astring != NULL) {
 		log_msg(MM_SCHGMGR, "Executing action `%s'\n", astring);
 
-		if (dm_pm_indicator_execute(astring)
-		    != DMPE_SUCCESS) {
+		if (dm_platform_indicator_execute(astring) != 0) {
 			log_warn("[Disk in %s] Action `%s' did not complete "
 			    "successfully.\n",
 			    diskp->location,
@@ -192,8 +191,7 @@
 
 			log_msg(MM_SCHGMGR, "Executing action `%s'\n", astring);
 
-			if (dm_pm_indicator_execute(astring)
-			    != DMPE_SUCCESS) {
+			if (dm_platform_indicator_execute(astring) != 0) {
 				log_warn("[Disk in %s][State transition from "
 				    "%s to %s] Action `%s' did not complete "
 				    "successfully.\n",
@@ -214,7 +212,7 @@
 }
 
 static void
-schg_send_fru_to_plugin(diskmon_t *diskp, dm_fru_t *frup)
+schg_send_fru_update(diskmon_t *diskp, dm_fru_t *frup)
 {
 	const char *action = dm_prop_lookup(diskp->props, DISK_PROP_FRUACTION);
 
@@ -224,7 +222,7 @@
 		return;
 	}
 
-	if (dm_pm_update_fru(action, frup) != DMPE_SUCCESS) {
+	if (dm_platform_update_fru(action, frup) != 0) {
 		log_warn("Error updating FRU information for disk in %s.\n",
 		    diskp->location);
 	}
@@ -238,7 +236,7 @@
 		diskp->initial_configuration = B_FALSE;
 		dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
 		if (diskp->frup != NULL)
-			schg_send_fru_to_plugin(diskp, diskp->frup);
+			schg_send_fru_update(diskp, diskp->frup);
 		else
 			log_warn("frup unexpectedly went away: not updating "
 			    "FRU information for disk %s!\n", diskp->location);
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/sfx4500-disk.c	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/sfx4500-disk.c	Sat Mar 10 17:17:25 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -51,9 +51,9 @@
 #include "fault_mgr.h"
 #include "hotplug_mgr.h"
 #include "schg_mgr.h"
-#include "plugin_mgr.h"
 #include "fm_disk_events.h"
 #include "topo_gather.h"
+#include "dm_platform.h"
 
 #define	THIS_FMD_MODULE_NAME "sfx4500-disk"
 
@@ -93,7 +93,6 @@
 	cleanup_fault_manager(config_data);
 	cleanup_hotplug_manager();
 	cleanup_state_change_manager(config_data);
-	cleanup_plugin_manager();
 	config_fini();
 }
 
@@ -121,10 +120,8 @@
 	 */
 	block_state_change_events();
 
-	if (init_plugin_manager() != 0)
+	if (dm_platform_init() != 0)
 		goto cleanup;
-	else
-		g_init_state |= PLUGIN_MGR_INITTED;
 
 	if (init_hotplug_manager() != 0)
 		goto cleanup;
@@ -157,8 +154,7 @@
 		cleanup_hotplug_manager();
 	if (g_init_state & STATE_CHANGE_MGR_INITTED)
 		cleanup_state_change_manager(config_data);
-	if (g_init_state & PLUGIN_MGR_INITTED)
-		cleanup_plugin_manager();
+	dm_platform_fini();
 
 	return (E_ERROR);
 }
@@ -197,7 +193,6 @@
 {
 	const char		*action_prop = NULL;
 	const char		*action_string;
-	dm_plugin_error_t	rv;
 
 	/*
 	 * The predictive failure action is the activation of the fault
@@ -221,8 +216,7 @@
 	    (action_string = dm_prop_lookup(diskp->props, action_prop))
 	    != NULL) {
 
-		rv = dm_pm_indicator_execute(action_string);
-		if (rv != DMPE_SUCCESS) {
+		if (dm_platform_indicator_execute(action_string) != 0) {
 			log_warn("Fault action `%s' did not successfully "
 			    "complete.\n", action_string);
 		}
@@ -390,11 +384,11 @@
 
 	fltclass =
 	    fmd_nvl_class_match(hdl, nvl, EREPORT_SATA_PREDFAIL) ?
-		FAULT_DISK_PREDFAIL :
+	    FAULT_DISK_PREDFAIL :
 	    fmd_nvl_class_match(hdl, nvl, EREPORT_SATA_OVERTEMP) ?
-		FAULT_DISK_OVERTEMP :
+	    FAULT_DISK_OVERTEMP :
 	    fmd_nvl_class_match(hdl, nvl, EREPORT_SATA_STFAIL) ?
-		FAULT_DISK_STFAIL : NULL;
+	    FAULT_DISK_STFAIL : NULL;
 
 	if (fltclass != NULL) {
 
@@ -432,8 +426,6 @@
 	 * OPTION_OVERTEMP_ERRS_ARE_FATAL) == 0xC
 	 */
 	{ GLOBAL_PROP_FAULT_OPTIONS, FMD_TYPE_UINT32, "0xC" },
-	{ GLOBAL_PROP_IPMI_BMC_MON, FMD_TYPE_UINT32, "1" },
-	{ GLOBAL_PROP_IPMI_ERR_INJ, FMD_TYPE_UINT32, "0" },
 	{ NULL, 0, NULL }
 };
 
--- a/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/util.h	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/cmd/fm/modules/i86pc/sfx4500-disk/util.h	Sat Mar 10 17:17:25 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -99,7 +99,6 @@
 	MM_FLTANALYZE	= 0x0010,
 	MM_SCSI		= 0x0020,
 	MM_MAIN		= 0x0040,
-	MM_PLUGIN	= 0x0080,
 	MM_TOPO 	= 0x0100,
 	MM_ERR		= 0x0200,
 	MM_WARN		= 0x0400,
--- a/usr/src/lib/Makefile	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/lib/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -229,6 +229,7 @@
 	policykit	\
 	hal		\
 	libshare	\
+	libipmi		\
 	$($(MACH)_SUBDIRS)
 
 sparc_SUBDIRS= .WAIT	\
@@ -343,6 +344,7 @@
 	libinetcfg	\
 	libinetsvc	\
 	libinetutil	\
+	libipmi		\
 	libipmp		\
 	libipp		\
 	libiscsitgt	\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include		../Makefile.lib
+
+HDRS=		libipmi.h
+
+HDRDIR=		common
+
+SUBDIRS=	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all :=		TARGET= all
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+install :=	TARGET= install
+lint :=		TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS) 
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/Makefile.com	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+LIBRARY=	libipmi.a
+VERS=		.1
+
+OBJECTS=	ipmi_bmc.o	\
+		ipmi_misc.o	\
+		ipmi_sdr.o	\
+		ipmi_sensor.o	\
+		ipmi_sunoem.o	\
+		ipmi_util.o	\
+		libipmi.o
+
+SRCS=		$(OBJECTS:%.o:$(SRCDIR)/%c.)
+
+include ../../Makefile.lib
+
+LIBS=		$(DYNLIB) $(LINTLIB)
+
+SRCDIR=		../common
+
+INCS +=		-I$(SRCDIR)
+LDLIBS +=	-lc
+CPPFLAGS +=	$(INCS)
+
+$(LINTLIB) := SRCS=	$(SRCDIR)/$(LINTSRC)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/amd64/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_bmc.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,186 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libipmi.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stropts.h>
+#include <unistd.h>
+
+#include <sys/bmc_intf.h>
+
+#include "ipmi_impl.h"
+
+/*
+ * IPMI transport for /dev/bmc
+ */
+
+typedef struct ipmi_bmc {
+	ipmi_handle_t	*ib_ihp;	/* ipmi handle */
+	int		ib_fd;		/* /dev/bmc filedescriptor */
+	uint32_t	ib_msgseq;	/* message sequence number */
+	bmc_msg_t	*ib_msg;	/* message buffer */
+	size_t		ib_msglen;	/* size of message buffer */
+} ipmi_bmc_t;
+
+#define	BMC_DEV	"/dev/bmc"
+
+static void
+ipmi_bmc_close(void *data)
+{
+	ipmi_bmc_t *ibp = data;
+
+	ipmi_free(ibp->ib_ihp, ibp->ib_msg);
+
+	(void) close(ibp->ib_fd);
+
+	ipmi_free(ibp->ib_ihp, ibp);
+}
+
+static void *
+ipmi_bmc_open(ipmi_handle_t *ihp)
+{
+	ipmi_bmc_t *ibp;
+
+	if ((ibp = ipmi_zalloc(ihp, sizeof (ipmi_bmc_t))) == NULL)
+		return (NULL);
+	ibp->ib_ihp = ihp;
+
+	/* open /dev/bmc */
+	if ((ibp->ib_fd = open(BMC_DEV, O_RDWR)) < 0) {
+		ipmi_free(ihp, ibp);
+		(void) ipmi_set_error(ihp, EIPMI_BMC_OPEN_FAILED, "%s",
+		    strerror(errno));
+		return (NULL);
+	}
+
+	if ((ibp->ib_msg = (bmc_msg_t *)ipmi_zalloc(ihp, BUFSIZ)) == NULL) {
+		ipmi_bmc_close(ibp);
+		return (NULL);
+	}
+	ibp->ib_msglen = BUFSIZ;
+
+	return (ibp);
+}
+
+static int
+ipmi_bmc_send(void *data, ipmi_cmd_t *cmd, ipmi_cmd_t *response,
+    int *completion)
+{
+	ipmi_bmc_t *ibp = data;
+	struct strbuf sb;
+	int flags = 0;
+	size_t msgsz;
+	bmc_msg_t *msg;
+	bmc_req_t *bmcreq;
+	bmc_rsp_t *bmcrsp;
+
+	/*
+	 * The length of the message structure is equal to the size of the
+	 * bmc_req_t structure, PLUS any additional data space in excess of
+	 * the data space already reserved in the data member + <n> for
+	 * the rest of the members in the bmc_msg_t structure.
+	 */
+	msgsz = offsetof(bmc_msg_t, msg) + sizeof (bmc_req_t) +
+	    ((cmd->ic_dlen > SEND_MAX_PAYLOAD_SIZE) ?
+	    (cmd->ic_dlen - SEND_MAX_PAYLOAD_SIZE) : 0);
+
+	/* construct and send the message */
+	if ((msg = ipmi_zalloc(ibp->ib_ihp, msgsz)) == NULL)
+		return (-1);
+	bmcreq = (bmc_req_t *)&msg->msg[0];
+
+	msg->m_type = BMC_MSG_REQUEST;
+	msg->m_id = ibp->ib_msgseq++;
+	bmcreq->fn = cmd->ic_netfn;
+	bmcreq->lun = cmd->ic_lun;
+	bmcreq->cmd = cmd->ic_cmd;
+	bmcreq->datalength = cmd->ic_dlen;
+	(void) memcpy(bmcreq->data, cmd->ic_data, cmd->ic_dlen);
+	sb.len = msgsz;
+	sb.buf = (char *)msg;
+
+	if (putmsg(ibp->ib_fd, NULL, &sb, 0) < 0) {
+		ipmi_free(ibp->ib_ihp, msg);
+		(void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_PUTMSG, "%s",
+		    strerror(errno));
+		return (-1);
+	}
+
+	ipmi_free(ibp->ib_ihp, msg);
+
+	/* get the response from the BMC */
+	sb.buf = (char *)ibp->ib_msg;
+	sb.maxlen = ibp->ib_msglen;
+
+	if (getmsg(ibp->ib_fd, NULL, &sb, &flags) < 0) {
+		(void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_GETMSG, "%s",
+		    strerror(errno));
+		return (-1);
+	}
+
+	switch (ibp->ib_msg->m_type) {
+	case BMC_MSG_RESPONSE:
+		bmcrsp = (bmc_rsp_t *)&ibp->ib_msg->msg[0];
+
+		response->ic_netfn = bmcrsp->fn;
+		response->ic_lun = bmcrsp->lun;
+		response->ic_cmd = bmcrsp->cmd;
+		if (bmcrsp->ccode != 0) {
+			*completion = bmcrsp->ccode;
+			response->ic_dlen = 0;
+			response->ic_data = NULL;
+		} else {
+			*completion = 0;
+			response->ic_dlen = bmcrsp->datalength;
+			response->ic_data = bmcrsp->data;
+		}
+		break;
+
+	case BMC_MSG_ERROR:
+		(void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE, "%s",
+		    strerror(ibp->ib_msg->msg[0]));
+		return (-1);
+
+	default:
+		(void) ipmi_set_error(ibp->ib_ihp, EIPMI_BMC_RESPONSE,
+		    "unknown BMC message type %d", ibp->ib_msg->m_type);
+		return (-1);
+	}
+
+	return (0);
+}
+
+ipmi_transport_t ipmi_transport_bmc = {
+	ipmi_bmc_open,
+	ipmi_bmc_close,
+	ipmi_bmc_send
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_impl.h	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_IPMI_IMPL_H
+#define	_IPMI_IMPL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+struct ipmi_sdr_generic_locator;
+struct ipmi_sdr_fru_locator;
+
+typedef struct ipmi_sdr_cache_ent {
+	uint8_t				isc_type;
+	struct ipmi_sdr_generic_locator	*isc_generic;
+	struct ipmi_sdr_fru_locator	*isc_fru;
+	struct ipmi_sdr_cache_ent	*isc_next;
+} ipmi_sdr_cache_ent_t;
+
+typedef struct ipmi_transport {
+	void *		(*it_open)(struct ipmi_handle *);
+	void		(*it_close)(void *);
+	int 		(*it_send)(void *, struct ipmi_cmd *, struct ipmi_cmd *,
+			    int *);
+} ipmi_transport_t;
+
+struct ipmi_handle {
+	ipmi_transport_t	*ih_transport;
+	void			*ih_tdata;
+	ipmi_cmd_t		ih_response;
+	int			ih_errno;
+	uint16_t		ih_reservation;
+	int			ih_retries;
+	ipmi_sdr_cache_ent_t	*ih_sdr_cache;
+	ipmi_deviceid_t		ih_deviceid;
+	boolean_t		ih_deviceid_valid;
+	char			ih_errmsg[1024];
+	char			ih_errbuf[1024];
+};
+
+/*
+ * Error handling
+ */
+extern int ipmi_set_error(ipmi_handle_t *, int, const char *, ...);
+
+/*
+ * Memory allocation
+ */
+extern void *ipmi_alloc(ipmi_handle_t *, size_t);
+extern void *ipmi_zalloc(ipmi_handle_t *, size_t);
+extern void ipmi_free(ipmi_handle_t *, void *);
+extern void *impi_realloc(ipmi_handle_t *, void *, size_t);
+
+/*
+ * Supported transports
+ */
+extern ipmi_transport_t ipmi_transport_bmc;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _IPMI_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_misc.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <string.h>
+
+#include "ipmi_impl.h"
+
+ipmi_deviceid_t *
+ipmi_get_deviceid(ipmi_handle_t *ihp)
+{
+	ipmi_cmd_t cmd, *resp;
+
+	if (ihp->ih_deviceid_valid)
+		return (&ihp->ih_deviceid);
+
+	cmd.ic_netfn = IPMI_NETFN_APP;
+	cmd.ic_lun = 0;
+	cmd.ic_cmd = IPMI_CMD_GET_DEVICEID;
+	cmd.ic_data = NULL;
+	cmd.ic_dlen = 0;
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (NULL);
+
+	if (resp->ic_dlen < sizeof (ipmi_deviceid_t)) {
+		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
+		return (NULL);
+	}
+
+	(void) memcpy(&ihp->ih_deviceid, resp->ic_data,
+	    sizeof (ipmi_deviceid_t));
+	ihp->ih_deviceid.id_product = LE_16(ihp->ih_deviceid.id_product);
+	ihp->ih_deviceid_valid = B_TRUE;
+
+	return (&ihp->ih_deviceid);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_sdr.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,234 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "ipmi_impl.h"
+
+typedef struct ipmi_cmd_get_sdr {
+	uint16_t	ic_gs_resid;
+	uint16_t	ic_gs_recid;
+	uint8_t		ic_gs_offset;
+	uint8_t		ic_gs_len;
+} ipmi_cmd_get_sdr_t;
+
+typedef struct ipmi_rsp_get_sdr {
+	uint16_t	ir_gs_next;
+	uint8_t		ir_gs_record[1];
+} ipmi_rsp_get_sdr_t;
+
+/*
+ * Issue the "Reserve SDR Repository" command.
+ */
+static int
+ipmi_sdr_reserve_repository(ipmi_handle_t *ihp)
+{
+	ipmi_cmd_t cmd, *rsp;
+
+	cmd.ic_netfn = IPMI_NETFN_STORAGE;
+	cmd.ic_lun = 0;
+	cmd.ic_cmd = IPMI_CMD_RESERVE_SDR_REPOSITORY;
+	cmd.ic_dlen = 0;
+	cmd.ic_data = NULL;
+
+	if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
+		return (-1);
+
+	ihp->ih_reservation = *((uint16_t *)rsp->ic_data);
+	return (0);
+}
+
+/*
+ * Refresh the cache of sensor data records.
+ */
+static int
+ipmi_sdr_refresh(ipmi_handle_t *ihp)
+{
+	size_t len;
+	uint16_t id;
+	ipmi_sdr_t *sdr;
+	ipmi_sdr_cache_ent_t *ent;
+	ipmi_sdr_generic_locator_t *gen_src, *gen_dst;
+	ipmi_sdr_fru_locator_t *fru_src, *fru_dst;
+
+	/*
+	 * Free any existing SDRs.
+	 */
+	while (ihp->ih_sdr_cache != NULL) {
+		ent = ihp->ih_sdr_cache->isc_next;
+		ipmi_free(ihp, ent->isc_generic);
+		ipmi_free(ihp, ent->isc_fru);
+		ipmi_free(ihp, ent);
+		ihp->ih_sdr_cache = ent;
+	}
+
+	/*
+	 * Iterate over all existing SDRs and add them to the cache.
+	 */
+	id = IPMI_SDR_FIRST;
+	while (id != IPMI_SDR_LAST) {
+		if ((sdr = ipmi_sdr_get(ihp, id, &id)) == NULL)
+			return (-1);
+
+		/*
+		 * We currently only understand FRU and generic device records.
+		 */
+		if (sdr->is_type != IPMI_SDR_TYPE_GENERIC_LOCATOR &&
+		    sdr->is_type != IPMI_SDR_TYPE_FRU_LOCATOR)
+			continue;
+
+		/*
+		 * Create a copy of the SDR-specific data.
+		 */
+		gen_dst = NULL;
+		fru_dst = NULL;
+		switch (sdr->is_type) {
+		case IPMI_SDR_TYPE_GENERIC_LOCATOR:
+			gen_src = (ipmi_sdr_generic_locator_t *)sdr->is_record;
+			len = offsetof(ipmi_sdr_generic_locator_t,
+			    is_gl_idstring) + gen_src->is_gl_idlen + 1;
+			if ((gen_dst = ipmi_alloc(ihp, len)) == NULL)
+				return (-1);
+			(void) memcpy(gen_dst, gen_src, len - 1);
+			((char *)gen_dst)[len - 1] = '\0';
+			break;
+
+		case IPMI_SDR_TYPE_FRU_LOCATOR:
+			fru_src = (ipmi_sdr_fru_locator_t *)sdr->is_record;
+			len = offsetof(ipmi_sdr_fru_locator_t,
+			    is_fl_idstring) + fru_src->is_fl_idlen + 1;
+			if ((fru_dst = ipmi_alloc(ihp, len)) == NULL)
+				return (-1);
+			(void) memcpy(fru_dst, fru_src, len - 1);
+			((char *)fru_dst)[len - 1] = '\0';
+			break;
+		}
+
+		if ((ent = ipmi_alloc(ihp,
+		    sizeof (ipmi_sdr_cache_ent_t))) == NULL) {
+			ipmi_free(ihp, gen_dst);
+			ipmi_free(ihp, fru_dst);
+		}
+
+		ent->isc_generic = gen_dst;
+		ent->isc_fru = fru_dst;
+		ent->isc_next = ihp->ih_sdr_cache;
+		ent->isc_type = sdr->is_type;
+		ihp->ih_sdr_cache = ent;
+	}
+
+	return (0);
+}
+
+ipmi_sdr_t *
+ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next)
+{
+	ipmi_cmd_t cmd, *rsp;
+	ipmi_cmd_get_sdr_t req;
+	ipmi_rsp_get_sdr_t *sdr;
+	int i;
+
+	req.ic_gs_resid = ihp->ih_reservation;
+	req.ic_gs_recid = id;
+	req.ic_gs_offset = 0;
+	req.ic_gs_len = 0xFF;
+
+	cmd.ic_netfn = IPMI_NETFN_STORAGE;
+	cmd.ic_lun = 0;
+	cmd.ic_cmd = IPMI_CMD_GET_SDR;
+	cmd.ic_dlen = sizeof (req);
+	cmd.ic_data = &req;
+
+	for (i = 0; i < ihp->ih_retries; i++) {
+		if ((rsp = ipmi_send(ihp, &cmd)) == NULL) {
+			if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION)
+				return (NULL);
+
+			if (ipmi_sdr_reserve_repository(ihp) != 0)
+				return (NULL);
+			req.ic_gs_resid = ihp->ih_reservation;
+		}
+	}
+
+	if (rsp == NULL)
+		return (NULL);
+
+	if (rsp->ic_dlen < sizeof (uint16_t) + sizeof (ipmi_sdr_t)) {
+		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
+		return (NULL);
+	}
+
+	sdr = rsp->ic_data;
+	*next = sdr->ir_gs_next;
+
+	return ((ipmi_sdr_t *)sdr->ir_gs_record);
+}
+
+ipmi_sdr_fru_locator_t *
+ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr)
+{
+	ipmi_sdr_cache_ent_t *ent;
+
+	if (ihp->ih_sdr_cache == NULL &&
+	    ipmi_sdr_refresh(ihp) != 0)
+		return (NULL);
+
+	for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) {
+		if (ent->isc_type != IPMI_SDR_TYPE_FRU_LOCATOR)
+			continue;
+
+		if (strcmp(ent->isc_fru->is_fl_idstring, idstr) == 0)
+			return (ent->isc_fru);
+	}
+
+	(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+	return (NULL);
+}
+
+ipmi_sdr_generic_locator_t *
+ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr)
+{
+	ipmi_sdr_cache_ent_t *ent;
+
+	if (ihp->ih_sdr_cache == NULL &&
+	    ipmi_sdr_refresh(ihp) != 0)
+		return (NULL);
+
+	for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) {
+		if (ent->isc_type != IPMI_SDR_TYPE_GENERIC_LOCATOR)
+			continue;
+
+		if (strcmp(ent->isc_generic->is_gl_idstring, idstr) == 0)
+			return (ent->isc_generic);
+	}
+
+	(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+	return (NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_sensor.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,94 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <string.h>
+
+#include "ipmi_impl.h"
+
+ipmi_sensor_reading_t *
+ipmi_get_sensor_reading(ipmi_handle_t *ihp, uint8_t id)
+{
+	ipmi_cmd_t cmd, *resp;
+	ipmi_sensor_reading_t *srp;
+
+	cmd.ic_netfn = IPMI_NETFN_SE;
+	cmd.ic_cmd = IPMI_CMD_GET_SENSOR_READING;
+	cmd.ic_lun = 0;
+	cmd.ic_data = &id;
+	cmd.ic_dlen = sizeof (id);
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (NULL);
+
+	/*
+	 * The upper half of the state field is optional, so if it's not
+	 * present, then set it to zero.  We also need to convert to the
+	 * native endianness.
+	 */
+	if (resp->ic_dlen < sizeof (ipmi_sensor_reading_t) - sizeof (uint8_t)) {
+		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
+		return (NULL);
+	}
+	srp = resp->ic_data;
+
+	if (resp->ic_dlen < sizeof (ipmi_sensor_reading_t))
+		(void) memset((char *)srp + resp->ic_dlen, '\0',
+		    sizeof (ipmi_sensor_reading_t) - resp->ic_dlen);
+
+	srp->isr_state = LE_16(srp->isr_state);
+	return (srp);
+}
+
+int
+ipmi_set_sensor_reading(ipmi_handle_t *ihp, ipmi_set_sensor_reading_t *req)
+{
+	ipmi_set_sensor_reading_t realreq;
+	ipmi_cmd_t cmd, *resp;
+
+	/*
+	 * Convert states to little endian.
+	 */
+	(void) memcpy(&realreq, req, sizeof (realreq));
+
+	realreq.iss_assert_state = LE_16(realreq.iss_assert_state);
+	realreq.iss_deassert_state = LE_16(realreq.iss_deassert_state);
+
+	cmd.ic_netfn = IPMI_NETFN_SE;
+	cmd.ic_cmd = IPMI_CMD_SET_SENSOR_READING;
+	cmd.ic_lun = 0;
+	cmd.ic_data = &realreq;
+	cmd.ic_dlen = sizeof (realreq);
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (-1);
+
+	if (resp->ic_dlen != 0)
+		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_sunoem.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,194 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <stddef.h>
+
+#include "ipmi_impl.h"
+
+static int
+check_sunoem(ipmi_handle_t *ihp)
+{
+	ipmi_deviceid_t *devid;
+
+	if ((devid = ipmi_get_deviceid(ihp)) == NULL)
+		return (-1);
+
+	if (ipmi_devid_manufacturer(devid) != IPMI_OEM_SUN)
+		return (ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, NULL));
+
+	return (0);
+}
+
+static int
+ipmi_send_sunoem_led_set(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_set_t *req)
+{
+	ipmi_cmd_t cmd, *resp;
+
+	cmd.ic_netfn = IPMI_NETFN_OEM;
+	cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_SET;
+	cmd.ic_lun = 0;
+	cmd.ic_data = req;
+	cmd.ic_dlen = sizeof (*req);
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (-1);
+
+	if (resp->ic_dlen != 0)
+		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+
+	return (0);
+}
+
+static int
+ipmi_send_sunoem_led_get(ipmi_handle_t *ihp, ipmi_cmd_sunoem_led_get_t *req,
+    uint8_t *result)
+{
+	ipmi_cmd_t cmd, *resp;
+
+	cmd.ic_netfn = IPMI_NETFN_OEM;
+	cmd.ic_cmd = IPMI_CMD_SUNOEM_LED_GET;
+	cmd.ic_lun = 0;
+	cmd.ic_data = req;
+	cmd.ic_dlen = sizeof (*req);
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (-1);
+
+	if (resp->ic_dlen != 1)
+		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+
+	*result = *((uint8_t *)resp->ic_data);
+	return (0);
+}
+
+int
+ipmi_sunoem_led_set(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev,
+    uint8_t mode)
+{
+	ipmi_cmd_sunoem_led_set_t cmd = { 0 };
+
+	if (check_sunoem(ihp) != 0)
+		return (-1);
+
+	cmd.ic_sls_devaddr = dev->is_gl_slaveaddr;
+	cmd.ic_sls_type = dev->is_gl_oem;
+	cmd.ic_sls_ctladdr = dev->is_gl_accessaddr;
+	cmd.ic_sls_hwinfo = dev->is_gl_oem;
+	cmd.ic_sls_mode = mode;
+
+	return (ipmi_send_sunoem_led_set(ihp, &cmd));
+}
+
+int
+ipmi_sunoem_led_get(ipmi_handle_t *ihp, ipmi_sdr_generic_locator_t *dev,
+    uint8_t *mode)
+{
+	ipmi_cmd_sunoem_led_get_t cmd = { 0 };
+
+	if (check_sunoem(ihp) != 0)
+		return (-1);
+
+	cmd.ic_slg_devaddr = dev->is_gl_slaveaddr;
+	cmd.ic_slg_type = dev->is_gl_oem;
+	cmd.ic_slg_ctladdr = dev->is_gl_accessaddr;
+	cmd.ic_slg_hwinfo = dev->is_gl_oem;
+
+	return (ipmi_send_sunoem_led_get(ihp, &cmd, mode));
+}
+
+int
+ipmi_sunoem_uptime(ipmi_handle_t *ihp, uint32_t *uptime, uint32_t *gen)
+{
+	ipmi_cmd_t cmd, *resp;
+	uint8_t unused;
+
+	if (check_sunoem(ihp) != 0)
+		return (-1);
+
+	cmd.ic_netfn = IPMI_NETFN_OEM;
+	cmd.ic_lun = 0;
+	cmd.ic_cmd = IPMI_CMD_SUNOEM_UPTIME;
+	cmd.ic_dlen = sizeof (unused);
+	cmd.ic_data = &unused;
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (-1);
+
+	if (resp->ic_dlen != 2 * sizeof (uint32_t))
+		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+
+	if (uptime)
+		*uptime = BE_32(((uint32_t *)resp->ic_data)[0]);
+	if (gen)
+		*gen = BE_32(((uint32_t *)resp->ic_data)[1]);
+
+	return (0);
+}
+
+int
+ipmi_sunoem_update_fru(ipmi_handle_t *ihp, ipmi_sunoem_fru_t *req)
+{
+	ipmi_cmd_t cmd, *resp;
+
+	if (check_sunoem(ihp) != 0)
+		return (-1);
+
+	switch (req->isf_type) {
+	case IPMI_SUNOEM_FRU_DIMM:
+		req->isf_datalen = sizeof (req->isf_data.dimm);
+		break;
+
+	case IPMI_SUNOEM_FRU_CPU:
+		req->isf_datalen = sizeof (req->isf_data.cpu);
+		break;
+
+	case IPMI_SUNOEM_FRU_BIOS:
+		req->isf_datalen = sizeof (req->isf_data.bios);
+		break;
+
+	case IPMI_SUNOEM_FRU_DISK:
+		req->isf_datalen = sizeof (req->isf_data.disk);
+		break;
+	}
+
+	cmd.ic_netfn = IPMI_NETFN_OEM;
+	cmd.ic_cmd = IPMI_CMD_SUNOEM_FRU_UPDATE;
+	cmd.ic_lun = 0;
+	cmd.ic_dlen = offsetof(ipmi_sunoem_fru_t, isf_data) +
+	    req->isf_datalen;
+	cmd.ic_data = req;
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (-1);
+
+	if (resp->ic_dlen != 0)
+		return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_util.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,147 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "ipmi_impl.h"
+
+/*
+ * Error handling
+ */
+int
+ipmi_set_error(ipmi_handle_t *ihp, int error, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	ihp->ih_errno = error;
+	if (fmt == NULL)
+		ihp->ih_errmsg[0] = '\0';
+	else
+		(void) vsnprintf(ihp->ih_errmsg, sizeof (ihp->ih_errmsg),
+		    fmt, ap);
+	va_end(ap);
+
+	return (-1);
+}
+
+int
+ipmi_errno(ipmi_handle_t *ihp)
+{
+	return (ihp->ih_errno);
+}
+
+static struct {
+	int		err;
+	const char	*msg;
+} errno_table[] = {
+	{ EIPMI_NOMEM,			"memory allocation failure" },
+	{ EIPMI_BMC_OPEN_FAILED,	"failed to open /dev/bmc" },
+	{ EIPMI_BMC_PUTMSG,		"failed to send message to /dev/bmc" },
+	{ EIPMI_BMC_GETMSG,
+	    "failed to read response from /dev/bmc" },
+	{ EIPMI_BMC_RESPONSE,
+	    "failed to read response from /dev/bmc" },
+	{ EIPMI_INVALID_COMMAND,	"invalid command" },
+	{ EIPMI_COMMAND_TIMEOUT,	"command timed out" },
+	{ EIPMI_DATA_LENGTH_EXCEEDED,	"maximum data length exceeded" },
+	{ EIPMI_SEND_FAILED,		"failed to send BMC request" },
+	{ EIPMI_UNSPECIFIED,		"unspecified BMC error" },
+	{ EIPMI_BAD_RESPONSE_LENGTH,
+	    "unexpected command response data length" },
+	{ EIPMI_INVALID_RESERVATION,	"invalid or cancelled reservation" },
+	{ EIPMI_NOT_PRESENT,		"request entity not present" },
+	{ EIPMI_INVALID_REQUEST,	"malformed request data" },
+	{ EIPMI_BUSY,			"service processor is busy" },
+	{ EIPMI_NOSPACE,		"service processor is out of space" },
+	{ EIPMI_UNAVAILABLE,		"service processor is unavailable" },
+	{ EIPMI_ACCESS,			"insufficient privileges" }
+};
+
+/* ARGSUSED */
+const char *
+ipmi_errmsg(ipmi_handle_t *ihp)
+{
+	int i;
+	const char *str;
+
+	str = NULL;
+	for (i = 0; i < sizeof (errno_table) / sizeof (errno_table[0]); i++) {
+		if (errno_table[i].err == ihp->ih_errno) {
+			str = errno_table[i].msg;
+			break;
+		}
+	}
+
+	if (str == NULL && (str = strerror(ihp->ih_errno)) == NULL)
+		str = "unknown failure";
+
+	if (ihp->ih_errmsg[0] == '\0')
+		return (str);
+
+	(void) snprintf(ihp->ih_errbuf, sizeof (ihp->ih_errbuf),
+	    "%s: %s", str, ihp->ih_errmsg);
+	return (ihp->ih_errbuf);
+}
+
+/*
+ * Memory allocation
+ */
+
+void *
+ipmi_alloc(ipmi_handle_t *ihp, size_t size)
+{
+	void *ptr;
+
+	if ((ptr = malloc(size)) == NULL)
+		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
+
+	return (ptr);
+}
+
+void *
+ipmi_zalloc(ipmi_handle_t *ihp, size_t size)
+{
+	void *ptr;
+
+	if ((ptr = calloc(size, 1)) == NULL)
+		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
+
+	return (ptr);
+}
+
+/* ARGSUSED */
+void
+ipmi_free(ipmi_handle_t *ihp, void *ptr)
+{
+	free(ptr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/libipmi.c	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <string.h>
+
+#include <sys/bmc_intf.h>
+
+#include "ipmi_impl.h"
+
+ipmi_handle_t *
+ipmi_open(int *errp, char **msg)
+{
+	ipmi_handle_t *ihp;
+
+	if (msg)
+		*msg = NULL;
+
+	if ((ihp = calloc(sizeof (ipmi_handle_t), 1)) == NULL) {
+		*errp = EIPMI_NOMEM;
+		if (msg)
+			*msg = "memory allocation failure";
+		return (NULL);
+	}
+
+	/* /dev/bmc is the only currently available transport */
+	ihp->ih_transport = &ipmi_transport_bmc;
+
+	ihp->ih_retries = 3;
+
+	if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp)) == NULL) {
+		*errp = ihp->ih_errno;
+		if (msg) {
+			if ((*msg = strdup(ipmi_errmsg(ihp))) == NULL)
+				*msg = "memory allocation failure";
+		}
+		ipmi_close(ihp);
+		return (NULL);
+	}
+
+	return (ihp);
+}
+
+void
+ipmi_close(ipmi_handle_t *ihp)
+{
+	if (ihp->ih_transport && ihp->ih_tdata)
+		ihp->ih_transport->it_close(ihp->ih_tdata);
+	free(ihp);
+}
+
+/*
+ * See section 5.2 for a description of the completion codes.
+ */
+static struct ipmi_err_conv {
+	int	bmc_err;
+	int	ipmi_err;
+} ipmi_errtable[] = {
+	{ 0xC0,			EIPMI_BUSY },
+	{ 0xC1,			EIPMI_INVALID_COMMAND },
+	{ 0xC2,			EIPMI_INVALID_COMMAND },
+	{ 0xC3,			EIPMI_COMMAND_TIMEOUT },
+	{ 0xC4,			EIPMI_NOSPACE },
+	{ 0xC5,			EIPMI_INVALID_RESERVATION },
+	{ 0xC6,			EIPMI_INVALID_REQUEST },
+	{ 0xC7,			EIPMI_INVALID_REQUEST },
+	{ 0xC8,			EIPMI_INVALID_REQUEST },
+	{ 0xC9,			EIPMI_INVALID_REQUEST },
+	{ 0xCA,			EIPMI_DATA_LENGTH_EXCEEDED },
+	{ 0xCB,			EIPMI_NOT_PRESENT },
+	{ 0xCC,			EIPMI_INVALID_REQUEST },
+	{ 0xCD,			EIPMI_INVALID_COMMAND },
+	{ 0xCE,			EIPMI_UNAVAILABLE },
+	{ 0xCF,			EIPMI_UNAVAILABLE },
+	{ 0xD0,			EIPMI_BUSY },
+	{ 0xD1,			EIPMI_BUSY },
+	{ 0xD2,			EIPMI_BUSY },
+	{ 0xD3,			EIPMI_NOT_PRESENT },
+	{ 0xD4,			EIPMI_ACCESS },
+	{ 0xD5,			EIPMI_UNAVAILABLE },
+	{ 0xD6,			EIPMI_UNAVAILABLE },
+	{ 0xFF,			EIPMI_UNSPECIFIED },
+	{ BMC_IPMI_OEM_FAILURE_SENDBMC,	EIPMI_SEND_FAILED },
+};
+
+#define	IPMI_ERROR_COUNT \
+	(sizeof (ipmi_errtable) / sizeof (ipmi_errtable[0]))
+
+ipmi_cmd_t *
+ipmi_send(ipmi_handle_t *ihp, ipmi_cmd_t *cmd)
+{
+	int completion;
+	int i;
+
+	if (ihp->ih_transport->it_send(ihp->ih_tdata, cmd, &ihp->ih_response,
+	    &completion) != 0)
+		return (NULL);
+
+	if (completion != 0) {
+		for (i = 0; i < IPMI_ERROR_COUNT; i++) {
+			if (completion == ipmi_errtable[i].bmc_err) {
+				(void) ipmi_set_error(ihp,
+				    ipmi_errtable[i].ipmi_err,
+				    "IPMI completion code 0x%x", completion);
+				return (NULL);
+			}
+		}
+
+		(void) ipmi_set_error(ihp, EIPMI_UNKNOWN,
+		    "IPMI completion code 0x%x", completion);
+		return (NULL);
+	}
+
+	return (&ihp->ih_response);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/libipmi.h	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,503 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_LIBIPMI_H
+#define	_LIBIPMI_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/bmc_intf.h>
+#include <sys/byteorder.h>
+
+/*
+ * Private interfaces for communicating with attached services over IPMI.  This
+ * library is designed for system software communicating with Sun-supported
+ * service processors over /dev/bmc.  It is not a generic IPMI library.
+ *
+ * Documentation references refer to "Intelligent Platform Management Interface
+ * Specification Second Generation v2.0", document revision 1.0 with Februrary
+ * 15, 2006 Markup from "IPMI v2.0 Addenda, Errata, and Clarifications Revision
+ * 3".
+ */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct ipmi_handle ipmi_handle_t;
+
+#if !defined(_BIT_FIELDS_LTOH) && !defined(_BIT_FIELDS_HTOL)
+#error  One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
+#pragma pack(1)
+
+/*
+ * Basic netfn definitions.  See section 5.1.
+ */
+#define	IPMI_NETFN_APP			BMC_NETFN_APP
+#define	IPMI_NETFN_STORAGE		BMC_NETFN_STORAGE
+#define	IPMI_NETFN_SE			BMC_NETFN_SE
+#define	IPMI_NETFN_OEM			0x2e
+
+/*
+ * Error definitions
+ */
+#define	EIPMI_BASE	2000
+
+enum {
+	EIPMI_NOMEM = EIPMI_BASE,	/* memory allocation failure */
+	EIPMI_BMC_OPEN_FAILED,		/* failed to open /dev/bmc */
+	EIPMI_BMC_PUTMSG,		/* putmsg() failed */
+	EIPMI_BMC_GETMSG,		/* getmsg() failed */
+	EIPMI_BMC_RESPONSE,		/* response from /dev/bmc failed */
+	EIPMI_INVALID_COMMAND,		/* invalid command */
+	EIPMI_COMMAND_TIMEOUT,		/* command timeout */
+	EIPMI_DATA_LENGTH_EXCEEDED,	/* maximum data length exceeded */
+	EIPMI_SEND_FAILED,		/* failed to send BMC request */
+	EIPMI_UNSPECIFIED,		/* unspecified error */
+	EIPMI_UNKNOWN,			/* unknown error */
+	EIPMI_BAD_RESPONSE,		/* received unexpected response */
+	EIPMI_BAD_RESPONSE_LENGTH,	/* unexpected response length */
+	EIPMI_INVALID_RESERVATION,	/* invalid reservation */
+	EIPMI_NOT_PRESENT,		/* requested entity not present */
+	EIPMI_INVALID_REQUEST,		/* malformed request */
+	EIPMI_BUSY,			/* SP is busy */
+	EIPMI_NOSPACE,			/* SP is out of space */
+	EIPMI_UNAVAILABLE,		/* SP is present but unavailable */
+	EIPMI_ACCESS			/* insufficient privileges */
+};
+
+/*
+ * Basic library functions.
+ *
+ * The ipmi_handle is the primary interface to the library.  The library itself
+ * is not MT-safe, but it is safe within a single handle.  Multithreaded clients
+ * should either open multiple handles, or otherwise synchronize access to the
+ * same handle.
+ *
+ * There is a single command response buffer that is stored with the handle, to
+ * simplify memory management in the caller.  The memory referenced by a command
+ * response is only valid until the next command is issued.  The caller is
+ * responsible for making a copy of the response if it is needed.
+ */
+extern ipmi_handle_t *ipmi_open(int *, char **);
+extern void ipmi_close(ipmi_handle_t *);
+
+extern int ipmi_errno(ipmi_handle_t *);
+extern const char *ipmi_errmsg(ipmi_handle_t *);
+
+/*
+ * Raw requests.  See section 5.
+ */
+typedef struct ipmi_cmd {
+	uint8_t		ic_netfn:6;
+	uint8_t		ic_lun:2;
+	uint8_t		ic_cmd;
+	uint16_t	ic_dlen;
+	void		*ic_data;
+} ipmi_cmd_t;
+
+extern ipmi_cmd_t *ipmi_send(ipmi_handle_t *, ipmi_cmd_t *);
+
+/*
+ * Retrieve basic information about the IPMI device.  See section 20.1 "Get
+ * Device ID Command".
+ */
+#define	IPMI_CMD_GET_DEVICEID		0x01
+
+typedef struct ipmi_deviceid {
+	uint8_t		id_devid;
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		id_dev_rev:4;
+	uint8_t		__reserved:3;
+	uint8_t		id_dev_sdrs:1;
+#else
+	uint8_t		id_dev_sdrs:1;
+	uint8_t		__reserved:3;
+	uint8_t		id_dev_rev:4;
+#endif
+#if defined(_BIT_FIELD_LTOH)
+	uint8_t		id_firm_major:7;
+	uint8_t		id_dev_available:1;
+#else
+	uint8_t		id_dev_available:1;
+	uint8_t		id_firm_major:7;
+#endif
+	uint8_t		id_firm_minor;
+	uint8_t		id_ipmi_rev;
+	uint8_t		id_dev_support;
+	uint8_t		id_manufacturer[3];
+	uint16_t	id_product;
+} ipmi_deviceid_t;
+
+#define	IPMI_OEM_SUN	0x2a
+
+ipmi_deviceid_t *ipmi_get_deviceid(ipmi_handle_t *);
+
+#define	ipmi_devid_manufacturer(dp)		\
+	((dp)->id_manufacturer[0] |		\
+	((dp)->id_manufacturer[1] << 8) |	\
+	((dp)->id_manufacturer[2] << 16))
+
+/*
+ * SDR (Sensor Device Record) requests.  A cache of the current SDR repository
+ * is kept as part of the IPMI handle and updated when necessary.  Routines to
+ * access the raw SDR repository are also provided.
+ */
+
+/*
+ * Reserve repository command.  See section 33.11.
+ */
+#define	IPMI_CMD_RESERVE_SDR_REPOSITORY	0x22
+
+/*
+ * Get SDR command.  See section 33.12.  This command accesses the raw SDR
+ * repository.  Clients can also use the lookup functions to retrieve a
+ * particular SDR record by name.
+ *
+ * The list of possible types is indicated in the sub-chapters of section 43.
+ */
+typedef struct ipmi_sdr {
+	uint16_t	is_id;
+	uint8_t		is_version;
+	uint8_t		is_type;
+	uint8_t		is_length;
+	uint8_t		is_record[1];
+} ipmi_sdr_t;
+#define	IPMI_CMD_GET_SDR		0x23
+
+#define	IPMI_SDR_FIRST			0x0000
+#define	IPMI_SDR_LAST			0xFFFF
+
+extern ipmi_sdr_t *ipmi_sdr_get(ipmi_handle_t *, uint16_t, uint16_t *);
+
+/*
+ * Generic Device Locator Record.  See section 43.7.
+ */
+
+#define	IPMI_SDR_TYPE_GENERIC_LOCATOR		0x10
+
+typedef struct ipmi_sdr_generic_locator {
+	/* RECORD KEY BYTES */
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		__reserved1:1;
+	uint8_t		is_gl_accessaddr:7;
+	uint8_t		is_gl_channel_msb:1;
+	uint8_t		is_gl_slaveaddr:7;
+	uint8_t		is_gl_bus:3;
+	uint8_t		is_gl_lun:2;
+	uint8_t		is_gl_channel:3;
+#else
+	uint8_t		is_gl_accessaddr:7;
+	uint8_t		__reserved1:1;
+	uint8_t		is_gl_slaveaddr:7;
+	uint8_t		is_gl_channel_msb:1;
+	uint8_t		is_gl_channel:3;
+	uint8_t		is_gl_lun:2;
+	uint8_t		is_gl_bus:3;
+#endif
+	/* RECORD BODY BYTES */
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		is_gl_span:3;
+	uint8_t		__reserved2:5;
+#else
+	uint8_t		__reserved2:5;
+	uint8_t		is_gl_span:3;
+#endif
+	uint8_t		__reserved3;
+	uint8_t		is_gl_type;
+	uint8_t		is_gl_modifier;
+	uint8_t		is_gl_entity;
+	uint8_t		is_gl_instance;
+	uint8_t		is_gl_oem;
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		is_gl_idlen:6;
+	uint8_t		is_gl_idtype:2;
+#else
+	uint8_t		is_gl_idtype:2;
+	uint8_t		is_gl_idlen:6;
+#endif
+	char		is_gl_idstring[1];
+} ipmi_sdr_generic_locator_t;
+
+/*
+ * FRU Device Locator Record.  See section 43.8.
+ */
+
+#define	IPMI_SDR_TYPE_FRU_LOCATOR		0x11
+
+typedef struct ipmi_sdr_fru_locator {
+	/* RECORD KEY BYTES */
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		__reserved1:1;
+	uint8_t		is_fl_accessaddr:7;
+#else
+	uint8_t		is_fl_accessaddr:7;
+	uint8_t		__reserved1:1;
+#endif
+	union {
+		struct {
+			uint8_t	_is_fl_devid;
+		} _logical;
+		struct {
+#if defined(_BIT_FIELDS_LTOH)
+			uint8_t	__reserved:1;
+			uint8_t	_is_fl_slaveaddr:7;
+#else
+			uint8_t	_is_fl_slaveaddr:7;
+			uint8_t	__reserved:1;
+#endif
+		} _nonintelligent;
+	} _devid_or_slaveaddr;
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		is_fl_bus:3;
+	uint8_t		is_fl_lun:2;
+	uint8_t		__reserved2:2;
+	uint8_t		is_fl_logical:1;
+	uint8_t		__reserved3:4;
+	uint8_t		is_fl_channel:4;
+#else
+	uint8_t		is_fl_logical:1;
+	uint8_t		__reserved2:2;
+	uint8_t		is_fl_lun:2;
+	uint8_t		is_fl_bus:3;
+	uint8_t		is_fl_channel:4;
+	uint8_t		__reserved3:4;
+#endif
+	/* RECORD BODY BYTES */
+	uint8_t		__reserved4;
+	uint8_t		is_fl_type;
+	uint8_t		is_fl_modifier;
+	uint8_t		is_fl_entity;
+	uint8_t		is_fl_instance;
+	uint8_t		is_fl_oem;
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		is_fl_idlen:6;
+	uint8_t		is_fl_idtype:2;
+#else
+	uint8_t		is_fl_idtype:2;
+	uint8_t		is_fl_idlen:6;
+#endif
+	char		is_fl_idstring[1];
+} ipmi_sdr_fru_locator_t;
+
+#define	is_fl_devid	_devid_or_slaveaddr._logical._is_fl_devid
+#define	is_fl_slaveaddr	_devid_or_slaveaddr._nonintelligent._is_fl_slaveaddr
+
+/*
+ * The remaining SDR types do not have an associated structure, yet.
+ */
+#define	IPMI_SDR_TYPE_FULL_SENSOR		0x01
+#define	IPMI_SDR_TYPE_COMPACT_SENSOR		0x02
+#define	IPMI_SDR_TYPE_EVENT_ONLY		0x03
+#define	IPMI_SDR_TYPE_ENTITY_ASSOCIATION	0x08
+#define	IPMI_SDR_TYPE_DEVICE_RELATIVE		0x09
+#define	IPMI_SDR_TYPE_MANAGEMENT_DEVICE		0x12
+#define	IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION	0x13
+#define	IPMI_SDR_TYPE_BMC_MESSAGE_CHANNEL	0x14
+#define	IPMI_SDR_TYPE_OEM			0xC0
+
+/*
+ * Lookup the given sensor type by name.  These functions automatically read in
+ * and cache the complete SDR repository.
+ */
+extern ipmi_sdr_fru_locator_t *ipmi_sdr_lookup_fru(ipmi_handle_t *,
+    const char *);
+extern ipmi_sdr_generic_locator_t *ipmi_sdr_lookup_generic(ipmi_handle_t *,
+    const char *);
+
+/*
+ * Get Sensor Reading.  See section 35.14.
+ */
+
+#define	IPMI_CMD_GET_SENSOR_READING	0x2d
+
+typedef struct ipmi_sensor_reading {
+	uint8_t		isr_reading;
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		__reserved1:5;
+	uint8_t		isr_state_unavailable:1;
+	uint8_t		isr_scanning_disabled:1;
+	uint8_t		isr_event_disabled:1;
+#else
+	uint8_t		isr_event_disabled:1;
+	uint8_t		isr_scanning_disabled:1;
+	uint8_t		isr_state_unavailable:1;
+	uint8_t		__reserved1:5;
+#endif
+	uint16_t	isr_state;
+} ipmi_sensor_reading_t;
+
+extern ipmi_sensor_reading_t *ipmi_get_sensor_reading(ipmi_handle_t *, uint8_t);
+
+/*
+ * Set Sensor Reading.  See section 35.14.
+ */
+#define	IPMI_CMD_SET_SENSOR_READING	0x30
+
+#define	IPMI_SENSOR_OP_CLEAR	0x3	/* clear '0' bits */
+#define	IPMI_SENSOR_OP_SET	0x2	/* set '1' bits */
+#define	IPMI_SENSOR_OP_EXACT	0x1	/* set bits exactly */
+
+typedef struct ipmi_set_sensor_reading {
+	uint8_t		iss_id;
+#if defined(_BIT_FIELDS_LTOH)
+	uint8_t		iss_set_reading:1;
+	uint8_t		__reserved:1;
+	uint8_t		iss_deassrt_op:2;
+	uint8_t		iss_assert_op:2;
+	uint8_t		iss_data_bytes:2;
+#else
+	uint8_t		iss_data_bytes:2;
+	uint8_t		iss_assert_op:2;
+	uint8_t		iss_deassrt_op:2;
+	uint8_t		__reserved:1;
+	uint8_t		iss_set_reading:1;
+#endif
+	uint8_t		iss_sensor_reading;
+	uint16_t	iss_assert_state;	/* optional */
+	uint16_t	iss_deassert_state;	/* optional */
+	uint8_t		iss_event_data1;	/* optional */
+	uint8_t		iss_event_data2;	/* optional */
+	uint8_t		iss_event_data3;	/* optional */
+} ipmi_set_sensor_reading_t;
+
+extern int ipmi_set_sensor_reading(ipmi_handle_t *,
+    ipmi_set_sensor_reading_t *);
+
+/*
+ * The remaining functions are private to the implementation of the Sun ILOM
+ * service processor.  These function first check the manufacturer from the IPMI
+ * device ID, and will return EIPMI_NOT_SUPPORTED if attempted for non-Sun
+ * devices.
+ */
+
+/*
+ * Sun OEM LED requests.
+ */
+
+#define	IPMI_CMD_SUNOEM_LED_GET		0x21
+#define	IPMI_CMD_SUNOEM_LED_SET		0x22
+
+typedef struct ipmi_cmd_sunoem_led_set {
+	uint8_t		ic_sls_devaddr;		/* device slave address */
+	uint8_t		ic_sls_type;		/* led type */
+	uint8_t		ic_sls_ctladdr;		/* controller address */
+	uint8_t		ic_sls_hwinfo;		/* OEM hardware info */
+	uint8_t		ic_sls_mode;		/* LED mode */
+	uint8_t		ic_sls_force;		/* force direct access */
+	uint8_t		ic_sls_role;		/* BMC authorization */
+} ipmi_cmd_sunoem_led_set_t;
+
+typedef struct ipmi_cmd_sunoem_led_get {
+	uint8_t		ic_slg_devaddr;		/* device slave address */
+	uint8_t		ic_slg_type;		/* led type */
+	uint8_t		ic_slg_ctladdr;		/* controller address */
+	uint8_t		ic_slg_hwinfo;		/* OEM hardware info */
+	uint8_t		ic_slg_force;		/* force direct access */
+} ipmi_cmd_sunoem_led_get_t;
+
+#define	IPMI_SUNOEM_LED_TYPE_OK2RM	0
+#define	IPMI_SUNOEM_LED_TYPE_SERVICE	1
+#define	IPMI_SUNOEM_LED_TYPE_ACT	2
+#define	IPMI_SUNOEM_LED_TYPE_LOCATE	3
+#define	IPMI_SUNOEM_LED_TYPE_ANY	0xFF
+
+#define	IPMI_SUNOEM_LED_MODE_OFF	0
+#define	IPMI_SUNOEM_LED_MODE_ON		1
+#define	IPMI_SUNOEM_LED_MODE_STANDBY	2
+#define	IPMI_SUNOEM_LED_MODE_SLOW	3
+#define	IPMI_SUNOEM_LED_MODE_FAST	4
+
+/*
+ * These functions take a SDR record and construct the appropriate form of the
+ * above commands.
+ */
+extern int ipmi_sunoem_led_set(ipmi_handle_t *,
+    ipmi_sdr_generic_locator_t *, uint8_t);
+extern int ipmi_sunoem_led_get(ipmi_handle_t *,
+    ipmi_sdr_generic_locator_t *, uint8_t *);
+
+/*
+ * Sun OEM uptime.  Note that the underlying command returns the uptime in big
+ * endian form.  This wrapper automatically converts to the appropriate native
+ * form.
+ */
+
+#define	IPMI_CMD_SUNOEM_UPTIME		0x08
+
+extern int ipmi_sunoem_uptime(ipmi_handle_t *, uint32_t *, uint32_t *);
+
+/*
+ * Sun OEM FRU update.  The FRU information is managed through a generic
+ * identifier, and then a type-specific data portion.  The wrapper function will
+ * automatically fill in the data length field according to which type is
+ * specified.
+ */
+
+#define	IPMI_CMD_SUNOEM_FRU_UPDATE	0x16
+
+#define	IPMI_SUNOEM_FRU_DIMM	0x00
+#define	IPMI_SUNOEM_FRU_CPU	0x01
+#define	IPMI_SUNOEM_FRU_BIOS	0x02
+#define	IPMI_SUNOEM_FRU_DISK	0x03
+
+typedef struct ipmi_sunoem_fru {
+	uint8_t				isf_type;
+	uint8_t				isf_id;
+	uint8_t				isf_datalen;
+	union {
+		struct {
+			uint8_t		isf_data[128];
+		} dimm;
+		struct {
+			uint32_t	isf_thermtrip;
+			uint32_t	isf_eax;
+			char		isf_product[48];
+		} cpu;
+		struct {
+			char		isf_part[16];
+			char		isf_version[16];
+		} bios;
+		struct {
+			char		isf_manufacturer[16];
+			char		isf_model[28];
+			char		isf_serial[20];
+			char		isf_version[8];
+			char		isf_capacity[16];
+		} disk;
+	} isf_data;
+} ipmi_sunoem_fru_t;
+
+int ipmi_sunoem_update_fru(ipmi_handle_t *, ipmi_sunoem_fru_t *);
+
+#pragma pack()
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBIPMI_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/llib-lipmi	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libipmi.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/mapfile-vers	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+SUNWprivate_1.1 {
+    global:
+	ipmi_close;
+	ipmi_errmsg;
+	ipmi_errno;
+	ipmi_get_deviceid;
+	ipmi_get_sensor_reading;
+	ipmi_open;
+	ipmi_sdr_get;
+	ipmi_sdr_lookup_fru;
+	ipmi_sdr_lookup_generic;
+	ipmi_send;
+	ipmi_set_sensor_reading;
+	ipmi_sunoem_led_get;
+	ipmi_sunoem_led_set;
+	ipmi_sunoem_update_fru;
+	ipmi_sunoem_uptime;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/i386/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/sparc/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/sparcv9/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- a/usr/src/pkgdefs/SUNWarc/prototype_com	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_com	Sat Mar 10 17:17:25 2007 -0800
@@ -21,7 +21,7 @@
 
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -118,6 +118,8 @@
 f none usr/lib/llib-lexacct.ln 644 root bin
 s none usr/lib/llib-lintl=../../lib/llib-lintl
 s none usr/lib/llib-lintl.ln=../../lib/llib-lintl.ln
+f none usr/lib/llib-lipmi 644 root bin
+f none usr/lib/llib-lipmi.ln 644 root bin
 f none usr/lib/llib-lipmp 644 root bin
 f none usr/lib/llib-lipmp.ln 644 root bin
 f none usr/lib/llib-lipp 644 root bin
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386	Sat Mar 10 17:17:25 2007 -0800
@@ -21,7 +21,7 @@
 
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -90,6 +90,7 @@
 s none usr/lib/amd64/llib-lgen.ln=../../../lib/amd64/llib-lgen.ln
 f none usr/lib/amd64/llib-lgss.ln 644 root bin
 s none usr/lib/amd64/llib-lintl.ln=../../../lib/amd64/llib-lintl.ln
+f none usr/lib/amd64/llib-lipmi.ln 644 root bin
 f none usr/lib/amd64/llib-lipp.ln 644 root bin
 f none usr/lib/amd64/llib-lkmf.ln 644 root bin
 f none usr/lib/amd64/llib-lkmfberder.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWarc/prototype_sparc	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc	Sat Mar 10 17:17:25 2007 -0800
@@ -21,7 +21,7 @@
 
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -86,6 +86,7 @@
 s none usr/lib/sparcv9/llib-lgen.ln=../../../lib/sparcv9/llib-lgen.ln
 f none usr/lib/sparcv9/llib-lgss.ln 644 root bin
 s none usr/lib/sparcv9/llib-lintl.ln=../../../lib/sparcv9/llib-lintl.ln
+f none usr/lib/sparcv9/llib-lipmi.ln 644 root bin
 f none usr/lib/sparcv9/llib-lipp.ln 644 root bin
 f none usr/lib/sparcv9/llib-lkmf.ln 644 root bin
 f none usr/lib/sparcv9/llib-lkmfberder.ln 644 root bin
--- a/usr/src/pkgdefs/SUNWcsl/prototype_com	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_com	Sat Mar 10 17:17:25 2007 -0800
@@ -139,6 +139,8 @@
 s none usr/lib/libinetcfg.so.1=../../lib/libinetcfg.so.1
 s none usr/lib/libintl.so=../../lib/libintl.so.1
 s none usr/lib/libintl.so.1=../../lib/libintl.so.1
+f none usr/lib/libipmi.so.1 755 root bin
+s none usr/lib/libipmi.so=./libipmi.so.1
 s none usr/lib/libipmp.so=./libipmp.so.1
 f none usr/lib/libipmp.so.1 755 root bin
 s none usr/lib/libipp.so=./libipp.so.1
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386	Sat Mar 10 17:17:25 2007 -0800
@@ -168,6 +168,8 @@
 s none usr/lib/amd64/libgen.so.1=../../../lib/amd64/libgen.so.1
 s none usr/lib/amd64/libgen.so=../../../lib/amd64/libgen.so.1
 s none usr/lib/amd64/libinetutil.so.1=../../../lib/amd64/libinetutil.so.1
+f none usr/lib/amd64/libipmi.so.1 755 root bin
+s none usr/lib/amd64/libipmi.so=./libipmi.so.1
 f none usr/lib/amd64/libipp.so.1 755 root bin
 s none usr/lib/amd64/libipp.so=libipp.so.1
 f none usr/lib/amd64/libkmf.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc	Sat Mar 10 17:17:25 2007 -0800
@@ -161,6 +161,8 @@
 s none usr/lib/sparcv9/libgen.so.1=../../../lib/sparcv9/libgen.so.1
 s none usr/lib/sparcv9/libgen.so=../../../lib/sparcv9/libgen.so.1
 s none usr/lib/sparcv9/libinetutil.so.1=../../../lib/sparcv9/libinetutil.so.1
+f none usr/lib/sparcv9/libipmi.so.1 755 root bin
+s none usr/lib/sparcv9/libipmi.so=libipmi.so.1
 f none usr/lib/sparcv9/libipp.so.1 755 root bin
 s none usr/lib/sparcv9/libipp.so=libipp.so.1
 f none usr/lib/sparcv9/libkmf.so.1 755 root bin
--- a/usr/src/pkgdefs/SUNWfmd/prototype_com	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_com	Sat Mar 10 17:17:25 2007 -0800
@@ -71,6 +71,8 @@
 f none usr/lib/fm/fmd/plugins/ip-transport.conf 644 root bin
 f none usr/lib/fm/fmd/plugins/snmp-trapgen.conf 644 root bin
 f none usr/lib/fm/fmd/plugins/snmp-trapgen.so 555 root bin
+f none usr/lib/fm/fmd/plugins/sp-monitor.conf 644 root bin
+f none usr/lib/fm/fmd/plugins/sp-monitor.so 555 root bin
 f none usr/lib/fm/fmd/plugins/syslog-msgs.conf 644 root bin
 f none usr/lib/fm/fmd/plugins/syslog-msgs.so 555 root bin
 f none usr/lib/fm/fmd/plugins/zfs-diagnosis.conf 644 root bin
--- a/usr/src/pkgdefs/SUNWhea/prototype_com	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com	Sat Mar 10 17:17:25 2007 -0800
@@ -195,6 +195,7 @@
 f none usr/include/libfstyp_module.h 644 root bin
 f none usr/include/libgen.h 644 root bin
 f none usr/include/libintl.h 644 root bin
+f none usr/include/libipmi.h 644 root bin
 f none usr/include/libnvpair.h 644 root bin
 f none usr/include/libipp.h 644 root bin
 d none usr/include/libpolkit 755 root bin
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Sat Mar 10 17:17:25 2007 -0800
@@ -869,6 +869,10 @@
 #
 usr/include/nss.h			sparc
 #
+# bmc (IPMI) interfaces shared within ON.
+#
+usr/include/sys/bmc_intf.h		sparc
+#
 # This file is used in ON to build DSCP clients.  It is not for customers.
 #
 usr/include/libdscp.h			sparc
--- a/usr/src/uts/common/sys/Makefile	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/uts/common/sys/Makefile	Sat Mar 10 17:17:25 2007 -0800
@@ -48,7 +48,6 @@
 	audio/audio810.h	\
 	audio/audiohd.h	\
 	audio/audioixp.h	\
-	bmc_intf.h		\
 	fd_debug.h		\
 	fdc.h			\
 	fdmedia.h		\
@@ -99,6 +98,7 @@
 	bitmap.h		\
 	bitset.h		\
 	bl.h			\
+	bmc_intf.h		\
 	bofi.h			\
 	bofi_impl.h		\
 	bpp_io.h		\
--- a/usr/src/uts/common/sys/bmc_intf.h	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/uts/common/sys/bmc_intf.h	Sat Mar 10 17:17:25 2007 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,6 +29,8 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
+#include <sys/types.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
--- a/usr/src/uts/common/sys/sysevent/eventdefs.h	Sat Mar 10 06:42:50 2007 -0800
+++ b/usr/src/uts/common/sys/sysevent/eventdefs.h	Sat Mar 10 17:17:25 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -148,7 +148,7 @@
 #define	ESC_DOMAIN_LOGHOST_CHANGE	"ESC_domain_loghost_change"
 
 /*
- * EC_AP_DRIVER subclass defintions - supporting attributes (name/value pairs)
+ * EC_AP_DRIVER subclass definitions - supporting attributes (name/value pairs)
  * are found in sys/sysevent/ap_driver.h
  */
 
@@ -161,7 +161,7 @@
 	"ESC_ap_driver_phys_path_status_change"
 
 /*
- * EC_IPMP subclass defintions - supporting attributes (name/value pairs)
+ * EC_IPMP subclass definitions - supporting attributes (name/value pairs)
  * are found in sys/sysevent/ipmp.h
  */
 
@@ -179,7 +179,7 @@
 
 
 /*
- * EC_DEV_ADD and EC_DEV_REMOVE subclass defintions - supporting attributes
+ * EC_DEV_ADD and EC_DEV_REMOVE subclass definitions - supporting attributes
  * (name/value pairs) are found in sys/sysevent/dev.h
  */
 #define	ESC_DISK	"disk"		/* disk device */
@@ -187,7 +187,7 @@
 #define	ESC_PRINTER	"printer"	/* printer device */
 
 /*
- * EC_DEV_BRANCH subclass defintions - supporting attributes (name/value pairs)
+ * EC_DEV_BRANCH subclass definitions - supporting attributes (name/value pairs)
  * are found in sys/sysevent/dev.h
  */
 
@@ -200,6 +200,10 @@
 /* FMA Fault and Error event protocol subclass */
 #define	ESC_FM_ERROR		"ESC_FM_error"
 #define	ESC_FM_ERROR_REPLAY	"ESC_FM_error_replay"
+
+/* Service processor subclass definitions */
+#define	ESC_PLATFORM_SP_RESET	"ESC_platform_sp_reset"
+
 #ifdef	__cplusplus
 }
 #endif