19113a79cSeschrock /*
29113a79cSeschrock  * CDDL HEADER START
39113a79cSeschrock  *
49113a79cSeschrock  * The contents of this file are subject to the terms of the
59113a79cSeschrock  * Common Development and Distribution License (the "License").
69113a79cSeschrock  * You may not use this file except in compliance with the License.
79113a79cSeschrock  *
89113a79cSeschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99113a79cSeschrock  * or http://www.opensolaris.org/os/licensing.
109113a79cSeschrock  * See the License for the specific language governing permissions
119113a79cSeschrock  * and limitations under the License.
129113a79cSeschrock  *
139113a79cSeschrock  * When distributing Covered Code, include this CDDL HEADER in each
149113a79cSeschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159113a79cSeschrock  * If applicable, add the following below this CDDL HEADER, with the
169113a79cSeschrock  * fields enclosed by brackets "[]" replaced with your own identifying
179113a79cSeschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
189113a79cSeschrock  *
199113a79cSeschrock  * CDDL HEADER END
209113a79cSeschrock  */
219113a79cSeschrock /*
22*81d9f076SRobert Johnston  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
239113a79cSeschrock  * Use is subject to license terms.
249113a79cSeschrock  */
259113a79cSeschrock 
269113a79cSeschrock #include <ctype.h>
279113a79cSeschrock #include <libipmi.h>
289113a79cSeschrock #include <libnvpair.h>
299113a79cSeschrock #include <libuutil.h>
309113a79cSeschrock #include <limits.h>
319113a79cSeschrock #include <stddef.h>
329113a79cSeschrock #include <string.h>
339113a79cSeschrock 
349113a79cSeschrock #include "diskmon_conf.h"
359113a79cSeschrock #include "dm_platform.h"
369113a79cSeschrock #include "util.h"
379113a79cSeschrock 
389113a79cSeschrock /* For the purposes of disk capacity, a <X>B is 1000x, not 1024x */
399113a79cSeschrock #define	ONE_KILOBYTE 1000.0
409113a79cSeschrock #define	ONE_MEGABYTE (ONE_KILOBYTE * 1000)
419113a79cSeschrock #define	ONE_GIGABYTE (ONE_MEGABYTE * 1000)
429113a79cSeschrock #define	ONE_TERABYTE (ONE_GIGABYTE * 1000)
439113a79cSeschrock #define	ONE_PETABYTE (ONE_TERABYTE * 1000)
449113a79cSeschrock 
459113a79cSeschrock static ipmi_handle_t *g_ipmi_hdl;
469113a79cSeschrock 
479113a79cSeschrock typedef enum {
489113a79cSeschrock 	IPMI_CACHE_SENSOR,
499113a79cSeschrock 	IPMI_CACHE_FRU
509113a79cSeschrock } ipmi_cache_type_t;
519113a79cSeschrock 
529113a79cSeschrock typedef struct ipmi_cache_entry {
539113a79cSeschrock 	ipmi_cache_type_t			ic_type;
549113a79cSeschrock 	uu_list_node_t				ic_node;
559113a79cSeschrock 	union {
569113a79cSeschrock 		ipmi_set_sensor_reading_t	ic_sensor;
579113a79cSeschrock 		ipmi_sunoem_fru_t		ic_fru;
589113a79cSeschrock 	} ic_data;
599113a79cSeschrock } ipmi_cache_entry_t;
609113a79cSeschrock 
619113a79cSeschrock static pthread_mutex_t g_ipmi_mtx = PTHREAD_MUTEX_INITIALIZER;
629113a79cSeschrock static uu_list_pool_t *g_ipmi_cache_pool;
639113a79cSeschrock static uu_list_t *g_ipmi_cache;
649113a79cSeschrock 
659113a79cSeschrock /*
669113a79cSeschrock  * The textual strings that are used in the actions may be one of the
679113a79cSeschrock  * following forms:
689113a79cSeschrock  *
699113a79cSeschrock  * [1] `fru gid=<n> hdd=<m>'
709113a79cSeschrock  * [2] `sensor id=<x> assert=<y> deassert=<z>'
719113a79cSeschrock  *
729113a79cSeschrock  * The generic parser will take a string and spit out the first token
739113a79cSeschrock  * (e.g. `fru' or `sensor') and an nvlist that contains the key-value
749113a79cSeschrock  * pairs in the rest of the string.  The assumption is that there are
759113a79cSeschrock  * no embedded spaces or tabs in the keys or values.
769113a79cSeschrock  */
779113a79cSeschrock 
789113a79cSeschrock static boolean_t
isnumber(const char * str)799113a79cSeschrock isnumber(const char *str)
809113a79cSeschrock {
819113a79cSeschrock 	boolean_t hex = B_FALSE;
829113a79cSeschrock 	int digits = 0;
839113a79cSeschrock 
849113a79cSeschrock 	if (strncasecmp(str, "0x", 2) == 0) {
859113a79cSeschrock 		hex = B_TRUE;
869113a79cSeschrock 		str += 2;
879113a79cSeschrock 	} else if (*str == '-' || *str == '+') {
889113a79cSeschrock 		str++;
899113a79cSeschrock 	}
909113a79cSeschrock 
919113a79cSeschrock 	while (*str != 0) {
929113a79cSeschrock 		if ((hex && !isxdigit(*str)) ||
939113a79cSeschrock 		    (!hex && !isdigit(*str))) {
949113a79cSeschrock 			return (B_FALSE);
959113a79cSeschrock 		}
969113a79cSeschrock 
979113a79cSeschrock 		str++;
989113a79cSeschrock 		digits++;
999113a79cSeschrock 	}
1009113a79cSeschrock 
1019113a79cSeschrock 	return ((digits == 0) ? B_FALSE : B_TRUE);
1029113a79cSeschrock }
1039113a79cSeschrock 
1049113a79cSeschrock static void
tolowerString(char * str)1059113a79cSeschrock tolowerString(char *str)
1069113a79cSeschrock {
1079113a79cSeschrock 	while (*str != 0) {
1089113a79cSeschrock 		*str = tolower(*str);
1099113a79cSeschrock 		str++;
1109113a79cSeschrock 	}
1119113a79cSeschrock }
1129113a79cSeschrock 
1139113a79cSeschrock static boolean_t
parse_action_string(const char * actionString,char ** cmdp,nvlist_t ** propsp)1149113a79cSeschrock parse_action_string(const char *actionString, char **cmdp, nvlist_t **propsp)
1159113a79cSeschrock {
1169113a79cSeschrock 	char *action;
1179113a79cSeschrock 	char *tok, *lasts, *eq;
1189113a79cSeschrock 	int actionlen;
1199113a79cSeschrock 	boolean_t rv = B_TRUE;
1209113a79cSeschrock 
1219113a79cSeschrock 	if (nvlist_alloc(propsp, NV_UNIQUE_NAME, 0) != 0)
1229113a79cSeschrock 		return (B_FALSE);
1239113a79cSeschrock 
1249113a79cSeschrock 	actionlen = strlen(actionString) + 1;
1259113a79cSeschrock 	action = dstrdup(actionString);
1269113a79cSeschrock 
1279113a79cSeschrock 	*cmdp = NULL;
1289113a79cSeschrock 
1299113a79cSeschrock 	if ((tok = strtok_r(action, " \t", &lasts)) != NULL) {
1309113a79cSeschrock 
1319113a79cSeschrock 		*cmdp = dstrdup(tok);
1329113a79cSeschrock 
1339113a79cSeschrock 		while (rv && (tok = strtok_r(NULL, " \t", &lasts)) != NULL) {
1349113a79cSeschrock 
1359113a79cSeschrock 			/* Look for a name=val construct */
1369113a79cSeschrock 			if ((eq = strchr(tok, '=')) != NULL && eq[1] != 0) {
1379113a79cSeschrock 
1389113a79cSeschrock 				*eq = 0;
1399113a79cSeschrock 				eq++;
1409113a79cSeschrock 
1419113a79cSeschrock 				/*
1429113a79cSeschrock 				 * Convert token to lowercase to preserve
1439113a79cSeschrock 				 * case-insensitivity, because nvlist doesn't
1449113a79cSeschrock 				 * do case-insensitive lookups
1459113a79cSeschrock 				 */
1469113a79cSeschrock 				tolowerString(tok);
1479113a79cSeschrock 
1489113a79cSeschrock 				if (isnumber(eq)) {
1499113a79cSeschrock 					/* Integer property */
1509113a79cSeschrock 
1519113a79cSeschrock 					if (nvlist_add_uint64(*propsp, tok,
1529113a79cSeschrock 					    strtoull(eq, NULL, 0)) != 0)
1539113a79cSeschrock 						rv = B_FALSE;
1549113a79cSeschrock 				} else {
1559113a79cSeschrock 					/* String property */
1569113a79cSeschrock 
1579113a79cSeschrock 					if (nvlist_add_string(*propsp, tok,
1589113a79cSeschrock 					    eq) != 0)
1599113a79cSeschrock 						rv = B_FALSE;
1609113a79cSeschrock 				}
1619113a79cSeschrock 			} else if (eq == NULL) {
1629113a79cSeschrock 				/* Boolean property */
1639113a79cSeschrock 				if (nvlist_add_boolean(*propsp, tok) != 0)
1649113a79cSeschrock 					rv = B_FALSE;
1659113a79cSeschrock 			} else /* Parse error (`X=' is invalid) */
1669113a79cSeschrock 				rv = B_FALSE;
1679113a79cSeschrock 		}
1689113a79cSeschrock 	} else
1699113a79cSeschrock 		rv = B_FALSE;
1709113a79cSeschrock 
1719113a79cSeschrock 	dfree(action, actionlen);
1729113a79cSeschrock 	if (!rv) {
1739113a79cSeschrock 		if (*cmdp) {
1749113a79cSeschrock 			dstrfree(*cmdp);
1759113a79cSeschrock 			*cmdp = NULL;
1769113a79cSeschrock 		}
1779113a79cSeschrock 		nvlist_free(*propsp);
1789113a79cSeschrock 		*propsp = NULL;
1799113a79cSeschrock 	}
1809113a79cSeschrock 	return (rv);
1819113a79cSeschrock }
1829113a79cSeschrock 
1839113a79cSeschrock static int
platform_update_fru(nvlist_t * props,dm_fru_t * frup)1849113a79cSeschrock platform_update_fru(nvlist_t *props, dm_fru_t *frup)
1859113a79cSeschrock {
1869113a79cSeschrock 	uint64_t gid, hdd;
1879113a79cSeschrock 	ipmi_sunoem_fru_t fru;
1889113a79cSeschrock 	char *buf;
1899113a79cSeschrock 	ipmi_cache_entry_t *entry;
1909113a79cSeschrock 
1919113a79cSeschrock 	if (nvlist_lookup_uint64(props, "gid", &gid) != 0 ||
1929113a79cSeschrock 	    nvlist_lookup_uint64(props, "hdd", &hdd) != 0) {
1939113a79cSeschrock 		return (-1);
1949113a79cSeschrock 	}
1959113a79cSeschrock 
1969113a79cSeschrock 	fru.isf_type = (uint8_t)gid;
1979113a79cSeschrock 	fru.isf_id = (uint8_t)hdd;
1989113a79cSeschrock 
1999113a79cSeschrock 	buf = (char *)dzmalloc(sizeof (fru.isf_data.disk.isf_capacity) + 1);
2009113a79cSeschrock 
2019113a79cSeschrock 	(void) memcpy(fru.isf_data.disk.isf_manufacturer, frup->manuf,
2029113a79cSeschrock 	    MIN(sizeof (fru.isf_data.disk.isf_manufacturer),
2039113a79cSeschrock 	    sizeof (frup->manuf)));
2049113a79cSeschrock 	(void) memcpy(fru.isf_data.disk.isf_model, frup->model,
2059113a79cSeschrock 	    MIN(sizeof (fru.isf_data.disk.isf_model), sizeof (frup->model)));
2069113a79cSeschrock 	(void) memcpy(fru.isf_data.disk.isf_serial, frup->serial,
2079113a79cSeschrock 	    MIN(sizeof (fru.isf_data.disk.isf_serial), sizeof (frup->serial)));
2089113a79cSeschrock 	(void) memcpy(fru.isf_data.disk.isf_version, frup->rev,
2099113a79cSeschrock 	    MIN(sizeof (fru.isf_data.disk.isf_version), sizeof (frup->rev)));
2109113a79cSeschrock 	/*
2119113a79cSeschrock 	 * Print the size of the disk to a temporary buffer whose size is
2129113a79cSeschrock 	 * 1 more than the size of the buffer in the ipmi request data
2139113a79cSeschrock 	 * structure, so we can get the full 8 characters (instead of 7 + NUL)
2149113a79cSeschrock 	 */
2159113a79cSeschrock 	(void) snprintf(buf, sizeof (fru.isf_data.disk.isf_capacity) + 1,
2169113a79cSeschrock 	    "%.1f%s",
2179113a79cSeschrock 	    frup->size_in_bytes >= ONE_PETABYTE ?
2189113a79cSeschrock 	    (frup->size_in_bytes / ONE_PETABYTE) :
2199113a79cSeschrock 	    (frup->size_in_bytes >= ONE_TERABYTE ?
2209113a79cSeschrock 	    (frup->size_in_bytes / ONE_TERABYTE) :
2219113a79cSeschrock 	    (frup->size_in_bytes >= ONE_GIGABYTE ?
2229113a79cSeschrock 	    (frup->size_in_bytes / ONE_GIGABYTE) :
2239113a79cSeschrock 	    (frup->size_in_bytes >= ONE_MEGABYTE ?
2249113a79cSeschrock 	    (frup->size_in_bytes / ONE_MEGABYTE) :
2259113a79cSeschrock 	    (frup->size_in_bytes / ONE_KILOBYTE)))),
2269113a79cSeschrock 
2279113a79cSeschrock 	    frup->size_in_bytes >= ONE_PETABYTE ? "PB" :
2289113a79cSeschrock 	    (frup->size_in_bytes >= ONE_TERABYTE ? "TB" :
2299113a79cSeschrock 	    (frup->size_in_bytes >= ONE_GIGABYTE ? "GB" :
2309113a79cSeschrock 	    (frup->size_in_bytes >= ONE_MEGABYTE ? "MB" :
2319113a79cSeschrock 	    "KB"))));
2329113a79cSeschrock 	(void) memcpy(fru.isf_data.disk.isf_capacity, buf,
2339113a79cSeschrock 	    sizeof (fru.isf_data.disk.isf_capacity));
2349113a79cSeschrock 
2359113a79cSeschrock 	dfree(buf, sizeof (fru.isf_data.disk.isf_capacity) + 1);
2369113a79cSeschrock 
2379113a79cSeschrock 	if (ipmi_sunoem_update_fru(g_ipmi_hdl, &fru) != 0)
2389113a79cSeschrock 		return (-1);
2399113a79cSeschrock 
2409113a79cSeschrock 	/* find a cache entry or create one if necessary */
2419113a79cSeschrock 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
2429113a79cSeschrock 	    entry = uu_list_next(g_ipmi_cache, entry)) {
2439113a79cSeschrock 		if (entry->ic_type == IPMI_CACHE_FRU &&
2449113a79cSeschrock 		    entry->ic_data.ic_fru.isf_type == gid &&
2459113a79cSeschrock 		    entry->ic_data.ic_fru.isf_id == hdd)
2469113a79cSeschrock 			break;
2479113a79cSeschrock 	}
2489113a79cSeschrock 
2499113a79cSeschrock 	if (entry == NULL) {
2509113a79cSeschrock 		entry = dzmalloc(sizeof (ipmi_cache_entry_t));
2519113a79cSeschrock 		entry->ic_type = IPMI_CACHE_FRU;
2529113a79cSeschrock 		(void) uu_list_insert_before(g_ipmi_cache, NULL, entry);
2539113a79cSeschrock 	}
2549113a79cSeschrock 
2559113a79cSeschrock 	(void) memcpy(&entry->ic_data.ic_fru, &fru, sizeof (fru));
2569113a79cSeschrock 
2579113a79cSeschrock 	return (0);
2589113a79cSeschrock }
2599113a79cSeschrock 
2609113a79cSeschrock static int
platform_set_sensor(nvlist_t * props)2619113a79cSeschrock platform_set_sensor(nvlist_t *props)
2629113a79cSeschrock {
2639113a79cSeschrock 	uint64_t assertmask = 0, deassertmask = 0, sid;
2649113a79cSeschrock 	boolean_t am_present, dam_present;
2659113a79cSeschrock 	ipmi_set_sensor_reading_t sr, *sp;
2669113a79cSeschrock 	ipmi_cache_entry_t *entry;
2679113a79cSeschrock 	int ret;
2689113a79cSeschrock 
2699113a79cSeschrock 	/* We need at least 2 properties: `sid' and (`amask' || `dmask'): */
2709113a79cSeschrock 	am_present = nvlist_lookup_uint64(props, "amask", &assertmask) == 0;
2719113a79cSeschrock 	dam_present = nvlist_lookup_uint64(props, "dmask", &deassertmask) == 0;
2729113a79cSeschrock 
2739113a79cSeschrock 	if (nvlist_lookup_uint64(props, "sid", &sid) != 0 ||
2749113a79cSeschrock 	    (!am_present && !dam_present)) {
2759113a79cSeschrock 		return (-1);
2769113a79cSeschrock 	}
2779113a79cSeschrock 
2789113a79cSeschrock 	if (sid > UINT8_MAX) {
2799113a79cSeschrock 		log_warn("IPMI Plugin: Invalid sensor id `0x%llx'.\n",
2809113a79cSeschrock 		    (longlong_t)sid);
2819113a79cSeschrock 		return (-1);
2829113a79cSeschrock 	} else if (assertmask > UINT16_MAX) {
2839113a79cSeschrock 		log_warn("IPMI Plugin: Invalid assertion mask `0x%llx'.\n",
2849113a79cSeschrock 		    (longlong_t)assertmask);
2859113a79cSeschrock 		return (-1);
2869113a79cSeschrock 	} else if (assertmask > UINT16_MAX) {
2879113a79cSeschrock 		log_warn("IPMI Plugin: Invalid deassertion mask `0x%llx'.\n",
2889113a79cSeschrock 		    (longlong_t)deassertmask);
2899113a79cSeschrock 		return (-1);
2909113a79cSeschrock 	}
2919113a79cSeschrock 
2929113a79cSeschrock 	(void) memset(&sr, '\0', sizeof (sr));
2939113a79cSeschrock 	sr.iss_id = (uint8_t)sid;
2949113a79cSeschrock 	if (am_present) {
2959113a79cSeschrock 		sr.iss_assert_op = IPMI_SENSOR_OP_SET;
2969113a79cSeschrock 		sr.iss_assert_state = (uint16_t)assertmask;
2979113a79cSeschrock 	}
2989113a79cSeschrock 	if (dam_present) {
2999113a79cSeschrock 		sr.iss_deassrt_op = IPMI_SENSOR_OP_SET;
3009113a79cSeschrock 		sr.iss_deassert_state = (uint16_t)deassertmask;
3019113a79cSeschrock 	}
3029113a79cSeschrock 
3039113a79cSeschrock 	ret = ipmi_set_sensor_reading(g_ipmi_hdl, &sr);
3049113a79cSeschrock 
3059113a79cSeschrock 	/* find a cache entry or create one if necessary */
3069113a79cSeschrock 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
3079113a79cSeschrock 	    entry = uu_list_next(g_ipmi_cache, entry)) {
3089113a79cSeschrock 		if (entry->ic_type == IPMI_CACHE_SENSOR &&
3099113a79cSeschrock 		    entry->ic_data.ic_sensor.iss_id == (uint8_t)sid)
3109113a79cSeschrock 			break;
3119113a79cSeschrock 	}
3129113a79cSeschrock 
3139113a79cSeschrock 	if (entry == NULL) {
3149113a79cSeschrock 		entry = dzmalloc(sizeof (ipmi_cache_entry_t));
3159113a79cSeschrock 		entry->ic_type = IPMI_CACHE_SENSOR;
3169113a79cSeschrock 		(void) uu_list_insert_before(g_ipmi_cache, NULL, entry);
3179113a79cSeschrock 		entry->ic_data.ic_sensor.iss_id = (uint8_t)sid;
3189113a79cSeschrock 		entry->ic_data.ic_sensor.iss_assert_op = IPMI_SENSOR_OP_SET;
3199113a79cSeschrock 		entry->ic_data.ic_sensor.iss_deassrt_op = IPMI_SENSOR_OP_SET;
3209113a79cSeschrock 	}
3219113a79cSeschrock 	sp = &entry->ic_data.ic_sensor;
3229113a79cSeschrock 
3239113a79cSeschrock 	if (am_present) {
3249113a79cSeschrock 		sp->iss_assert_state |= assertmask;
3259113a79cSeschrock 		sp->iss_deassert_state &= ~assertmask;
3269113a79cSeschrock 	}
3279113a79cSeschrock 	if (dam_present) {
3289113a79cSeschrock 		sp->iss_deassert_state |= deassertmask;
3299113a79cSeschrock 		sp->iss_assert_state &= ~deassertmask;
3309113a79cSeschrock 	}
3319113a79cSeschrock 
3329113a79cSeschrock 	return (ret);
3339113a79cSeschrock }
3349113a79cSeschrock 
3359113a79cSeschrock #define	PROTOCOL_SEPARATOR ':'
3369113a79cSeschrock 
3379113a79cSeschrock static char *
extract_protocol(const char * action)3389113a79cSeschrock extract_protocol(const char *action)
3399113a79cSeschrock {
3409113a79cSeschrock 	char *s = strchr(action, PROTOCOL_SEPARATOR);
3419113a79cSeschrock 	char *proto = NULL;
3429113a79cSeschrock 	int len;
3439113a79cSeschrock 	int i = 0;
3449113a79cSeschrock 
3459113a79cSeschrock 	/* The protocol is the string before the separator, but in lower-case */
3469113a79cSeschrock 	if (s) {
3479113a79cSeschrock 		len = (uintptr_t)s - (uintptr_t)action;
3489113a79cSeschrock 		proto = (char *)dmalloc(len + 1);
3499113a79cSeschrock 		while (i < len) {
3509113a79cSeschrock 			proto[i] = tolower(action[i]);
3519113a79cSeschrock 			i++;
3529113a79cSeschrock 		}
3539113a79cSeschrock 		proto[len] = 0;
3549113a79cSeschrock 	}
3559113a79cSeschrock 
3569113a79cSeschrock 	return (proto);
3579113a79cSeschrock }
3589113a79cSeschrock 
3599113a79cSeschrock static char *
extract_action(const char * action)3609113a79cSeschrock extract_action(const char *action)
3619113a79cSeschrock {
3629113a79cSeschrock 	/* The action is the string after the separator */
3639113a79cSeschrock 	char *s = strchr(action, PROTOCOL_SEPARATOR);
3649113a79cSeschrock 
3659113a79cSeschrock 	return (s ? (s + 1) : NULL);
3669113a79cSeschrock }
3679113a79cSeschrock 
3689113a79cSeschrock static int
do_action(const char * action,dm_fru_t * fru)3699113a79cSeschrock do_action(const char *action, dm_fru_t *fru)
3709113a79cSeschrock {
3719113a79cSeschrock 	nvlist_t	*props;
3729113a79cSeschrock 	char		*cmd;
3739113a79cSeschrock 	int rv = -1;
3749113a79cSeschrock 	char		*protocol = extract_protocol(action);
3759113a79cSeschrock 	char		*actionp = extract_action(action);
3769113a79cSeschrock 
3779113a79cSeschrock 	if (strcmp(protocol, "ipmi") != 0) {
3789113a79cSeschrock 		log_err("unknown protocol '%s'\n", protocol);
3799113a79cSeschrock 		dstrfree(protocol);
3809113a79cSeschrock 		return (-1);
3819113a79cSeschrock 	}
3829113a79cSeschrock 
3839113a79cSeschrock 	dstrfree(protocol);
3849113a79cSeschrock 
3859113a79cSeschrock 	(void) pthread_mutex_lock(&g_ipmi_mtx);
3869113a79cSeschrock 	if (parse_action_string(actionp, &cmd, &props)) {
3879113a79cSeschrock 		if (strcmp(cmd, "fru") == 0) {
3889113a79cSeschrock 			rv = platform_update_fru(props, fru);
3899113a79cSeschrock 		} else if (strcmp(cmd, "state") == 0) {
3909113a79cSeschrock 			rv = platform_set_sensor(props);
3919113a79cSeschrock 		} else {
3929113a79cSeschrock 			log_err("unknown platform action '%s'\n", cmd);
3939113a79cSeschrock 		}
3949113a79cSeschrock 		dstrfree(cmd);
3959113a79cSeschrock 		nvlist_free(props);
3969113a79cSeschrock 	}
3979113a79cSeschrock 	(void) pthread_mutex_unlock(&g_ipmi_mtx);
3989113a79cSeschrock 
3999113a79cSeschrock 	return (rv);
4009113a79cSeschrock }
4019113a79cSeschrock 
4029113a79cSeschrock int
dm_platform_update_fru(const char * action,dm_fru_t * fru)4039113a79cSeschrock dm_platform_update_fru(const char *action, dm_fru_t *fru)
4049113a79cSeschrock {
4059113a79cSeschrock 	return (do_action(action, fru));
4069113a79cSeschrock }
4079113a79cSeschrock 
4089113a79cSeschrock int
dm_platform_indicator_execute(const char * action)4099113a79cSeschrock dm_platform_indicator_execute(const char *action)
4109113a79cSeschrock {
4119113a79cSeschrock 	return (do_action(action, NULL));
4129113a79cSeschrock }
4139113a79cSeschrock 
4149113a79cSeschrock int
dm_platform_resync(void)4159113a79cSeschrock dm_platform_resync(void)
4169113a79cSeschrock {
4179113a79cSeschrock 	ipmi_cache_entry_t *entry;
4189113a79cSeschrock 	int rv = 0;
4199113a79cSeschrock 
4209113a79cSeschrock 	(void) pthread_mutex_lock(&g_ipmi_mtx);
4219113a79cSeschrock 
4229113a79cSeschrock 	/*
4239113a79cSeschrock 	 * Called when the SP is reset, as the sensor/FRU state is not
4249113a79cSeschrock 	 * maintained across reboots.  Note that we must update the FRU
4259113a79cSeschrock 	 * information first, as certain sensor states prevent this from
4269113a79cSeschrock 	 * working.
4279113a79cSeschrock 	 */
4289113a79cSeschrock 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
4299113a79cSeschrock 	    entry = uu_list_next(g_ipmi_cache, entry)) {
4309113a79cSeschrock 		if (entry->ic_type == IPMI_CACHE_FRU)
4319113a79cSeschrock 			rv |= ipmi_sunoem_update_fru(g_ipmi_hdl,
4329113a79cSeschrock 			    &entry->ic_data.ic_fru);
4339113a79cSeschrock 	}
4349113a79cSeschrock 
4359113a79cSeschrock 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
4369113a79cSeschrock 	    entry = uu_list_next(g_ipmi_cache, entry)) {
4379113a79cSeschrock 		if (entry->ic_type == IPMI_CACHE_SENSOR)
4389113a79cSeschrock 			rv |= ipmi_set_sensor_reading(g_ipmi_hdl,
4399113a79cSeschrock 			    &entry->ic_data.ic_sensor);
4409113a79cSeschrock 	}
4419113a79cSeschrock 
4429113a79cSeschrock 	(void) pthread_mutex_unlock(&g_ipmi_mtx);
4439113a79cSeschrock 	return (rv);
4449113a79cSeschrock }
4459113a79cSeschrock 
4469113a79cSeschrock int
dm_platform_init(void)4479113a79cSeschrock dm_platform_init(void)
4489113a79cSeschrock {
4499113a79cSeschrock 	int err;
4509113a79cSeschrock 	char *msg;
4519113a79cSeschrock 
452*81d9f076SRobert Johnston 	if ((g_ipmi_hdl = ipmi_open(&err, &msg, IPMI_TRANSPORT_BMC, NULL))
453*81d9f076SRobert Johnston 	    == NULL) {
4549113a79cSeschrock 		log_warn("Failed to load libipmi: %s\n", msg);
4559113a79cSeschrock 		return (-1);
4569113a79cSeschrock 	}
4579113a79cSeschrock 
4589113a79cSeschrock 	if ((g_ipmi_cache_pool = uu_list_pool_create(
4599113a79cSeschrock 	    "ipmi_cache", sizeof (ipmi_cache_entry_t),
4609113a79cSeschrock 	    offsetof(ipmi_cache_entry_t, ic_node), NULL, 0)) == NULL)
4619113a79cSeschrock 		return (-1);
4629113a79cSeschrock 
4639113a79cSeschrock 	if ((g_ipmi_cache = uu_list_create(g_ipmi_cache_pool, NULL, 0))
4649113a79cSeschrock 	    == NULL)
4659113a79cSeschrock 		return (-1);
4669113a79cSeschrock 
4679113a79cSeschrock 	return (0);
4689113a79cSeschrock }
4699113a79cSeschrock 
4709113a79cSeschrock void
dm_platform_fini(void)4719113a79cSeschrock dm_platform_fini(void)
4729113a79cSeschrock {
4739113a79cSeschrock 	if (g_ipmi_hdl)
4749113a79cSeschrock 		ipmi_close(g_ipmi_hdl);
4759113a79cSeschrock 	if (g_ipmi_cache) {
4769113a79cSeschrock 		ipmi_cache_entry_t *entry;
4779113a79cSeschrock 
4789113a79cSeschrock 		while ((entry = uu_list_first(g_ipmi_cache)) != NULL) {
4799113a79cSeschrock 			uu_list_remove(g_ipmi_cache, entry);
4809113a79cSeschrock 			dfree(entry, sizeof (*entry));
4819113a79cSeschrock 		}
4829113a79cSeschrock 		uu_list_destroy(g_ipmi_cache);
4839113a79cSeschrock 	}
4849113a79cSeschrock 	if (g_ipmi_cache_pool)
4859113a79cSeschrock 		uu_list_pool_destroy(g_ipmi_cache_pool);
4869113a79cSeschrock }
487