xref: /illumos-gate/usr/src/cmd/fm/modules/common/disk-monitor/dm_platform.c (revision 81d9f076db88c1f40c85831ce1ebb444a209c5a8)
1184cd04cScth /*
2184cd04cScth  * CDDL HEADER START
3184cd04cScth  *
4184cd04cScth  * The contents of this file are subject to the terms of the
5184cd04cScth  * Common Development and Distribution License (the "License").
6184cd04cScth  * You may not use this file except in compliance with the License.
7184cd04cScth  *
8184cd04cScth  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9184cd04cScth  * or http://www.opensolaris.org/os/licensing.
10184cd04cScth  * See the License for the specific language governing permissions
11184cd04cScth  * and limitations under the License.
12184cd04cScth  *
13184cd04cScth  * When distributing Covered Code, include this CDDL HEADER in each
14184cd04cScth  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15184cd04cScth  * If applicable, add the following below this CDDL HEADER, with the
16184cd04cScth  * fields enclosed by brackets "[]" replaced with your own identifying
17184cd04cScth  * information: Portions Copyright [yyyy] [name of copyright owner]
18184cd04cScth  *
19184cd04cScth  * CDDL HEADER END
20184cd04cScth  */
21184cd04cScth /*
22*81d9f076SRobert Johnston  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23184cd04cScth  * Use is subject to license terms.
24184cd04cScth  */
25184cd04cScth 
26184cd04cScth #include <ctype.h>
27184cd04cScth #include <libipmi.h>
28184cd04cScth #include <libnvpair.h>
29184cd04cScth #include <libuutil.h>
30184cd04cScth #include <limits.h>
31184cd04cScth #include <stddef.h>
32184cd04cScth #include <string.h>
33184cd04cScth 
34184cd04cScth #include "diskmon_conf.h"
35184cd04cScth #include "dm_platform.h"
36184cd04cScth #include "util.h"
37184cd04cScth 
38184cd04cScth /* For the purposes of disk capacity, a <X>B is 1000x, not 1024x */
39184cd04cScth #define	ONE_KILOBYTE 1000.0
40184cd04cScth #define	ONE_MEGABYTE (ONE_KILOBYTE * 1000)
41184cd04cScth #define	ONE_GIGABYTE (ONE_MEGABYTE * 1000)
42184cd04cScth #define	ONE_TERABYTE (ONE_GIGABYTE * 1000)
43184cd04cScth #define	ONE_PETABYTE (ONE_TERABYTE * 1000)
44184cd04cScth 
45184cd04cScth static ipmi_handle_t *g_ipmi_hdl;
46184cd04cScth 
47184cd04cScth typedef enum {
48184cd04cScth 	IPMI_CACHE_SENSOR,
49184cd04cScth 	IPMI_CACHE_FRU
50184cd04cScth } ipmi_cache_type_t;
51184cd04cScth 
52184cd04cScth typedef struct ipmi_cache_entry {
53184cd04cScth 	ipmi_cache_type_t			ic_type;
54184cd04cScth 	uu_list_node_t				ic_node;
55184cd04cScth 	union {
56184cd04cScth 		ipmi_set_sensor_reading_t	ic_sensor;
57184cd04cScth 		ipmi_sunoem_fru_t		ic_fru;
58184cd04cScth 	} ic_data;
59184cd04cScth } ipmi_cache_entry_t;
60184cd04cScth 
61184cd04cScth static pthread_mutex_t g_ipmi_mtx = PTHREAD_MUTEX_INITIALIZER;
62184cd04cScth static uu_list_pool_t *g_ipmi_cache_pool;
63184cd04cScth static uu_list_t *g_ipmi_cache;
64184cd04cScth 
65184cd04cScth /*
66184cd04cScth  * The textual strings that are used in the actions may be one of the
67184cd04cScth  * following forms:
68184cd04cScth  *
69184cd04cScth  * [1] `fru gid=<n> hdd=<m>'
70184cd04cScth  * [2] `sensor id=<x> assert=<y> deassert=<z>'
71184cd04cScth  *
72184cd04cScth  * The generic parser will take a string and spit out the first token
73184cd04cScth  * (e.g. `fru' or `sensor') and an nvlist that contains the key-value
74184cd04cScth  * pairs in the rest of the string.  The assumption is that there are
75184cd04cScth  * no embedded spaces or tabs in the keys or values.
76184cd04cScth  */
77184cd04cScth 
78184cd04cScth static boolean_t
isnumber(const char * str)79184cd04cScth isnumber(const char *str)
80184cd04cScth {
81184cd04cScth 	boolean_t hex = B_FALSE;
82184cd04cScth 	int digits = 0;
83184cd04cScth 
84184cd04cScth 	if (strncasecmp(str, "0x", 2) == 0) {
85184cd04cScth 		hex = B_TRUE;
86184cd04cScth 		str += 2;
87184cd04cScth 	} else if (*str == '-' || *str == '+') {
88184cd04cScth 		str++;
89184cd04cScth 	}
90184cd04cScth 
91184cd04cScth 	while (*str != 0) {
92184cd04cScth 		if ((hex && !isxdigit(*str)) ||
93184cd04cScth 		    (!hex && !isdigit(*str))) {
94184cd04cScth 			return (B_FALSE);
95184cd04cScth 		}
96184cd04cScth 
97184cd04cScth 		str++;
98184cd04cScth 		digits++;
99184cd04cScth 	}
100184cd04cScth 
101184cd04cScth 	return ((digits == 0) ? B_FALSE : B_TRUE);
102184cd04cScth }
103184cd04cScth 
104184cd04cScth static void
tolowerString(char * str)105184cd04cScth tolowerString(char *str)
106184cd04cScth {
107184cd04cScth 	while (*str != 0) {
108184cd04cScth 		*str = tolower(*str);
109184cd04cScth 		str++;
110184cd04cScth 	}
111184cd04cScth }
112184cd04cScth 
113184cd04cScth static boolean_t
parse_action_string(const char * actionString,char ** cmdp,nvlist_t ** propsp)114184cd04cScth parse_action_string(const char *actionString, char **cmdp, nvlist_t **propsp)
115184cd04cScth {
116184cd04cScth 	char *action;
117184cd04cScth 	char *tok, *lasts, *eq;
118184cd04cScth 	int actionlen;
119184cd04cScth 	boolean_t rv = B_TRUE;
120184cd04cScth 
121184cd04cScth 	if (nvlist_alloc(propsp, NV_UNIQUE_NAME, 0) != 0)
122184cd04cScth 		return (B_FALSE);
123184cd04cScth 
124184cd04cScth 	actionlen = strlen(actionString) + 1;
125184cd04cScth 	action = dstrdup(actionString);
126184cd04cScth 
127184cd04cScth 	*cmdp = NULL;
128184cd04cScth 
129184cd04cScth 	if ((tok = strtok_r(action, " \t", &lasts)) != NULL) {
130184cd04cScth 
131184cd04cScth 		*cmdp = dstrdup(tok);
132184cd04cScth 
133184cd04cScth 		while (rv && (tok = strtok_r(NULL, " \t", &lasts)) != NULL) {
134184cd04cScth 
135184cd04cScth 			/* Look for a name=val construct */
136184cd04cScth 			if ((eq = strchr(tok, '=')) != NULL && eq[1] != 0) {
137184cd04cScth 
138184cd04cScth 				*eq = 0;
139184cd04cScth 				eq++;
140184cd04cScth 
141184cd04cScth 				/*
142184cd04cScth 				 * Convert token to lowercase to preserve
143184cd04cScth 				 * case-insensitivity, because nvlist doesn't
144184cd04cScth 				 * do case-insensitive lookups
145184cd04cScth 				 */
146184cd04cScth 				tolowerString(tok);
147184cd04cScth 
148184cd04cScth 				if (isnumber(eq)) {
149184cd04cScth 					/* Integer property */
150184cd04cScth 
151184cd04cScth 					if (nvlist_add_uint64(*propsp, tok,
152184cd04cScth 					    strtoull(eq, NULL, 0)) != 0)
153184cd04cScth 						rv = B_FALSE;
154184cd04cScth 				} else {
155184cd04cScth 					/* String property */
156184cd04cScth 
157184cd04cScth 					if (nvlist_add_string(*propsp, tok,
158184cd04cScth 					    eq) != 0)
159184cd04cScth 						rv = B_FALSE;
160184cd04cScth 				}
161184cd04cScth 			} else if (eq == NULL) {
162184cd04cScth 				/* Boolean property */
163184cd04cScth 				if (nvlist_add_boolean(*propsp, tok) != 0)
164184cd04cScth 					rv = B_FALSE;
165184cd04cScth 			} else /* Parse error (`X=' is invalid) */
166184cd04cScth 				rv = B_FALSE;
167184cd04cScth 		}
168184cd04cScth 	} else
169184cd04cScth 		rv = B_FALSE;
170184cd04cScth 
171184cd04cScth 	dfree(action, actionlen);
172184cd04cScth 	if (!rv) {
173184cd04cScth 		if (*cmdp) {
174184cd04cScth 			dstrfree(*cmdp);
175184cd04cScth 			*cmdp = NULL;
176184cd04cScth 		}
177184cd04cScth 		nvlist_free(*propsp);
178184cd04cScth 		*propsp = NULL;
179184cd04cScth 	}
180184cd04cScth 	return (rv);
181184cd04cScth }
182184cd04cScth 
183184cd04cScth static int
platform_update_fru(nvlist_t * props,dm_fru_t * frup)184184cd04cScth platform_update_fru(nvlist_t *props, dm_fru_t *frup)
185184cd04cScth {
186184cd04cScth 	uint64_t gid, hdd;
187184cd04cScth 	ipmi_sunoem_fru_t fru;
188184cd04cScth 	char *buf;
189184cd04cScth 	ipmi_cache_entry_t *entry;
190184cd04cScth 
191184cd04cScth 	if (nvlist_lookup_uint64(props, "gid", &gid) != 0 ||
192184cd04cScth 	    nvlist_lookup_uint64(props, "hdd", &hdd) != 0) {
193184cd04cScth 		return (-1);
194184cd04cScth 	}
195184cd04cScth 
196184cd04cScth 	fru.isf_type = (uint8_t)gid;
197184cd04cScth 	fru.isf_id = (uint8_t)hdd;
198184cd04cScth 
199184cd04cScth 	buf = (char *)dzmalloc(sizeof (fru.isf_data.disk.isf_capacity) + 1);
200184cd04cScth 
201184cd04cScth 	(void) memcpy(fru.isf_data.disk.isf_manufacturer, frup->manuf,
202184cd04cScth 	    MIN(sizeof (fru.isf_data.disk.isf_manufacturer),
203184cd04cScth 	    sizeof (frup->manuf)));
204184cd04cScth 	(void) memcpy(fru.isf_data.disk.isf_model, frup->model,
205184cd04cScth 	    MIN(sizeof (fru.isf_data.disk.isf_model), sizeof (frup->model)));
206184cd04cScth 	(void) memcpy(fru.isf_data.disk.isf_serial, frup->serial,
207184cd04cScth 	    MIN(sizeof (fru.isf_data.disk.isf_serial), sizeof (frup->serial)));
208184cd04cScth 	(void) memcpy(fru.isf_data.disk.isf_version, frup->rev,
209184cd04cScth 	    MIN(sizeof (fru.isf_data.disk.isf_version), sizeof (frup->rev)));
210184cd04cScth 	/*
211184cd04cScth 	 * Print the size of the disk to a temporary buffer whose size is
212184cd04cScth 	 * 1 more than the size of the buffer in the ipmi request data
213184cd04cScth 	 * structure, so we can get the full 8 characters (instead of 7 + NUL)
214184cd04cScth 	 */
215184cd04cScth 	(void) snprintf(buf, sizeof (fru.isf_data.disk.isf_capacity) + 1,
216184cd04cScth 	    "%.1f%s",
217184cd04cScth 	    frup->size_in_bytes >= ONE_PETABYTE ?
218184cd04cScth 	    (frup->size_in_bytes / ONE_PETABYTE) :
219184cd04cScth 	    (frup->size_in_bytes >= ONE_TERABYTE ?
220184cd04cScth 	    (frup->size_in_bytes / ONE_TERABYTE) :
221184cd04cScth 	    (frup->size_in_bytes >= ONE_GIGABYTE ?
222184cd04cScth 	    (frup->size_in_bytes / ONE_GIGABYTE) :
223184cd04cScth 	    (frup->size_in_bytes >= ONE_MEGABYTE ?
224184cd04cScth 	    (frup->size_in_bytes / ONE_MEGABYTE) :
225184cd04cScth 	    (frup->size_in_bytes / ONE_KILOBYTE)))),
226184cd04cScth 
227184cd04cScth 	    frup->size_in_bytes >= ONE_PETABYTE ? "PB" :
228184cd04cScth 	    (frup->size_in_bytes >= ONE_TERABYTE ? "TB" :
229184cd04cScth 	    (frup->size_in_bytes >= ONE_GIGABYTE ? "GB" :
230184cd04cScth 	    (frup->size_in_bytes >= ONE_MEGABYTE ? "MB" :
231184cd04cScth 	    "KB"))));
232184cd04cScth 	(void) memcpy(fru.isf_data.disk.isf_capacity, buf,
233184cd04cScth 	    sizeof (fru.isf_data.disk.isf_capacity));
234184cd04cScth 
235184cd04cScth 	dfree(buf, sizeof (fru.isf_data.disk.isf_capacity) + 1);
236184cd04cScth 
237184cd04cScth 	if (ipmi_sunoem_update_fru(g_ipmi_hdl, &fru) != 0)
238184cd04cScth 		return (-1);
239184cd04cScth 
240184cd04cScth 	/* find a cache entry or create one if necessary */
241184cd04cScth 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
242184cd04cScth 	    entry = uu_list_next(g_ipmi_cache, entry)) {
243184cd04cScth 		if (entry->ic_type == IPMI_CACHE_FRU &&
244184cd04cScth 		    entry->ic_data.ic_fru.isf_type == gid &&
245184cd04cScth 		    entry->ic_data.ic_fru.isf_id == hdd)
246184cd04cScth 			break;
247184cd04cScth 	}
248184cd04cScth 
249184cd04cScth 	if (entry == NULL) {
250184cd04cScth 		entry = dzmalloc(sizeof (ipmi_cache_entry_t));
251184cd04cScth 		entry->ic_type = IPMI_CACHE_FRU;
252184cd04cScth 		(void) uu_list_insert_before(g_ipmi_cache, NULL, entry);
253184cd04cScth 	}
254184cd04cScth 
255184cd04cScth 	(void) memcpy(&entry->ic_data.ic_fru, &fru, sizeof (fru));
256184cd04cScth 
257184cd04cScth 	return (0);
258184cd04cScth }
259184cd04cScth 
260184cd04cScth static int
platform_set_sensor(nvlist_t * props)261184cd04cScth platform_set_sensor(nvlist_t *props)
262184cd04cScth {
263184cd04cScth 	uint64_t assertmask = 0, deassertmask = 0, sid;
264184cd04cScth 	boolean_t am_present, dam_present;
265184cd04cScth 	ipmi_set_sensor_reading_t sr, *sp;
266184cd04cScth 	ipmi_cache_entry_t *entry;
267184cd04cScth 	int ret;
268184cd04cScth 
269184cd04cScth 	/* We need at least 2 properties: `sid' and (`amask' || `dmask'): */
270184cd04cScth 	am_present = nvlist_lookup_uint64(props, "amask", &assertmask) == 0;
271184cd04cScth 	dam_present = nvlist_lookup_uint64(props, "dmask", &deassertmask) == 0;
272184cd04cScth 
273184cd04cScth 	if (nvlist_lookup_uint64(props, "sid", &sid) != 0 ||
274184cd04cScth 	    (!am_present && !dam_present)) {
275184cd04cScth 		return (-1);
276184cd04cScth 	}
277184cd04cScth 
278184cd04cScth 	if (sid > UINT8_MAX) {
279184cd04cScth 		log_warn("IPMI Plugin: Invalid sensor id `0x%llx'.\n",
280184cd04cScth 		    (longlong_t)sid);
281184cd04cScth 		return (-1);
282184cd04cScth 	} else if (assertmask > UINT16_MAX) {
283184cd04cScth 		log_warn("IPMI Plugin: Invalid assertion mask `0x%llx'.\n",
284184cd04cScth 		    (longlong_t)assertmask);
285184cd04cScth 		return (-1);
286184cd04cScth 	} else if (assertmask > UINT16_MAX) {
287184cd04cScth 		log_warn("IPMI Plugin: Invalid deassertion mask `0x%llx'.\n",
288184cd04cScth 		    (longlong_t)deassertmask);
289184cd04cScth 		return (-1);
290184cd04cScth 	}
291184cd04cScth 
292184cd04cScth 	(void) memset(&sr, '\0', sizeof (sr));
293184cd04cScth 	sr.iss_id = (uint8_t)sid;
294184cd04cScth 	if (am_present) {
295184cd04cScth 		sr.iss_assert_op = IPMI_SENSOR_OP_SET;
296184cd04cScth 		sr.iss_assert_state = (uint16_t)assertmask;
297184cd04cScth 	}
298184cd04cScth 	if (dam_present) {
299184cd04cScth 		sr.iss_deassrt_op = IPMI_SENSOR_OP_SET;
300184cd04cScth 		sr.iss_deassert_state = (uint16_t)deassertmask;
301184cd04cScth 	}
302184cd04cScth 
303184cd04cScth 	ret = ipmi_set_sensor_reading(g_ipmi_hdl, &sr);
304184cd04cScth 
305184cd04cScth 	/* find a cache entry or create one if necessary */
306184cd04cScth 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
307184cd04cScth 	    entry = uu_list_next(g_ipmi_cache, entry)) {
308184cd04cScth 		if (entry->ic_type == IPMI_CACHE_SENSOR &&
309184cd04cScth 		    entry->ic_data.ic_sensor.iss_id == (uint8_t)sid)
310184cd04cScth 			break;
311184cd04cScth 	}
312184cd04cScth 
313184cd04cScth 	if (entry == NULL) {
314184cd04cScth 		entry = dzmalloc(sizeof (ipmi_cache_entry_t));
315184cd04cScth 		entry->ic_type = IPMI_CACHE_SENSOR;
316184cd04cScth 		(void) uu_list_insert_before(g_ipmi_cache, NULL, entry);
317184cd04cScth 		entry->ic_data.ic_sensor.iss_id = (uint8_t)sid;
318184cd04cScth 		entry->ic_data.ic_sensor.iss_assert_op = IPMI_SENSOR_OP_SET;
319184cd04cScth 		entry->ic_data.ic_sensor.iss_deassrt_op = IPMI_SENSOR_OP_SET;
320184cd04cScth 	}
321184cd04cScth 	sp = &entry->ic_data.ic_sensor;
322184cd04cScth 
323184cd04cScth 	if (am_present) {
324184cd04cScth 		sp->iss_assert_state |= assertmask;
325184cd04cScth 		sp->iss_deassert_state &= ~assertmask;
326184cd04cScth 	}
327184cd04cScth 	if (dam_present) {
328184cd04cScth 		sp->iss_deassert_state |= deassertmask;
329184cd04cScth 		sp->iss_assert_state &= ~deassertmask;
330184cd04cScth 	}
331184cd04cScth 
332184cd04cScth 	return (ret);
333184cd04cScth }
334184cd04cScth 
335184cd04cScth #define	PROTOCOL_SEPARATOR ':'
336184cd04cScth 
337184cd04cScth static char *
extract_protocol(const char * action)338184cd04cScth extract_protocol(const char *action)
339184cd04cScth {
340184cd04cScth 	char *s = strchr(action, PROTOCOL_SEPARATOR);
341184cd04cScth 	char *proto = NULL;
342184cd04cScth 	int len;
343184cd04cScth 	int i = 0;
344184cd04cScth 
345184cd04cScth 	/* The protocol is the string before the separator, but in lower-case */
346184cd04cScth 	if (s) {
347184cd04cScth 		len = (uintptr_t)s - (uintptr_t)action;
348184cd04cScth 		proto = (char *)dmalloc(len + 1);
349184cd04cScth 		while (i < len) {
350184cd04cScth 			proto[i] = tolower(action[i]);
351184cd04cScth 			i++;
352184cd04cScth 		}
353184cd04cScth 		proto[len] = 0;
354184cd04cScth 	}
355184cd04cScth 
356184cd04cScth 	return (proto);
357184cd04cScth }
358184cd04cScth 
359184cd04cScth static char *
extract_action(const char * action)360184cd04cScth extract_action(const char *action)
361184cd04cScth {
362184cd04cScth 	/* The action is the string after the separator */
363184cd04cScth 	char *s = strchr(action, PROTOCOL_SEPARATOR);
364184cd04cScth 
365184cd04cScth 	return (s ? (s + 1) : NULL);
366184cd04cScth }
367184cd04cScth 
368184cd04cScth static int
do_action(const char * action,dm_fru_t * fru)369184cd04cScth do_action(const char *action, dm_fru_t *fru)
370184cd04cScth {
371184cd04cScth 	nvlist_t	*props;
372184cd04cScth 	char		*cmd;
373184cd04cScth 	int rv = -1;
374184cd04cScth 	char		*protocol = extract_protocol(action);
375184cd04cScth 	char		*actionp = extract_action(action);
376184cd04cScth 
377184cd04cScth 	if (strcmp(protocol, "ipmi") != 0) {
378184cd04cScth 		log_err("unknown protocol '%s'\n", protocol);
379184cd04cScth 		dstrfree(protocol);
380184cd04cScth 		return (-1);
381184cd04cScth 	}
382184cd04cScth 
383184cd04cScth 	dstrfree(protocol);
384184cd04cScth 
385184cd04cScth 	(void) pthread_mutex_lock(&g_ipmi_mtx);
386184cd04cScth 	if (parse_action_string(actionp, &cmd, &props)) {
387184cd04cScth 		if (strcmp(cmd, "fru") == 0) {
388184cd04cScth 			rv = platform_update_fru(props, fru);
389184cd04cScth 		} else if (strcmp(cmd, "state") == 0) {
390184cd04cScth 			rv = platform_set_sensor(props);
391184cd04cScth 		} else {
392184cd04cScth 			log_err("unknown platform action '%s'\n", cmd);
393184cd04cScth 		}
394184cd04cScth 		dstrfree(cmd);
395184cd04cScth 		nvlist_free(props);
396184cd04cScth 	}
397184cd04cScth 	(void) pthread_mutex_unlock(&g_ipmi_mtx);
398184cd04cScth 
399184cd04cScth 	return (rv);
400184cd04cScth }
401184cd04cScth 
402184cd04cScth int
dm_platform_update_fru(const char * action,dm_fru_t * fru)403184cd04cScth dm_platform_update_fru(const char *action, dm_fru_t *fru)
404184cd04cScth {
405184cd04cScth 	return (do_action(action, fru));
406184cd04cScth }
407184cd04cScth 
408184cd04cScth int
dm_platform_indicator_execute(const char * action)409184cd04cScth dm_platform_indicator_execute(const char *action)
410184cd04cScth {
411184cd04cScth 	return (do_action(action, NULL));
412184cd04cScth }
413184cd04cScth 
414184cd04cScth int
dm_platform_resync(void)415184cd04cScth dm_platform_resync(void)
416184cd04cScth {
417184cd04cScth 	ipmi_cache_entry_t *entry;
418184cd04cScth 	int rv = 0;
419184cd04cScth 
420184cd04cScth 	(void) pthread_mutex_lock(&g_ipmi_mtx);
421184cd04cScth 
422184cd04cScth 	/*
423184cd04cScth 	 * Called when the SP is reset, as the sensor/FRU state is not
424184cd04cScth 	 * maintained across reboots.  Note that we must update the FRU
425184cd04cScth 	 * information first, as certain sensor states prevent this from
426184cd04cScth 	 * working.
427184cd04cScth 	 */
428184cd04cScth 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
429184cd04cScth 	    entry = uu_list_next(g_ipmi_cache, entry)) {
430184cd04cScth 		if (entry->ic_type == IPMI_CACHE_FRU)
431184cd04cScth 			rv |= ipmi_sunoem_update_fru(g_ipmi_hdl,
432184cd04cScth 			    &entry->ic_data.ic_fru);
433184cd04cScth 	}
434184cd04cScth 
435184cd04cScth 	for (entry = uu_list_first(g_ipmi_cache); entry != NULL;
436184cd04cScth 	    entry = uu_list_next(g_ipmi_cache, entry)) {
437184cd04cScth 		if (entry->ic_type == IPMI_CACHE_SENSOR)
438184cd04cScth 			rv |= ipmi_set_sensor_reading(g_ipmi_hdl,
439184cd04cScth 			    &entry->ic_data.ic_sensor);
440184cd04cScth 	}
441184cd04cScth 
442184cd04cScth 	(void) pthread_mutex_unlock(&g_ipmi_mtx);
443184cd04cScth 	return (rv);
444184cd04cScth }
445184cd04cScth 
446184cd04cScth int
dm_platform_init(void)447184cd04cScth dm_platform_init(void)
448184cd04cScth {
449184cd04cScth 	int err;
450184cd04cScth 	char *msg;
451184cd04cScth 
452*81d9f076SRobert Johnston 	if ((g_ipmi_hdl = ipmi_open(&err, &msg, IPMI_TRANSPORT_BMC, NULL))
453*81d9f076SRobert Johnston 	    == NULL) {
454184cd04cScth 		log_warn("Failed to load libipmi: %s\n", msg);
455184cd04cScth 		return (-1);
456184cd04cScth 	}
457184cd04cScth 
458184cd04cScth 	if ((g_ipmi_cache_pool = uu_list_pool_create(
459184cd04cScth 	    "ipmi_cache", sizeof (ipmi_cache_entry_t),
460184cd04cScth 	    offsetof(ipmi_cache_entry_t, ic_node), NULL, 0)) == NULL)
461184cd04cScth 		return (-1);
462184cd04cScth 
463184cd04cScth 	if ((g_ipmi_cache = uu_list_create(g_ipmi_cache_pool, NULL, 0))
464184cd04cScth 	    == NULL)
465184cd04cScth 		return (-1);
466184cd04cScth 
467184cd04cScth 	return (0);
468184cd04cScth }
469184cd04cScth 
470184cd04cScth void
dm_platform_fini(void)471184cd04cScth dm_platform_fini(void)
472184cd04cScth {
473184cd04cScth 	if (g_ipmi_hdl)
474184cd04cScth 		ipmi_close(g_ipmi_hdl);
475184cd04cScth 	if (g_ipmi_cache) {
476184cd04cScth 		ipmi_cache_entry_t *entry;
477184cd04cScth 
478184cd04cScth 		while ((entry = uu_list_first(g_ipmi_cache)) != NULL) {
479184cd04cScth 			uu_list_remove(g_ipmi_cache, entry);
480184cd04cScth 			dfree(entry, sizeof (*entry));
481184cd04cScth 		}
482184cd04cScth 		uu_list_destroy(g_ipmi_cache);
483184cd04cScth 	}
484184cd04cScth 	if (g_ipmi_cache_pool)
485184cd04cScth 		uu_list_pool_destroy(g_ipmi_cache_pool);
486184cd04cScth }
487