xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c (revision 88045cff0aae4ed8823cd0989168e8f56927f83e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <limits.h>
32 #include <alloca.h>
33 #include <errno.h>
34 #include <libnvpair.h>
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/fm/protocol.h>
38 #include <fm/libtopo.h>
39 #include <fm/topo_mod.h>
40 #include <libipmi.h>
41 
42 #define	BUFSZ	128
43 
44 #define	BAY_PRESENT_LED_MASK	0x01
45 
46 /*
47  * The largest possible SDR ID length is 2^5+1
48  */
49 #define	MAX_ID_LEN	33
50 
51 #define	TOPO_METH_IPMI_READING_VERSION		0
52 #define	TOPO_METH_IPMI_STATE_VERSION		0
53 #define	TOPO_METH_IPMI_MODE_VERSION		0
54 #define	TOPO_METH_X4500_MODE_VERSION		0
55 #define	TOPO_METH_BAY_LOCATE_VERSION		0
56 #define	TOPO_METH_BAY_MODE_VERSION		0
57 #define	TOPO_METH_CHASSIS_SERVICE_VERSION	0
58 #define	TOPO_METH_IPMI_ENTITY_VERSION		0
59 #define	TOPO_METH_DIMM_IPMI_ENTITY_VERSION	0
60 
61 static int fac_prov_ipmi_enum(topo_mod_t *, tnode_t *, const char *,
62     topo_instance_t, topo_instance_t, void *, void *);
63 
64 /*
65  * IPMI facility provider methods
66  */
67 static int ipmi_sensor_enum(topo_mod_t *, tnode_t *, topo_version_t,
68     nvlist_t *, nvlist_t **);
69 static int ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
70     nvlist_t **);
71 static int dimm_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
72     nvlist_t **);
73 static int cs_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
74     nvlist_t **);
75 static int ipmi_sensor_reading(topo_mod_t *, tnode_t *, topo_version_t,
76     nvlist_t *, nvlist_t **);
77 static int ipmi_sensor_state(topo_mod_t *, tnode_t *, topo_version_t,
78     nvlist_t *, nvlist_t **);
79 static int ipmi_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
80     nvlist_t *, nvlist_t **);
81 static int bay_locate_mode(topo_mod_t *, tnode_t *, topo_version_t,
82     nvlist_t *, nvlist_t **);
83 static int x4500_present_mode(topo_mod_t *, tnode_t *, topo_version_t,
84     nvlist_t *, nvlist_t **);
85 static int bay_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
86     nvlist_t *, nvlist_t **);
87 static int chassis_service_mode(topo_mod_t *, tnode_t *, topo_version_t,
88     nvlist_t *, nvlist_t **);
89 
90 const topo_modops_t ipmi_ops = { fac_prov_ipmi_enum, NULL };
91 
92 const topo_modinfo_t ipmi_info =
93 	{ "IPMI facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION,
94 	&ipmi_ops };
95 
96 static const topo_method_t ipmi_node_methods[] = {
97 	{ TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
98 	    TOPO_STABILITY_INTERNAL, ipmi_sensor_enum },
99 	{ TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
100 	    TOPO_METH_IPMI_ENTITY_VERSION,
101 	    TOPO_STABILITY_INTERNAL, ipmi_entity },
102 	{ "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
103 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
104 	    TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
105 	{ "cs_ipmi_entity", TOPO_PROP_METH_DESC,
106 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
107 	    TOPO_STABILITY_INTERNAL, cs_ipmi_entity },
108 	{ NULL }
109 };
110 
111 static const topo_method_t ipmi_fac_methods[] = {
112 	{ "ipmi_sensor_reading", TOPO_PROP_METH_DESC,
113 	    TOPO_METH_IPMI_READING_VERSION,
114 	    TOPO_STABILITY_INTERNAL, ipmi_sensor_reading },
115 	{ "ipmi_sensor_state", TOPO_PROP_METH_DESC,
116 	    TOPO_METH_IPMI_STATE_VERSION,
117 	    TOPO_STABILITY_INTERNAL, ipmi_sensor_state },
118 	{ "ipmi_indicator_mode", TOPO_PROP_METH_DESC,
119 	    TOPO_METH_IPMI_MODE_VERSION,
120 	    TOPO_STABILITY_INTERNAL, ipmi_indicator_mode },
121 	{ "bay_locate_mode", TOPO_PROP_METH_DESC,
122 	    TOPO_METH_BAY_LOCATE_VERSION,
123 	    TOPO_STABILITY_INTERNAL, bay_locate_mode },
124 	{ "bay_indicator_mode", TOPO_PROP_METH_DESC,
125 	    TOPO_METH_BAY_MODE_VERSION,
126 	    TOPO_STABILITY_INTERNAL, bay_indicator_mode },
127 	{ "chassis_service_mode", TOPO_PROP_METH_DESC,
128 	    TOPO_METH_CHASSIS_SERVICE_VERSION,
129 	    TOPO_STABILITY_INTERNAL, chassis_service_mode },
130 	{ "x4500_present_mode", TOPO_PROP_METH_DESC,
131 	    TOPO_METH_CHASSIS_SERVICE_VERSION,
132 	    TOPO_STABILITY_INTERNAL, x4500_present_mode },
133 	{ TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
134 	    TOPO_METH_IPMI_ENTITY_VERSION,
135 	    TOPO_STABILITY_INTERNAL, ipmi_entity },
136 	{ "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
137 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
138 	    TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
139 	{ "cs_ipmi_entity", TOPO_PROP_METH_DESC,
140 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
141 	    TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
142 	{ NULL }
143 };
144 
145 struct entity_info {
146 	uint32_t ei_id;
147 	uint32_t ei_inst;
148 	topo_mod_t *ei_mod;
149 	tnode_t *ei_node;
150 };
151 
152 struct sensor_data {
153 	char sd_entity_ref[MAX_ID_LEN];
154 	uint8_t sd_units;
155 	uint32_t sd_stype;
156 	uint32_t sd_rtype;
157 	char *sd_class;
158 };
159 
160 /*ARGSUSED*/
161 int
162 _topo_init(topo_mod_t *mod, topo_version_t version)
163 {
164 	if (getenv("TOPOFACIPMIDEBUG") != NULL)
165 		topo_mod_setdebug(mod);
166 
167 	return (topo_mod_register(mod, &ipmi_info, TOPO_VERSION));
168 }
169 
170 void
171 _topo_fini(topo_mod_t *mod)
172 {
173 	topo_mod_unregister(mod);
174 }
175 
176 static void
177 strarr_free(topo_mod_t *mod, char **arr, uint_t nelems)
178 {
179 	for (int i = 0; i < nelems; i++)
180 		topo_mod_strfree(mod, arr[i]);
181 	topo_mod_free(mod, arr, (nelems * sizeof (char *)));
182 }
183 
184 /*ARGSUSED*/
185 static int
186 ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
187     nvlist_t *in, nvlist_t **out)
188 {
189 	char **entity_refs;
190 	uint_t nelems;
191 	ipmi_sdr_t *sdr = NULL;
192 	ipmi_sensor_reading_t *reading;
193 	ipmi_handle_t *hdl;
194 	int err, i;
195 	uint8_t sensor_num;
196 	ipmi_sdr_full_sensor_t *fsensor;
197 	ipmi_sdr_compact_sensor_t *csensor;
198 	nvlist_t *nvl;
199 	boolean_t found_sdr = B_FALSE;
200 
201 	if (vers > TOPO_METH_IPMI_STATE_VERSION)
202 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
203 
204 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
205 	    &entity_refs, &nelems, &err) != 0) {
206 		topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
207 		    "property (%s)", __func__, topo_strerror(err));
208 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
209 	}
210 
211 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
212 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
213 		strarr_free(mod, entity_refs, nelems);
214 		return (-1);
215 	}
216 
217 	for (i = 0; i < nelems; i++) {
218 		if ((sdr = ipmi_sdr_lookup(hdl, entity_refs[i])) != NULL) {
219 			found_sdr = B_TRUE;
220 			break;
221 		} else
222 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
223 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
224 	}
225 
226 	if (! found_sdr) {
227 		strarr_free(mod, entity_refs, nelems);
228 		topo_mod_ipmi_rele(mod);
229 		return (-1);
230 	}
231 
232 	switch (sdr->is_type) {
233 		case IPMI_SDR_TYPE_FULL_SENSOR:
234 			fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record;
235 			sensor_num = fsensor->is_fs_number;
236 			break;
237 		case IPMI_SDR_TYPE_COMPACT_SENSOR:
238 			csensor = (ipmi_sdr_compact_sensor_t *)sdr->is_record;
239 			sensor_num = csensor->is_cs_number;
240 			break;
241 		default:
242 			topo_mod_dprintf(mod, "%s does not refer to a full or "
243 			    "compact SDR\n", entity_refs[i]);
244 			topo_mod_ipmi_rele(mod);
245 			strarr_free(mod, entity_refs, nelems);
246 			return (-1);
247 	}
248 	if ((reading = ipmi_get_sensor_reading(hdl, sensor_num))
249 	    == NULL) {
250 		topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
251 		    "%s, sensor_num=%d (%s)\n", entity_refs[i], sensor_num,
252 		    ipmi_errmsg(hdl));
253 		strarr_free(mod, entity_refs, nelems);
254 		topo_mod_ipmi_rele(mod);
255 		return (-1);
256 	}
257 	strarr_free(mod, entity_refs, nelems);
258 	topo_mod_ipmi_rele(mod);
259 
260 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
261 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
262 	    TOPO_SENSOR_STATE) != 0 ||
263 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
264 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, reading->isr_state)
265 	    != 0) {
266 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
267 		nvlist_free(nvl);
268 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
269 	}
270 	*out = nvl;
271 
272 	return (0);
273 }
274 
275 /*ARGSUSED*/
276 static int
277 ipmi_sensor_reading(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
278     nvlist_t *in, nvlist_t **out)
279 {
280 	char **entity_refs, reading_str[BUFSZ];
281 	uint_t nelems;
282 	int err = 0, i;
283 	ipmi_sdr_full_sensor_t *sensor;
284 	ipmi_sensor_reading_t  *reading;
285 	double conv_reading;
286 	ipmi_handle_t *hdl;
287 	nvlist_t *nvl;
288 	boolean_t found_sdr = B_FALSE;
289 
290 	if (vers > TOPO_METH_IPMI_READING_VERSION)
291 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
292 
293 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
294 	    &entity_refs, &nelems, &err) != 0) {
295 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
296 		    "(%s)", topo_strerror(err));
297 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
298 	}
299 
300 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
301 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
302 		strarr_free(mod, entity_refs, nelems);
303 		return (-1);
304 	}
305 
306 	for (i = 0; i < nelems; i++) {
307 		if ((sensor = ipmi_sdr_lookup_full_sensor(hdl, entity_refs[i]))
308 		    != NULL) {
309 			found_sdr = B_TRUE;
310 			break;
311 		} else
312 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
313 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
314 	}
315 
316 	if (! found_sdr) {
317 		strarr_free(mod, entity_refs, nelems);
318 		topo_mod_ipmi_rele(mod);
319 		return (-1);
320 	}
321 
322 	if ((reading = ipmi_get_sensor_reading(hdl, sensor->is_fs_number))
323 	    == NULL) {
324 		topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
325 		    "%s, sensor_num=%d (%s)\n", entity_refs[i],
326 		    sensor->is_fs_number, ipmi_errmsg(hdl));
327 		strarr_free(mod, entity_refs, nelems);
328 		topo_mod_ipmi_rele(mod);
329 		return (-1);
330 	}
331 	topo_mod_ipmi_rele(mod);
332 
333 	if (ipmi_sdr_conv_reading(sensor, reading->isr_reading, &conv_reading)
334 	    != 0) {
335 		topo_mod_dprintf(mod, "Failed to convert sensor reading for "
336 		    "sensor %s (%s)\n", entity_refs[i], ipmi_errmsg(hdl));
337 		strarr_free(mod, entity_refs, nelems);
338 		return (-1);
339 	}
340 	strarr_free(mod, entity_refs, nelems);
341 
342 	(void) snprintf(reading_str, BUFSZ, "%f", conv_reading);
343 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
344 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
345 	    TOPO_SENSOR_READING) != 0 ||
346 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_DOUBLE) != 0 ||
347 	    nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, conv_reading) != 0) {
348 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
349 		nvlist_free(nvl);
350 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
351 	}
352 	*out = nvl;
353 
354 	return (0);
355 }
356 
357 static int
358 ipmi_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
359     nvlist_t *in, nvlist_t **out)
360 {
361 	char **entity_refs;
362 	uint_t nelems;
363 	ipmi_sdr_generic_locator_t *gdl = NULL;
364 	ipmi_handle_t *hdl;
365 	int err, ret, i;
366 	uint8_t ledmode;
367 	uint32_t mode_in;
368 	nvlist_t *pargs, *nvl;
369 	boolean_t found_sdr = B_FALSE;
370 
371 	if (vers > TOPO_METH_IPMI_MODE_VERSION)
372 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
373 
374 	/*
375 	 * Get an IPMI handle and then lookup the generic device locator sensor
376 	 * data record referenced by the entity_ref prop val
377 	 */
378 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
379 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
380 		return (-1);
381 	}
382 
383 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
384 	    &entity_refs, &nelems, &err) != 0) {
385 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
386 		    "(%s)", topo_strerror(err));
387 		topo_mod_ipmi_rele(mod);
388 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
389 	}
390 
391 	for (i = 0; i < nelems; i++) {
392 		if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
393 		    != NULL) {
394 			found_sdr = B_TRUE;
395 			break;
396 		} else
397 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
398 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
399 	}
400 
401 	if (! found_sdr) {
402 		strarr_free(mod, entity_refs, nelems);
403 		topo_mod_ipmi_rele(mod);
404 		return (-1);
405 	}
406 
407 	/*
408 	 * Now look for a private argument list to figure out whether we're
409 	 * doing a get or a set operation, and then do it.
410 	 */
411 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
412 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
413 		/*
414 		 * Set the LED mode
415 		 */
416 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
417 		    &mode_in)) != 0) {
418 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
419 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
420 			strarr_free(mod, entity_refs, nelems);
421 			topo_mod_ipmi_rele(mod);
422 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
423 		}
424 		if (mode_in != TOPO_LED_STATE_OFF &&
425 		    mode_in != TOPO_LED_STATE_ON) {
426 			topo_mod_dprintf(mod, "Invalid property value: %d\n",
427 			    mode_in);
428 			strarr_free(mod, entity_refs, nelems);
429 			topo_mod_ipmi_rele(mod);
430 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
431 		}
432 		ledmode = (uint8_t)mode_in;
433 		if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
434 			topo_mod_dprintf(mod, "%s: Failed to set LED mode for "
435 			    "%s (%s) to %s\n", __func__, entity_refs[i],
436 			    ipmi_errmsg(hdl), ledmode ? "ON" : "OFF");
437 			strarr_free(mod, entity_refs, nelems);
438 			topo_mod_ipmi_rele(mod);
439 			return (-1);
440 		}
441 	} else {
442 		/*
443 		 * Get the LED mode
444 		 */
445 		if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
446 			topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
447 			    "%s (%s)\n", __func__, entity_refs[i],
448 			    ipmi_errmsg(hdl));
449 			strarr_free(mod, entity_refs, nelems);
450 			topo_mod_ipmi_rele(mod);
451 			return (-1);
452 		}
453 	}
454 	strarr_free(mod, entity_refs, nelems);
455 	topo_mod_ipmi_rele(mod);
456 
457 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
458 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
459 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
460 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
461 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
462 		nvlist_free(nvl);
463 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
464 	}
465 	*out = nvl;
466 
467 	return (0);
468 }
469 
470 /*
471  * On most Sun platforms there is no seperate locate LED for the drive bays.
472  * This propmethod simulates a locate LED by blinking the ok2rm LED.
473  *
474  * LED control is through a the Sun OEM led/get commands.  This propmethod can
475  * work on X4500/X4540 with ILOM 2.x and on
476  * X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms with ILOM 3.x.
477  */
478 static int
479 bay_locate_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
480     nvlist_t *in, nvlist_t **out)
481 {
482 	char **entity_refs;
483 	uint_t nelems;
484 	ipmi_sdr_generic_locator_t *gdl = NULL;
485 	ipmi_handle_t *hdl;
486 	int err, ret, i;
487 	uint8_t ledmode;
488 	uint32_t mode_in;
489 	nvlist_t *pargs, *nvl;
490 	boolean_t found_sdr = B_FALSE;
491 
492 	if (vers > TOPO_METH_BAY_LOCATE_VERSION)
493 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
494 
495 	/*
496 	 * Get an IPMI handle and then lookup the generic device locator sensor
497 	 * data record referenced by the entity_ref prop val
498 	 */
499 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
500 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
501 		return (-1);
502 	}
503 
504 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
505 	    &entity_refs, &nelems, &err) != 0) {
506 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
507 		    "(%s)", topo_strerror(err));
508 		topo_mod_ipmi_rele(mod);
509 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
510 	}
511 
512 	for (i = 0; i < nelems; i++) {
513 		if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
514 		    != NULL) {
515 			found_sdr = B_TRUE;
516 			break;
517 		} else
518 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
519 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
520 	}
521 
522 	if (! found_sdr) {
523 		strarr_free(mod, entity_refs, nelems);
524 		topo_mod_ipmi_rele(mod);
525 		return (-1);
526 	}
527 
528 	/*
529 	 * Now look for a private argument list to figure out whether we're
530 	 * doing a get or a set operation, and then do it.
531 	 */
532 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
533 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
534 		/*
535 		 * Set the LED mode
536 		 */
537 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
538 		    &mode_in)) != 0) {
539 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
540 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
541 			strarr_free(mod, entity_refs, nelems);
542 			topo_mod_ipmi_rele(mod);
543 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
544 		}
545 		if (mode_in != TOPO_LED_STATE_OFF &&
546 		    mode_in != TOPO_LED_STATE_ON) {
547 			topo_mod_dprintf(mod, "Invalid property value: %d\n",
548 			    mode_in);
549 			strarr_free(mod, entity_refs, nelems);
550 			topo_mod_ipmi_rele(mod);
551 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
552 		}
553 		if (mode_in == TOPO_LED_STATE_ON)
554 			ledmode = IPMI_SUNOEM_LED_MODE_FAST;
555 		else
556 			ledmode = IPMI_SUNOEM_LED_MODE_OFF;
557 		if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
558 			topo_mod_dprintf(mod, "Failed to set LED mode for %s "
559 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
560 			strarr_free(mod, entity_refs, nelems);
561 			topo_mod_ipmi_rele(mod);
562 			return (-1);
563 		}
564 	} else {
565 		/*
566 		 * Get the LED mode
567 		 */
568 		if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
569 			topo_mod_dprintf(mod, "Failed to get LED mode for %s "
570 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
571 			strarr_free(mod, entity_refs, nelems);
572 			topo_mod_ipmi_rele(mod);
573 			return (-1);
574 		}
575 	}
576 	strarr_free(mod, entity_refs, nelems);
577 	topo_mod_ipmi_rele(mod);
578 
579 	if (ledmode == IPMI_SUNOEM_LED_MODE_SLOW ||
580 	    ledmode == IPMI_SUNOEM_LED_MODE_FAST)
581 		ledmode = TOPO_LED_STATE_ON;
582 	else
583 		ledmode = TOPO_LED_STATE_OFF;
584 
585 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
586 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
587 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
588 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
589 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
590 		nvlist_free(nvl);
591 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
592 	}
593 	*out = nvl;
594 
595 	return (0);
596 }
597 
598 /*
599  * This is a method for the "mode" property that is specific for the ok2rm and
600  * service drive bay LED's on the X4500/X4540 platforms running ILOM 2.x and
601  * for X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms running
602  * ILOM 3.x.
603  *
604  * For ILOM 2.x, the LED's are controlled by a Sun OEM led set command
605  *
606  * For ILOM 3.x platforms the LED's are controlled by sending a platform event
607  * message for the appropriate DBP/HDD##/STATE compact SDR.
608  *
609  * For both ILOM 2 and ILOM 3, the current LED mode can be obtained by a
610  * Sun OEM led get command.
611  */
612 static int
613 bay_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
614     nvlist_t *in, nvlist_t **out)
615 {
616 	char **entity_refs;
617 	uint_t nelems;
618 	ipmi_sdr_compact_sensor_t *cs = NULL;
619 	ipmi_sdr_generic_locator_t *gdl = NULL;
620 	ipmi_deviceid_t *sp_devid;
621 	ipmi_platform_event_message_t pem;
622 	ipmi_handle_t *hdl;
623 	int err, ret, i;
624 	uint32_t type, ledmode;
625 	uint8_t mode_in, ev_off;
626 	nvlist_t *pargs, *nvl;
627 	boolean_t found_sdr = B_FALSE;
628 
629 	if (vers > TOPO_METH_BAY_MODE_VERSION)
630 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
631 
632 	if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
633 	    &type, &err) != 0) {
634 		topo_mod_dprintf(mod, "Failed to lookup %s property "
635 		    "(%s)", TOPO_FACILITY_TYPE, topo_strerror(err));
636 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
637 	}
638 	switch (type) {
639 	case (TOPO_LED_TYPE_SERVICE):
640 		ev_off = 0x01;
641 		break;
642 	case (TOPO_LED_TYPE_OK2RM):
643 		ev_off = 0x03;
644 		break;
645 	default:
646 		topo_mod_dprintf(mod, "Invalid LED type: 0x%x\n", type);
647 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
648 	}
649 
650 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
651 	    &entity_refs, &nelems, &err) != 0) {
652 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
653 		    "(%s)", topo_strerror(err));
654 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
655 	}
656 
657 	/*
658 	 * Figure out whether the SP is running ILOM 2.x or ILOM 3.x
659 	 */
660 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
661 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
662 		strarr_free(mod, entity_refs, nelems);
663 		return (-1);
664 	}
665 
666 	if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
667 		topo_mod_dprintf(mod, "%s: GET DEVICEID command failed (%s)\n",
668 		    __func__, ipmi_errmsg(hdl));
669 		strarr_free(mod, entity_refs, nelems);
670 		topo_mod_ipmi_rele(mod);
671 		return (-1);
672 	}
673 
674 	/*
675 	 * Now lookup the propmethod argument list and figure out whether we're
676 	 * doing a get or a set operation, and then do it.
677 	 */
678 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
679 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
680 		/*
681 		 * Set the LED mode
682 		 */
683 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
684 		    &ledmode)) != 0) {
685 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
686 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
687 			strarr_free(mod, entity_refs, nelems);
688 			topo_mod_ipmi_rele(mod);
689 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
690 		}
691 
692 		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
693 		    ledmode ? "ON" : "OFF");
694 
695 		if (sp_devid->id_firm_major == 2) {
696 			for (i = 0; i < nelems; i++) {
697 				if ((gdl = ipmi_sdr_lookup_generic(hdl,
698 				    entity_refs[i])) != NULL) {
699 					found_sdr = B_TRUE;
700 					break;
701 				} else
702 					topo_mod_dprintf(mod,
703 					    "Failed to lookup SDR for %s(%s)\n",
704 					    entity_refs[i], ipmi_errmsg(hdl));
705 			}
706 
707 			if (! found_sdr) {
708 				strarr_free(mod, entity_refs, nelems);
709 				topo_mod_ipmi_rele(mod);
710 				return (-1);
711 			}
712 
713 			if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)ledmode)
714 			    < 0) {
715 				topo_mod_dprintf(mod,
716 				    "Failed to set LED mode for %s (%s)\n",
717 				    entity_refs[i], ipmi_errmsg(hdl));
718 				strarr_free(mod, entity_refs, nelems);
719 				topo_mod_ipmi_rele(mod);
720 				return (-1);
721 			}
722 		} else {
723 			for (i = 0; i < nelems; i++) {
724 				if ((cs = ipmi_sdr_lookup_compact_sensor(hdl,
725 				    entity_refs[i])) != NULL) {
726 					found_sdr = B_TRUE;
727 					break;
728 				} else
729 					topo_mod_dprintf(mod,
730 					    "Failed to lookup SDR for %s(%s)\n",
731 					    entity_refs[i], ipmi_errmsg(hdl));
732 			}
733 
734 			if (! found_sdr) {
735 				strarr_free(mod, entity_refs, nelems);
736 				topo_mod_ipmi_rele(mod);
737 				return (-1);
738 			}
739 
740 			pem.ipem_generator = IPMI_SEL_SYSTEM;
741 			pem.ipem_rev = IPMI_EV_REV15;
742 			pem.ipem_sensor_type = IPMI_ST_BAY;
743 			pem.ipem_sensor_num = cs->is_cs_number;
744 			pem.ipem_event_type =  IPMI_RT_SPECIFIC;
745 			if (ledmode == TOPO_LED_STATE_ON)
746 				pem.ipem_event_dir = 0;
747 			else
748 				pem.ipem_event_dir = 1;
749 
750 			pem.ipem_event_data[0] = ev_off;
751 			pem.ipem_event_data[1] = 0xff;
752 			pem.ipem_event_data[2] = 0xff;
753 
754 			if (ipmi_event_platform_message(hdl, &pem) != 0) {
755 				topo_mod_dprintf(mod, "%s: Failed to send "
756 				    "platform event mesg for %s (%s)\n",
757 				    __func__, entity_refs[i], ipmi_errmsg(hdl));
758 				strarr_free(mod, entity_refs, nelems);
759 				topo_mod_ipmi_rele(mod);
760 				return (-1);
761 			}
762 		}
763 	} else {
764 		/*
765 		 * Get the LED mode
766 		 */
767 		for (i = 0; i < nelems; i++) {
768 			if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
769 			    != NULL) {
770 				found_sdr = B_TRUE;
771 				break;
772 			} else
773 				topo_mod_dprintf(mod, "%s: Failed to lookup "
774 				    "SDR for %s (%s)\n", __func__,
775 				    entity_refs[i], ipmi_errmsg(hdl));
776 		}
777 
778 		if (! found_sdr) {
779 			strarr_free(mod, entity_refs, nelems);
780 			topo_mod_ipmi_rele(mod);
781 			return (-1);
782 		}
783 		if (ipmi_sunoem_led_get(hdl, gdl, &mode_in) < 0) {
784 			topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
785 			    "%s (%s)\n", __func__, entity_refs[i],
786 			    ipmi_errmsg(hdl));
787 			strarr_free(mod, entity_refs, nelems);
788 			topo_mod_ipmi_rele(mod);
789 			return (-1);
790 		}
791 		ledmode = mode_in;
792 	}
793 	strarr_free(mod, entity_refs, nelems);
794 	topo_mod_ipmi_rele(mod);
795 
796 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
797 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
798 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
799 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
800 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
801 		nvlist_free(nvl);
802 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
803 	}
804 	*out = nvl;
805 	return (0);
806 }
807 
808 /*
809  * This propmethod is for controlling the present LED on the drive bays for
810  * the X4500 platform.
811  */
812 static int
813 x4500_present_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
814     nvlist_t *in, nvlist_t **out)
815 {
816 	char **entity_refs;
817 	uint_t nelems;
818 	ipmi_sdr_compact_sensor_t *cs = NULL;
819 	ipmi_set_sensor_reading_t sr_out = { 0 };
820 	ipmi_handle_t *hdl;
821 	int err, ret, i;
822 	uint32_t ledmode;
823 	nvlist_t *pargs, *nvl;
824 	boolean_t found_sdr = B_FALSE;
825 
826 	if (vers > TOPO_METH_X4500_MODE_VERSION)
827 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
828 
829 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
830 	    &entity_refs, &nelems, &err) != 0) {
831 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
832 		    "(%s)", topo_strerror(err));
833 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
834 	}
835 
836 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
837 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
838 		strarr_free(mod, entity_refs, nelems);
839 		return (-1);
840 	}
841 	for (i = 0; i < nelems; i++) {
842 		if ((cs = ipmi_sdr_lookup_compact_sensor(hdl, entity_refs[i]))
843 		    != NULL) {
844 			found_sdr = B_TRUE;
845 			break;
846 		} else
847 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
848 			    "(%s)\n", entity_refs[i],
849 			    ipmi_errmsg(hdl));
850 	}
851 
852 	if (! found_sdr) {
853 		strarr_free(mod, entity_refs, nelems);
854 		topo_mod_ipmi_rele(mod);
855 		return (-1);
856 	}
857 
858 	/*
859 	 * Now lookup the propmethod argument list and figure out whether we're
860 	 * doing a get or a set operation, and then do it.
861 	 */
862 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
863 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
864 		/*
865 		 * Set the LED mode
866 		 */
867 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
868 		    &ledmode)) != 0) {
869 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
870 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
871 			strarr_free(mod, entity_refs, nelems);
872 			topo_mod_ipmi_rele(mod);
873 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
874 		}
875 
876 		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
877 		    ledmode ? "ON" : "OFF");
878 
879 		if (ledmode == TOPO_LED_STATE_OFF) {
880 			sr_out.iss_deassert_state = BAY_PRESENT_LED_MASK;
881 			sr_out.iss_deassrt_op = IPMI_SENSOR_OP_SET;
882 		} else if (ledmode == TOPO_LED_STATE_ON) {
883 			sr_out.iss_assert_state = BAY_PRESENT_LED_MASK;
884 			sr_out.iss_assert_op = IPMI_SENSOR_OP_SET;
885 		} else {
886 			topo_mod_dprintf(mod, "%s: Invalid LED mode: "
887 			    "%d\n", __func__, ledmode);
888 			strarr_free(mod, entity_refs, nelems);
889 			topo_mod_ipmi_rele(mod);
890 			return (-1);
891 		}
892 		sr_out.iss_id = cs->is_cs_number;
893 		topo_mod_dprintf(mod, "Setting LED mode (mask=0x%x)\n",
894 		    BAY_PRESENT_LED_MASK);
895 		if (ipmi_set_sensor_reading(hdl, &sr_out) != 0) {
896 			topo_mod_dprintf(mod, "%s: Failed to set "
897 			    "sensor reading for %s (%s)\n", __func__,
898 			    entity_refs[i], ipmi_errmsg(hdl));
899 			strarr_free(mod, entity_refs, nelems);
900 			topo_mod_ipmi_rele(mod);
901 			return (-1);
902 		}
903 	} else {
904 		/*
905 		 * Get the LED mode
906 		 */
907 		ipmi_sensor_reading_t *sr_in;
908 
909 		topo_mod_dprintf(mod, "Getting LED mode\n");
910 		if ((sr_in = ipmi_get_sensor_reading(hdl, cs->is_cs_number))
911 		    == NULL) {
912 			topo_mod_dprintf(mod, "Failed to get sensor reading "
913 			    "for sensor %s (sensor num: %d) (error: %s)\n",
914 			    entity_refs[i], cs->is_cs_number, ipmi_errmsg(hdl));
915 			strarr_free(mod, entity_refs, nelems);
916 			topo_mod_ipmi_rele(mod);
917 			return (-1);
918 		}
919 		if (sr_in->isr_state & (uint16_t)BAY_PRESENT_LED_MASK)
920 			ledmode = TOPO_LED_STATE_ON;
921 		else
922 			ledmode = TOPO_LED_STATE_OFF;
923 	}
924 	strarr_free(mod, entity_refs, nelems);
925 	topo_mod_ipmi_rele(mod);
926 
927 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
928 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
929 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
930 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
931 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
932 		nvlist_free(nvl);
933 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
934 	}
935 	*out = nvl;
936 	return (0);
937 }
938 
939 /*
940  * This is a property method for controlling the chassis service LED on
941  * ILOM 3.x based platforms.
942  */
943 static int
944 chassis_service_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
945     nvlist_t *in, nvlist_t **out)
946 {
947 	char **entity_refs;
948 	uint_t nelems;
949 	ipmi_sdr_generic_locator_t *gdl = NULL;
950 	ipmi_deviceid_t *sp_devid;
951 	ipmi_platform_event_message_t pem;
952 	ipmi_handle_t *hdl;
953 	int err, ret, i;
954 	uint8_t ledmode;
955 	uint32_t mode_in;
956 	nvlist_t *pargs, *nvl;
957 	boolean_t found_sdr = B_FALSE;
958 
959 	if (vers > TOPO_METH_CHASSIS_SERVICE_VERSION)
960 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
961 
962 	/*
963 	 * Get an IPMI handle and then lookup the generic device locator record
964 	 * referenced by the entity_ref prop val
965 	 */
966 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
967 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
968 		return (-1);
969 	}
970 
971 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
972 	    &entity_refs, &nelems, &err) != 0) {
973 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
974 		    "(%s)", topo_strerror(err));
975 		topo_mod_ipmi_rele(mod);
976 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
977 	}
978 
979 	for (i = 0; i < nelems; i++) {
980 		if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
981 		    != NULL) {
982 			found_sdr = B_TRUE;
983 			break;
984 		} else
985 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
986 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
987 	}
988 
989 	if (! found_sdr) {
990 		strarr_free(mod, entity_refs, nelems);
991 		topo_mod_ipmi_rele(mod);
992 		return (-1);
993 	}
994 
995 	/*
996 	 * Now lookup the propmethod argument list and figure out whether we're
997 	 * doing a get or a set operation, and then do it.
998 	 */
999 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1000 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1001 		/*
1002 		 * Set the LED mode
1003 		 */
1004 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1005 		    &mode_in)) != 0) {
1006 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1007 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1008 			strarr_free(mod, entity_refs, nelems);
1009 			topo_mod_ipmi_rele(mod);
1010 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1011 		}
1012 
1013 		/*
1014 		 * Determine which IPMI mechanism to use to set the LED mode
1015 		 * based on whether the SP is running ILOM 2 or later.
1016 		 */
1017 		if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
1018 			topo_mod_dprintf(mod, "%s: GET DEVICEID command failed "
1019 			"(%s)\n", __func__, ipmi_errmsg(hdl));
1020 			strarr_free(mod, entity_refs, nelems);
1021 			topo_mod_ipmi_rele(mod);
1022 			return (-1);
1023 		}
1024 
1025 		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
1026 		    mode_in ? "ON" : "OFF");
1027 
1028 		if (sp_devid->id_firm_major == 2) {
1029 			if (mode_in != TOPO_LED_STATE_OFF &&
1030 			    mode_in != TOPO_LED_STATE_ON) {
1031 				topo_mod_dprintf(mod, "Invalid property value: "
1032 				    "%d\n", mode_in);
1033 				strarr_free(mod, entity_refs, nelems);
1034 				topo_mod_ipmi_rele(mod);
1035 				return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1036 			}
1037 			if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)mode_in)
1038 			    < 0) {
1039 				topo_mod_dprintf(mod, "Failed to set LED mode "
1040 				    "for %s (%s)\n", entity_refs[i],
1041 				    ipmi_errmsg(hdl));
1042 				strarr_free(mod, entity_refs, nelems);
1043 				topo_mod_ipmi_rele(mod);
1044 				return (-1);
1045 			}
1046 		} else {
1047 			pem.ipem_generator = IPMI_SEL_SYSTEM;
1048 			pem.ipem_rev = IPMI_EV_REV15;
1049 			pem.ipem_sensor_type = IPMI_ST_SYSTEM;
1050 			pem.ipem_sensor_num = 0x00;
1051 			pem.ipem_event_type =  IPMI_RT_SPECIFIC;
1052 			if (mode_in == TOPO_LED_STATE_ON)
1053 				pem.ipem_event_dir = 0;
1054 			else
1055 				pem.ipem_event_dir = 1;
1056 
1057 			pem.ipem_event_data[0] = 0x02;
1058 			pem.ipem_event_data[1] = 0xff;
1059 			pem.ipem_event_data[2] = 0xff;
1060 
1061 			topo_mod_dprintf(mod, "Sending platform event\n");
1062 			if (ipmi_event_platform_message(hdl, &pem) != 0) {
1063 				topo_mod_dprintf(mod, "%s: Failed to send "
1064 				    "platform event mesg for sensor 0 (%s)\n",
1065 				    __func__, ipmi_errmsg(hdl));
1066 				strarr_free(mod, entity_refs, nelems);
1067 				topo_mod_ipmi_rele(mod);
1068 				return (-1);
1069 			}
1070 		}
1071 	} else {
1072 		/*
1073 		 * Get the LED mode
1074 		 */
1075 		if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
1076 			topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
1077 			    "%s (%s)\n", __func__, entity_refs[i],
1078 			    ipmi_errmsg(hdl));
1079 			strarr_free(mod, entity_refs, nelems);
1080 			topo_mod_ipmi_rele(mod);
1081 			return (-1);
1082 		}
1083 	}
1084 	strarr_free(mod, entity_refs, nelems);
1085 	topo_mod_ipmi_rele(mod);
1086 
1087 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1088 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1089 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1090 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
1091 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1092 		nvlist_free(nvl);
1093 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1094 	}
1095 	*out = nvl;
1096 	return (0);
1097 }
1098 
1099 static int
1100 make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
1101 {
1102 	int err, ret, i;
1103 	tnode_t *fnode;
1104 	char *ftype = "sensor", facname[MAX_ID_LEN], **entity_refs;
1105 	topo_pgroup_info_t pgi;
1106 	nvlist_t *arg_nvl = NULL;
1107 
1108 	/*
1109 	 * Some platforms have '/' characters in the IPMI entity name, but '/'
1110 	 * has a special meaning for FMRI's so we change them to '.' before
1111 	 * binding the node into the topology.
1112 	 */
1113 	(void) strcpy(facname, sd->sd_entity_ref);
1114 	for (i = 0; facname[i]; i++)
1115 		if (facname[i] == '/')
1116 			facname[i] = '.';
1117 
1118 	if ((fnode = topo_node_facbind(mod, pnode, facname, ftype)) == NULL) {
1119 		topo_mod_dprintf(mod, "Failed to bind facility node: %s\n",
1120 		    facname);
1121 		/* topo errno set */
1122 		return (-1);
1123 	}
1124 
1125 	pgi.tpi_name = TOPO_PGROUP_FACILITY;
1126 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1127 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1128 	pgi.tpi_version = 1;
1129 	if (topo_pgroup_create(fnode, &pgi, &err) != 0) {
1130 		if (err != ETOPO_PROP_DEFD) {
1131 			topo_mod_dprintf(mod,  "pgroups create failure: %s\n",
1132 			    topo_strerror(err));
1133 			topo_node_unbind(fnode);
1134 			return (-1);
1135 		}
1136 	}
1137 	if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) {
1138 		topo_mod_dprintf(mod, "make_fac_node: "
1139 		    "failed to register facility methods");
1140 		topo_node_unbind(fnode);
1141 		return (-1);
1142 	}
1143 	/*
1144 	 * For both threshold and discrete sensors we set up a propmethod for
1145 	 * getting the sensor state and properties to hold the entity ref,
1146 	 * sensor class and sensor type.
1147 	 *
1148 	 * Additionally, for analog sensors we set up a property method for
1149 	 * getting the converted sensor reading and property for the base
1150 	 * unit type
1151 	 */
1152 	if ((entity_refs = topo_mod_alloc(mod, sizeof (char *))) == NULL)
1153 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1154 
1155 	entity_refs[0] = topo_mod_strdup(mod, sd->sd_entity_ref);
1156 
1157 	if (topo_prop_set_string_array(fnode, TOPO_PGROUP_FACILITY,
1158 	    "entity_ref", TOPO_PROP_IMMUTABLE, (const char **)entity_refs, 1,
1159 	    &err) != 0) {
1160 		topo_mod_dprintf(mod, "%s: Failed to set entity_ref property "
1161 		    "on node: %s=%d (%s)\n", __func__, topo_node_name(fnode),
1162 		    topo_node_instance(fnode), topo_strerror(err));
1163 		strarr_free(mod, entity_refs, 1);
1164 		return (-1);
1165 	}
1166 	strarr_free(mod, entity_refs, 1);
1167 
1168 	if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
1169 	    TOPO_PROP_IMMUTABLE, sd->sd_class, &err) != 0) {
1170 		topo_mod_dprintf(mod, "Failed to set %s property on node: "
1171 		    "%s=%d (%s)\n", TOPO_SENSOR_CLASS, topo_node_name(fnode),
1172 		    topo_node_instance(fnode), topo_strerror(err));
1173 		return (-1);
1174 	}
1175 	if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1176 	    TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) {
1177 		topo_mod_dprintf(mod, "Failed to set %s property on node: "
1178 		    "%s=%d (%s)\n", TOPO_FACILITY_TYPE, topo_node_name(fnode),
1179 		    topo_node_instance(fnode), topo_strerror(err));
1180 		return (-1);
1181 	}
1182 	if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) {
1183 		topo_node_unbind(fnode);
1184 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1185 	}
1186 
1187 	if ((ret = nvlist_add_string(arg_nvl, "ipmi_entity", sd->sd_entity_ref))
1188 	    != 0) {
1189 		topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n",
1190 		    strerror(ret));
1191 		nvlist_free(arg_nvl);
1192 		return (-1);
1193 	}
1194 
1195 	if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1196 	    TOPO_SENSOR_STATE, TOPO_TYPE_UINT32, "ipmi_sensor_state", arg_nvl,
1197 	    &err) != 0) {
1198 		topo_mod_dprintf(mod, "Failed to register %s propmeth on fac "
1199 		    "node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode),
1200 		    topo_strerror(err));
1201 		nvlist_free(arg_nvl);
1202 		return (-1);
1203 	}
1204 
1205 	if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0) {
1206 		if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1207 		    TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE,
1208 		    "ipmi_sensor_reading", arg_nvl, &err) != 0) {
1209 			topo_mod_dprintf(mod, "Failed to register %s propmeth "
1210 			    "on fac node %s (%s)\n", TOPO_SENSOR_READING,
1211 			    topo_node_name(fnode), topo_strerror(err));
1212 			nvlist_free(arg_nvl);
1213 			return (-1);
1214 		}
1215 		if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1216 		    TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err)
1217 		    != 0) {
1218 			topo_mod_dprintf(mod, "Failed to set units property on "
1219 			    "node: %s (%s)\n", topo_node_name(fnode),
1220 			    topo_strerror(err));
1221 			nvlist_free(arg_nvl);
1222 			return (-1);
1223 		}
1224 	}
1225 	nvlist_free(arg_nvl);
1226 	return (0);
1227 }
1228 
1229 /* ARGSUSED */
1230 static int
1231 sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data)
1232 {
1233 	uint8_t sensor_entity, sensor_inst;
1234 	int sensor_idlen;
1235 	ipmi_sdr_full_sensor_t *f_sensor = NULL;
1236 	ipmi_sdr_compact_sensor_t *c_sensor = NULL;
1237 	struct sensor_data sd;
1238 	struct entity_info *ei = (struct entity_info *)data;
1239 
1240 	switch (sdr->is_type) {
1241 		case IPMI_SDR_TYPE_FULL_SENSOR:
1242 			f_sensor =
1243 			    (ipmi_sdr_full_sensor_t *)sdr->is_record;
1244 			sensor_entity = f_sensor->is_fs_entity_id;
1245 			sensor_inst = f_sensor->is_fs_entity_instance;
1246 			sensor_idlen = f_sensor->is_fs_idlen;
1247 			(void) strncpy(sd.sd_entity_ref,
1248 			    f_sensor->is_fs_idstring,
1249 			    f_sensor->is_fs_idlen);
1250 			sd.sd_entity_ref[sensor_idlen] = '\0';
1251 			sd.sd_units = f_sensor->is_fs_unit2;
1252 			sd.sd_stype = f_sensor->is_fs_type;
1253 			sd.sd_rtype = f_sensor->is_fs_reading_type;
1254 			break;
1255 		case IPMI_SDR_TYPE_COMPACT_SENSOR:
1256 			c_sensor =
1257 			    (ipmi_sdr_compact_sensor_t *)sdr->is_record;
1258 			sensor_entity = c_sensor->is_cs_entity_id;
1259 			sensor_inst = c_sensor->is_cs_entity_instance;
1260 			sensor_idlen = c_sensor->is_cs_idlen;
1261 			(void) strncpy(sd.sd_entity_ref,
1262 			    c_sensor->is_cs_idstring,
1263 			    sensor_idlen);
1264 			sd.sd_entity_ref[sensor_idlen] = '\0';
1265 			sd.sd_units = c_sensor->is_cs_unit2;
1266 			sd.sd_stype = c_sensor->is_cs_type;
1267 			sd.sd_rtype = c_sensor->is_cs_reading_type;
1268 			break;
1269 		default:
1270 			return (0);
1271 	}
1272 	if (sd.sd_rtype == IPMI_RT_THRESHOLD)
1273 		sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD;
1274 	else
1275 		sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE;
1276 
1277 	/*
1278 	 * We offset the threshold and generic sensor reading types by 0x100
1279 	 */
1280 	if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc)
1281 		sd.sd_stype = sd.sd_rtype + 0x100;
1282 
1283 	if ((sensor_entity == ei->ei_id) && (sensor_inst == ei->ei_inst))
1284 		if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd) != 0) {
1285 			topo_mod_dprintf(ei->ei_mod, "Failed to create sensor "
1286 			    "node for %s\n", sd.sd_entity_ref);
1287 			if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP)
1288 				return (-1);
1289 		}
1290 	return (0);
1291 }
1292 
1293 /* ARGSUSED */
1294 static int
1295 ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1296     nvlist_t *in, nvlist_t **out)
1297 {
1298 	char **entity_refs;
1299 	int err;
1300 	uint_t nelems;
1301 	struct entity_info ei;
1302 	ipmi_sdr_t *ref_sdr;
1303 	ipmi_handle_t *hdl;
1304 	ipmi_sdr_full_sensor_t *fsensor;
1305 	ipmi_sdr_compact_sensor_t *csensor;
1306 	ipmi_sdr_fru_locator_t *floc;
1307 	ipmi_sdr_generic_locator_t *gloc;
1308 	boolean_t found_sdr = B_FALSE;
1309 
1310 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1311 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1312 		return (-1);
1313 	}
1314 
1315 	/*
1316 	 * Use the entity ref to lookup the SDR, which will have the entity ID
1317 	 * and instance.
1318 	 */
1319 	if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI,
1320 	    "entity_ref", &entity_refs, &nelems, &err) != 0) {
1321 		topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
1322 		    "property on %s=%d (%s)\n", __func__, topo_node_name(node),
1323 		    topo_node_instance(node), topo_strerror(err));
1324 		topo_mod_ipmi_rele(mod);
1325 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1326 	}
1327 
1328 	for (int i = 0; i < nelems; i++) {
1329 		if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_refs[i])) != NULL) {
1330 			found_sdr = B_TRUE;
1331 			break;
1332 		} else
1333 			topo_mod_dprintf(mod, "%s: Failed to lookup SDR for %s "
1334 			    "(%s)\n", __func__, entity_refs[i],
1335 			    ipmi_errmsg(hdl));
1336 	}
1337 	strarr_free(mod, entity_refs, nelems);
1338 	if (! found_sdr) {
1339 		topo_mod_ipmi_rele(mod);
1340 		return (-1);
1341 	}
1342 
1343 	switch (ref_sdr->is_type) {
1344 		case IPMI_SDR_TYPE_FULL_SENSOR:
1345 			fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record;
1346 			ei.ei_id = fsensor->is_fs_entity_id;
1347 			ei.ei_inst = fsensor->is_fs_entity_instance;
1348 			break;
1349 		case IPMI_SDR_TYPE_COMPACT_SENSOR:
1350 			csensor
1351 			    = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record;
1352 			ei.ei_id = csensor->is_cs_entity_id;
1353 			ei.ei_inst = csensor->is_cs_entity_instance;
1354 			break;
1355 		case IPMI_SDR_TYPE_FRU_LOCATOR:
1356 			floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record;
1357 			ei.ei_id = floc->is_fl_entity;
1358 			ei.ei_inst = floc->is_fl_instance;
1359 			break;
1360 		case IPMI_SDR_TYPE_GENERIC_LOCATOR:
1361 			gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record;
1362 			ei.ei_id = gloc->is_gl_entity;
1363 			ei.ei_inst = gloc->is_gl_instance;
1364 			break;
1365 		default:
1366 			topo_mod_dprintf(mod, "Failed to determine entity id "
1367 			    "and instance\n", ipmi_errmsg(hdl));
1368 			topo_mod_ipmi_rele(mod);
1369 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1370 	}
1371 	ei.ei_node = node;
1372 	ei.ei_mod = mod;
1373 
1374 	/*
1375 	 * Now iterate through all of the full and compact sensor data records
1376 	 * and create a sensor facility node for each record that matches our
1377 	 * entity ID and instance
1378 	 */
1379 	if (ipmi_sdr_iter(hdl, sdr_callback, &ei) != 0) {
1380 		topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n");
1381 		topo_mod_ipmi_rele(mod);
1382 		return (-1);
1383 	}
1384 
1385 	topo_mod_ipmi_rele(mod);
1386 
1387 	return (0);
1388 }
1389 
1390 static int
1391 ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1392     nvlist_t *in, nvlist_t **out)
1393 {
1394 	char **fmtarr, **entity_refs, buf[BUFSZ];
1395 	tnode_t *refnode;
1396 	uint_t nelems;
1397 	int ret, inst1, inst2;
1398 	uint32_t offset, nparams;
1399 	nvlist_t *args, *nvl;
1400 
1401 	if (vers > TOPO_METH_IPMI_ENTITY_VERSION)
1402 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1403 
1404 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1405 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1406 		    strerror(ret));
1407 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1408 	}
1409 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1410 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1411 		    strerror(ret));
1412 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1413 	}
1414 	if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) {
1415 		topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n",
1416 		    strerror(ret));
1417 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1418 	}
1419 	if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1420 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1421 		    strerror(errno));
1422 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1423 	}
1424 
1425 	if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1426 	    == NULL)
1427 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1428 
1429 	if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1430 		refnode = topo_node_parent(node);
1431 	else
1432 		refnode = node;
1433 
1434 	for (int i = 0; i < nelems; i++) {
1435 		switch (nparams) {
1436 		case 1:
1437 			/* LINTED: E_SEC_PRINTF_VAR_FMT */
1438 			(void) snprintf(buf, BUFSZ, fmtarr[i],
1439 			    (topo_node_instance(refnode) + offset));
1440 			break;
1441 		case 2:
1442 			inst1 = topo_node_instance(topo_node_parent(refnode))
1443 			    + offset;
1444 			inst2 = topo_node_instance(refnode) + offset;
1445 			/* LINTED: E_SEC_PRINTF_VAR_FMT */
1446 			(void) snprintf(buf, BUFSZ, fmtarr[i], inst1, inst2);
1447 			break;
1448 		default:
1449 			topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n",
1450 			    nparams);
1451 			strarr_free(mod, entity_refs, nelems);
1452 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1453 		}
1454 		entity_refs[i] = topo_mod_strdup(mod, buf);
1455 	}
1456 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1457 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1458 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1459 	    TOPO_TYPE_STRING_ARRAY) != 0 ||
1460 	    nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs,
1461 	    nelems) != 0) {
1462 
1463 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1464 		strarr_free(mod, entity_refs, nelems);
1465 		nvlist_free(nvl);
1466 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1467 	}
1468 	strarr_free(mod, entity_refs, nelems);
1469 	*out = nvl;
1470 
1471 	return (0);
1472 }
1473 
1474 /* ARGSUSED */
1475 static int
1476 dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1477     nvlist_t *in, nvlist_t **out)
1478 {
1479 	char **fmtarr, **entity_refs, buf[BUFSZ];
1480 	tnode_t *chip, *dimm;
1481 	int ret;
1482 	uint_t nelems;
1483 	uint32_t offset;
1484 	nvlist_t *args, *nvl;
1485 
1486 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1487 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1488 		    strerror(ret));
1489 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1490 	}
1491 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1492 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1493 		    strerror(ret));
1494 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1495 	}
1496 	if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1497 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1498 		    strerror(errno));
1499 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1500 	}
1501 
1502 	if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1503 	    == NULL)
1504 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1505 
1506 	if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1507 		dimm = topo_node_parent(node);
1508 	else
1509 		dimm = node;
1510 
1511 	chip = topo_node_parent(topo_node_parent(dimm));
1512 
1513 	for (int i = 0; i < nelems; i++) {
1514 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
1515 		(void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
1516 		    (topo_node_instance(dimm) + offset));
1517 		entity_refs[i] = topo_mod_strdup(mod, buf);
1518 	}
1519 
1520 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1521 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1522 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1523 	    TOPO_TYPE_STRING_ARRAY) != 0 ||
1524 	    nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
1525 	    != 0) {
1526 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1527 		strarr_free(mod, entity_refs, nelems);
1528 		nvlist_free(nvl);
1529 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1530 	}
1531 	strarr_free(mod, entity_refs, nelems);
1532 	*out = nvl;
1533 
1534 	return (0);
1535 }
1536 
1537 /* ARGSUSED */
1538 static int
1539 cs_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1540     nvlist_t *in, nvlist_t **out)
1541 {
1542 	char **fmtarr, **entity_refs, buf[BUFSZ];
1543 	tnode_t *chip, *chan, *cs;
1544 	int ret, dimm_num;
1545 	uint_t nelems;
1546 	uint32_t offset;
1547 	nvlist_t *args, *nvl;
1548 
1549 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1550 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1551 		    strerror(ret));
1552 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1553 	}
1554 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1555 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1556 		    strerror(ret));
1557 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1558 	}
1559 	if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1560 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1561 		    strerror(errno));
1562 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1563 	}
1564 
1565 	if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1566 	    == NULL)
1567 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1568 
1569 	if (topo_node_flags(node) & TOPO_NODE_FACILITY) {
1570 		cs = topo_node_parent(node);
1571 		chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
1572 		chan = topo_node_parent(cs);
1573 
1574 		dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
1575 		    + topo_node_instance(cs) + offset;
1576 	} else {
1577 		cs = node;
1578 		chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
1579 		chan = topo_node_parent(cs);
1580 
1581 		dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
1582 		    + topo_node_instance(chan) + offset;
1583 	}
1584 
1585 	for (int i = 0; i < nelems; i++) {
1586 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
1587 		(void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
1588 		    dimm_num);
1589 		entity_refs[i] = topo_mod_strdup(mod, buf);
1590 	}
1591 
1592 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1593 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1594 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1595 	    TOPO_TYPE_STRING_ARRAY) != 0 ||
1596 	    nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
1597 	    != 0) {
1598 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1599 		strarr_free(mod, entity_refs, nelems);
1600 		nvlist_free(nvl);
1601 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1602 	}
1603 	strarr_free(mod, entity_refs, nelems);
1604 	*out = nvl;
1605 
1606 	return (0);
1607 }
1608 
1609 /*ARGSUSED*/
1610 static int
1611 fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
1612     topo_instance_t min, topo_instance_t max, void *arg, void *unused)
1613 {
1614 	topo_pgroup_info_t pgi;
1615 	int err;
1616 
1617 	if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) {
1618 		pgi.tpi_name = TOPO_PGROUP_IPMI;
1619 		pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1620 		pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1621 		pgi.tpi_version = 1;
1622 		if (topo_pgroup_create(rnode, &pgi, &err) != 0) {
1623 			if (err != ETOPO_PROP_DEFD) {
1624 				topo_mod_dprintf(mod,
1625 				    "pgroups create failure: %s\n",
1626 				    topo_strerror(err));
1627 				return (-1);
1628 			}
1629 		}
1630 		if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) {
1631 			topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
1632 			    "topo_method_register() failed: %s",
1633 			    topo_mod_errmsg(mod));
1634 			return (-1);
1635 		}
1636 	} else {
1637 		if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) {
1638 			topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
1639 			    "topo_method_register() failed: %s",
1640 			    topo_mod_errmsg(mod));
1641 			return (-1);
1642 		}
1643 	}
1644 	return (0);
1645 }
1646