Mercurial > illumos > illumos-gate
changeset 3798:36499f71540b
6518277 need a common IPMI library
6518283 generic mechanism for detecting SP resets
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