1825ba0f2Srobj /*
2825ba0f2Srobj  * CDDL HEADER START
3825ba0f2Srobj  *
4825ba0f2Srobj  * The contents of this file are subject to the terms of the
5825ba0f2Srobj  * Common Development and Distribution License (the "License").
6825ba0f2Srobj  * You may not use this file except in compliance with the License.
7825ba0f2Srobj  *
8825ba0f2Srobj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9825ba0f2Srobj  * or http://www.opensolaris.org/os/licensing.
10825ba0f2Srobj  * See the License for the specific language governing permissions
11825ba0f2Srobj  * and limitations under the License.
12825ba0f2Srobj  *
13825ba0f2Srobj  * When distributing Covered Code, include this CDDL HEADER in each
14825ba0f2Srobj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15825ba0f2Srobj  * If applicable, add the following below this CDDL HEADER, with the
16825ba0f2Srobj  * fields enclosed by brackets "[]" replaced with your own identifying
17825ba0f2Srobj  * information: Portions Copyright [yyyy] [name of copyright owner]
18825ba0f2Srobj  *
19825ba0f2Srobj  * CDDL HEADER END
20825ba0f2Srobj  */
21825ba0f2Srobj /*
22e5dcf7beSRobert Johnston  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23825ba0f2Srobj  * Use is subject to license terms.
24825ba0f2Srobj  */
258f022dd6SRob Johnston /*
26e2336878SRob Johnston  * Copyright 2019 Joyent, Inc.
2722e991d5SYuri Pankov  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
288f022dd6SRob Johnston  */
29825ba0f2Srobj #include <unistd.h>
30825ba0f2Srobj #include <stdio.h>
31825ba0f2Srobj #include <stdlib.h>
32825ba0f2Srobj #include <string.h>
33825ba0f2Srobj #include <strings.h>
34825ba0f2Srobj #include <limits.h>
35825ba0f2Srobj #include <alloca.h>
36825ba0f2Srobj #include <errno.h>
37825ba0f2Srobj #include <libnvpair.h>
38825ba0f2Srobj #include <sys/types.h>
39825ba0f2Srobj #include <sys/param.h>
40825ba0f2Srobj #include <sys/fm/protocol.h>
41825ba0f2Srobj #include <fm/libtopo.h>
42825ba0f2Srobj #include <fm/topo_mod.h>
43825ba0f2Srobj #include <libipmi.h>
44825ba0f2Srobj 
45825ba0f2Srobj #define	BUFSZ	128
46825ba0f2Srobj 
4788045cffSRobert Johnston #define	BAY_PRESENT_LED_MASK	0x01
48825ba0f2Srobj 
49825ba0f2Srobj /*
50825ba0f2Srobj  * The largest possible SDR ID length is 2^5+1
51825ba0f2Srobj  */
52825ba0f2Srobj #define	MAX_ID_LEN	33
53825ba0f2Srobj 
54525b85dbSEric Schrock #define	TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION	0
55825ba0f2Srobj #define	TOPO_METH_IPMI_READING_VERSION		0
56825ba0f2Srobj #define	TOPO_METH_IPMI_STATE_VERSION		0
57825ba0f2Srobj #define	TOPO_METH_IPMI_MODE_VERSION		0
5888045cffSRobert Johnston #define	TOPO_METH_X4500_MODE_VERSION		0
5988045cffSRobert Johnston #define	TOPO_METH_BAY_LOCATE_VERSION		0
6088045cffSRobert Johnston #define	TOPO_METH_BAY_MODE_VERSION		0
6188045cffSRobert Johnston #define	TOPO_METH_CHASSIS_SERVICE_VERSION	0
62825ba0f2Srobj #define	TOPO_METH_IPMI_ENTITY_VERSION		0
63825ba0f2Srobj #define	TOPO_METH_DIMM_IPMI_ENTITY_VERSION	0
648f022dd6SRob Johnston #define	TOPO_METH_CHASSIS_IDENT_VERSION		0
65825ba0f2Srobj 
66825ba0f2Srobj static int fac_prov_ipmi_enum(topo_mod_t *, tnode_t *, const char *,
67825ba0f2Srobj     topo_instance_t, topo_instance_t, void *, void *);
68825ba0f2Srobj 
69825ba0f2Srobj /*
70825ba0f2Srobj  * IPMI facility provider methods
71825ba0f2Srobj  */
72825ba0f2Srobj static int ipmi_sensor_enum(topo_mod_t *, tnode_t *, topo_version_t,
73825ba0f2Srobj     nvlist_t *, nvlist_t **);
74825ba0f2Srobj static int ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
75825ba0f2Srobj     nvlist_t **);
76825ba0f2Srobj static int dimm_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
77825ba0f2Srobj     nvlist_t **);
7888045cffSRobert Johnston static int cs_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
7988045cffSRobert Johnston     nvlist_t **);
80525b85dbSEric Schrock static int ipmi_platform_message(topo_mod_t *, tnode_t *, topo_version_t,
81525b85dbSEric Schrock     nvlist_t *, nvlist_t **);
82825ba0f2Srobj static int ipmi_sensor_reading(topo_mod_t *, tnode_t *, topo_version_t,
83825ba0f2Srobj     nvlist_t *, nvlist_t **);
84825ba0f2Srobj static int ipmi_sensor_state(topo_mod_t *, tnode_t *, topo_version_t,
85825ba0f2Srobj     nvlist_t *, nvlist_t **);
86825ba0f2Srobj static int ipmi_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
87825ba0f2Srobj     nvlist_t *, nvlist_t **);
8888045cffSRobert Johnston static int bay_locate_mode(topo_mod_t *, tnode_t *, topo_version_t,
8988045cffSRobert Johnston     nvlist_t *, nvlist_t **);
9088045cffSRobert Johnston static int x4500_present_mode(topo_mod_t *, tnode_t *, topo_version_t,
9188045cffSRobert Johnston     nvlist_t *, nvlist_t **);
9288045cffSRobert Johnston static int bay_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
93825ba0f2Srobj     nvlist_t *, nvlist_t **);
9488045cffSRobert Johnston static int chassis_service_mode(topo_mod_t *, tnode_t *, topo_version_t,
95825ba0f2Srobj     nvlist_t *, nvlist_t **);
968f022dd6SRob Johnston static int chassis_ident_mode(topo_mod_t *, tnode_t *, topo_version_t,
978f022dd6SRob Johnston     nvlist_t *, nvlist_t **);
98825ba0f2Srobj 
99825ba0f2Srobj const topo_modops_t ipmi_ops = { fac_prov_ipmi_enum, NULL };
100825ba0f2Srobj 
101825ba0f2Srobj const topo_modinfo_t ipmi_info =
102825ba0f2Srobj 	{ "IPMI facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION,
103825ba0f2Srobj 	&ipmi_ops };
104825ba0f2Srobj 
105825ba0f2Srobj static const topo_method_t ipmi_node_methods[] = {
106825ba0f2Srobj 	{ TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
107825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, ipmi_sensor_enum },
108825ba0f2Srobj 	{ TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
109825ba0f2Srobj 	    TOPO_METH_IPMI_ENTITY_VERSION,
110825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, ipmi_entity },
111825ba0f2Srobj 	{ "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
112825ba0f2Srobj 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
113825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
11488045cffSRobert Johnston 	{ "cs_ipmi_entity", TOPO_PROP_METH_DESC,
11588045cffSRobert Johnston 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
11688045cffSRobert Johnston 	    TOPO_STABILITY_INTERNAL, cs_ipmi_entity },
117ea30102cSRob Johnston 	{ TOPO_METH_SENSOR_FAILURE, TOPO_METH_SENSOR_FAILURE_DESC,
118ea30102cSRob Johnston 	    TOPO_METH_SENSOR_FAILURE_VERSION, TOPO_STABILITY_INTERNAL,
119ea30102cSRob Johnston 	    topo_method_sensor_failure },
120825ba0f2Srobj 	{ NULL }
121825ba0f2Srobj };
122825ba0f2Srobj 
123825ba0f2Srobj static const topo_method_t ipmi_fac_methods[] = {
124525b85dbSEric Schrock 	{ "ipmi_platform_message", TOPO_PROP_METH_DESC,
125525b85dbSEric Schrock 	    TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION,
126525b85dbSEric Schrock 	    TOPO_STABILITY_INTERNAL, ipmi_platform_message },
127825ba0f2Srobj 	{ "ipmi_sensor_reading", TOPO_PROP_METH_DESC,
128825ba0f2Srobj 	    TOPO_METH_IPMI_READING_VERSION,
129825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, ipmi_sensor_reading },
130825ba0f2Srobj 	{ "ipmi_sensor_state", TOPO_PROP_METH_DESC,
131825ba0f2Srobj 	    TOPO_METH_IPMI_STATE_VERSION,
132825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, ipmi_sensor_state },
133825ba0f2Srobj 	{ "ipmi_indicator_mode", TOPO_PROP_METH_DESC,
134825ba0f2Srobj 	    TOPO_METH_IPMI_MODE_VERSION,
135825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, ipmi_indicator_mode },
13688045cffSRobert Johnston 	{ "bay_locate_mode", TOPO_PROP_METH_DESC,
13788045cffSRobert Johnston 	    TOPO_METH_BAY_LOCATE_VERSION,
13888045cffSRobert Johnston 	    TOPO_STABILITY_INTERNAL, bay_locate_mode },
13988045cffSRobert Johnston 	{ "bay_indicator_mode", TOPO_PROP_METH_DESC,
14088045cffSRobert Johnston 	    TOPO_METH_BAY_MODE_VERSION,
14188045cffSRobert Johnston 	    TOPO_STABILITY_INTERNAL, bay_indicator_mode },
14288045cffSRobert Johnston 	{ "chassis_service_mode", TOPO_PROP_METH_DESC,
14388045cffSRobert Johnston 	    TOPO_METH_CHASSIS_SERVICE_VERSION,
14488045cffSRobert Johnston 	    TOPO_STABILITY_INTERNAL, chassis_service_mode },
1458f022dd6SRob Johnston 	{ "chassis_ident_mode", TOPO_PROP_METH_DESC,
1468f022dd6SRob Johnston 	    TOPO_METH_CHASSIS_SERVICE_VERSION,
1478f022dd6SRob Johnston 	    TOPO_STABILITY_INTERNAL, chassis_ident_mode },
14888045cffSRobert Johnston 	{ "x4500_present_mode", TOPO_PROP_METH_DESC,
14988045cffSRobert Johnston 	    TOPO_METH_CHASSIS_SERVICE_VERSION,
15088045cffSRobert Johnston 	    TOPO_STABILITY_INTERNAL, x4500_present_mode },
151825ba0f2Srobj 	{ TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
152825ba0f2Srobj 	    TOPO_METH_IPMI_ENTITY_VERSION,
153825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, ipmi_entity },
154825ba0f2Srobj 	{ "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
155825ba0f2Srobj 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
156825ba0f2Srobj 	    TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
15788045cffSRobert Johnston 	{ "cs_ipmi_entity", TOPO_PROP_METH_DESC,
15888045cffSRobert Johnston 	    TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
15988045cffSRobert Johnston 	    TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
160825ba0f2Srobj 	{ NULL }
161825ba0f2Srobj };
162825ba0f2Srobj 
163825ba0f2Srobj struct entity_info {
164825ba0f2Srobj 	uint32_t ei_id;
165825ba0f2Srobj 	uint32_t ei_inst;
166825ba0f2Srobj 	topo_mod_t *ei_mod;
167825ba0f2Srobj 	tnode_t *ei_node;
1688f022dd6SRob Johnston 	char **ei_list;
1698f022dd6SRob Johnston 	uint_t ei_listsz;
170825ba0f2Srobj };
171825ba0f2Srobj 
172825ba0f2Srobj struct sensor_data {
173825ba0f2Srobj 	char sd_entity_ref[MAX_ID_LEN];
174825ba0f2Srobj 	uint8_t sd_units;
175825ba0f2Srobj 	uint32_t sd_stype;
176825ba0f2Srobj 	uint32_t sd_rtype;
177825ba0f2Srobj 	char *sd_class;
178208e1562SRob Johnston 	ipmi_sdr_full_sensor_t *sd_fs_sdr;
179825ba0f2Srobj };
180825ba0f2Srobj 
181825ba0f2Srobj /*ARGSUSED*/
182825ba0f2Srobj int
_topo_init(topo_mod_t * mod,topo_version_t version)183825ba0f2Srobj _topo_init(topo_mod_t *mod, topo_version_t version)
184825ba0f2Srobj {
185825ba0f2Srobj 	if (getenv("TOPOFACIPMIDEBUG") != NULL)
186825ba0f2Srobj 		topo_mod_setdebug(mod);
187825ba0f2Srobj 
188825ba0f2Srobj 	return (topo_mod_register(mod, &ipmi_info, TOPO_VERSION));
189825ba0f2Srobj }
190825ba0f2Srobj 
191825ba0f2Srobj void
_topo_fini(topo_mod_t * mod)192825ba0f2Srobj _topo_fini(topo_mod_t *mod)
193825ba0f2Srobj {
194825ba0f2Srobj 	topo_mod_unregister(mod);
195825ba0f2Srobj }
196825ba0f2Srobj 
197525b85dbSEric Schrock /*
198525b85dbSEric Schrock  * Some platforms (most notably G1/2N) use the 'platform event message' command
199525b85dbSEric Schrock  * to manipulate disk fault LEDs over IPMI, but uses the standard sensor
200525b85dbSEric Schrock  * reading to read the value.  This method implements this alternative
201525b85dbSEric Schrock  * interface for these platforms.
202525b85dbSEric Schrock  */
203525b85dbSEric Schrock /*ARGSUSED*/
204525b85dbSEric Schrock static int
ipmi_platform_message(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)205525b85dbSEric Schrock ipmi_platform_message(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
206525b85dbSEric Schrock     nvlist_t *in, nvlist_t **out)
207525b85dbSEric Schrock {
208525b85dbSEric Schrock 	char *entity_ref;
209525b85dbSEric Schrock 	ipmi_sdr_compact_sensor_t *csp;
210525b85dbSEric Schrock 	ipmi_handle_t *hdl;
211525b85dbSEric Schrock 	int err, ret;
212525b85dbSEric Schrock 	uint32_t mode;
213525b85dbSEric Schrock 	nvlist_t *pargs, *nvl;
214525b85dbSEric Schrock 	ipmi_platform_event_message_t pem;
215525b85dbSEric Schrock 	ipmi_sensor_reading_t *reading;
216525b85dbSEric Schrock 
217525b85dbSEric Schrock 	if (vers > TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION)
218525b85dbSEric Schrock 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
219525b85dbSEric Schrock 
220525b85dbSEric Schrock 	/*
221525b85dbSEric Schrock 	 * Get an IPMI handle and then lookup the generic device locator sensor
222525b85dbSEric Schrock 	 * data record referenced by the entity_ref prop val
223525b85dbSEric Schrock 	 */
224525b85dbSEric Schrock 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
225525b85dbSEric Schrock 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
226525b85dbSEric Schrock 		return (-1);
227525b85dbSEric Schrock 	}
228525b85dbSEric Schrock 
229525b85dbSEric Schrock 	if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref",
230525b85dbSEric Schrock 	    &entity_ref, &err) != 0) {
231525b85dbSEric Schrock 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
232525b85dbSEric Schrock 		    "(%s)", topo_strerror(err));
233525b85dbSEric Schrock 		topo_mod_ipmi_rele(mod);
234525b85dbSEric Schrock 		return (-1);
235525b85dbSEric Schrock 	}
236525b85dbSEric Schrock 
237525b85dbSEric Schrock 	if ((csp = ipmi_sdr_lookup_compact_sensor(hdl, entity_ref)) == NULL) {
238525b85dbSEric Schrock 		topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n",
239525b85dbSEric Schrock 		    entity_ref, ipmi_errmsg(hdl));
240525b85dbSEric Schrock 		topo_mod_strfree(mod, entity_ref);
241525b85dbSEric Schrock 		topo_mod_ipmi_rele(mod);
242525b85dbSEric Schrock 		return (-1);
243525b85dbSEric Schrock 	}
244525b85dbSEric Schrock 
245525b85dbSEric Schrock 	/*
246525b85dbSEric Schrock 	 * Now look for a private argument list to figure out whether we're
247525b85dbSEric Schrock 	 * doing a get or a set operation, and then do it.
248525b85dbSEric Schrock 	 */
249525b85dbSEric Schrock 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
250525b85dbSEric Schrock 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
251525b85dbSEric Schrock 		/*
252525b85dbSEric Schrock 		 * Set the LED mode
253525b85dbSEric Schrock 		 */
254525b85dbSEric Schrock 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
255525b85dbSEric Schrock 		    &mode)) != 0) {
256525b85dbSEric Schrock 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
257525b85dbSEric Schrock 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
258525b85dbSEric Schrock 			topo_mod_strfree(mod, entity_ref);
259525b85dbSEric Schrock 			(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
260525b85dbSEric Schrock 			topo_mod_ipmi_rele(mod);
261525b85dbSEric Schrock 			return (-1);
262525b85dbSEric Schrock 		}
263525b85dbSEric Schrock 
264525b85dbSEric Schrock 		if (mode != TOPO_LED_STATE_OFF &&
265525b85dbSEric Schrock 		    mode != TOPO_LED_STATE_ON) {
266525b85dbSEric Schrock 			topo_mod_dprintf(mod, "Invalid property value: %d\n",
267525b85dbSEric Schrock 			    mode);
268525b85dbSEric Schrock 			topo_mod_strfree(mod, entity_ref);
269525b85dbSEric Schrock 			(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
270525b85dbSEric Schrock 			topo_mod_ipmi_rele(mod);
271525b85dbSEric Schrock 			return (-1);
272525b85dbSEric Schrock 		}
273525b85dbSEric Schrock 
274525b85dbSEric Schrock 		pem.ipem_sensor_type = csp->is_cs_type;
275525b85dbSEric Schrock 		pem.ipem_sensor_num = csp->is_cs_number;
276525b85dbSEric Schrock 		pem.ipem_event_type = csp->is_cs_reading_type;
277525b85dbSEric Schrock 
278525b85dbSEric Schrock 		/*
279525b85dbSEric Schrock 		 * The spec states that any values between 0x20 and 0x29 are
280525b85dbSEric Schrock 		 * legitimate for "system software".  However, some versions of
281989f2807SJerry Jelinek 		 * Sun's ILOM rejects messages over /dev/ipmi0 with a generator
282525b85dbSEric Schrock 		 * of 0x20, so we use 0x21 instead.
283525b85dbSEric Schrock 		 */
284525b85dbSEric Schrock 		pem.ipem_generator = 0x21;
285525b85dbSEric Schrock 		pem.ipem_event_dir = 0;
286525b85dbSEric Schrock 		pem.ipem_rev = 0x04;
287525b85dbSEric Schrock 		if (mode == TOPO_LED_STATE_ON)
288525b85dbSEric Schrock 			pem.ipem_event_data[0] = 1;
289525b85dbSEric Schrock 		else
290525b85dbSEric Schrock 			pem.ipem_event_data[0] = 0;
291525b85dbSEric Schrock 		pem.ipem_event_data[1] = 0xff;
292525b85dbSEric Schrock 		pem.ipem_event_data[2] = 0xff;
293525b85dbSEric Schrock 
294525b85dbSEric Schrock 		if (ipmi_event_platform_message(hdl, &pem) < 0) {
295525b85dbSEric Schrock 			topo_mod_dprintf(mod, "Failed to set LED mode for %s "
296525b85dbSEric Schrock 			    "(%s)\n", entity_ref, ipmi_errmsg(hdl));
297525b85dbSEric Schrock 			topo_mod_strfree(mod, entity_ref);
298525b85dbSEric Schrock 			topo_mod_ipmi_rele(mod);
299525b85dbSEric Schrock 			return (-1);
300525b85dbSEric Schrock 		}
301525b85dbSEric Schrock 	} else {
302525b85dbSEric Schrock 		/*
303525b85dbSEric Schrock 		 * Get the LED mode
304525b85dbSEric Schrock 		 */
305525b85dbSEric Schrock 		if ((reading = ipmi_get_sensor_reading(hdl, csp->is_cs_number))
306525b85dbSEric Schrock 		    == NULL) {
307525b85dbSEric Schrock 			topo_mod_dprintf(mod, "Failed to get sensor reading "
308525b85dbSEric Schrock 			    "for sensor %s: %s\n", entity_ref,
309525b85dbSEric Schrock 			    ipmi_errmsg(hdl));
310525b85dbSEric Schrock 			topo_mod_strfree(mod, entity_ref);
311525b85dbSEric Schrock 			topo_mod_ipmi_rele(mod);
312525b85dbSEric Schrock 			return (-1);
313525b85dbSEric Schrock 		}
314525b85dbSEric Schrock 
315525b85dbSEric Schrock 		if (reading->isr_state &
316525b85dbSEric Schrock 		    TOPO_SENSOR_STATE_GENERIC_STATE_ASSERTED)
317525b85dbSEric Schrock 			mode = TOPO_LED_STATE_ON;
318525b85dbSEric Schrock 		else
319525b85dbSEric Schrock 			mode = TOPO_LED_STATE_OFF;
320525b85dbSEric Schrock 	}
321525b85dbSEric Schrock 	topo_mod_strfree(mod, entity_ref);
322525b85dbSEric Schrock 
323525b85dbSEric Schrock 	topo_mod_ipmi_rele(mod);
324525b85dbSEric Schrock 
325525b85dbSEric Schrock 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
326525b85dbSEric Schrock 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
327525b85dbSEric Schrock 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
328525b85dbSEric Schrock 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, mode) != 0) {
329525b85dbSEric Schrock 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
330525b85dbSEric Schrock 		nvlist_free(nvl);
331525b85dbSEric Schrock 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
332525b85dbSEric Schrock 	}
333525b85dbSEric Schrock 	*out = nvl;
334525b85dbSEric Schrock 
335525b85dbSEric Schrock 	return (0);
336525b85dbSEric Schrock }
337525b85dbSEric Schrock 
338825ba0f2Srobj /*ARGSUSED*/
339825ba0f2Srobj static int
ipmi_sensor_state(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)340825ba0f2Srobj ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
341825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
342825ba0f2Srobj {
343881aaecdSRob Johnston 	char **entity_refs, *sensor_class;
34488045cffSRobert Johnston 	uint_t nelems;
345825ba0f2Srobj 	ipmi_sdr_t *sdr = NULL;
346825ba0f2Srobj 	ipmi_sensor_reading_t *reading;
347825ba0f2Srobj 	ipmi_handle_t *hdl;
34888045cffSRobert Johnston 	int err, i;
349825ba0f2Srobj 	uint8_t sensor_num;
350881aaecdSRob Johnston 	uint32_t e_id, e_inst, state;
351825ba0f2Srobj 	ipmi_sdr_full_sensor_t *fsensor;
352825ba0f2Srobj 	ipmi_sdr_compact_sensor_t *csensor;
353825ba0f2Srobj 	nvlist_t *nvl;
35488045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
355ea30102cSRob Johnston 	tnode_t *pnode;
356825ba0f2Srobj 
357825ba0f2Srobj 	if (vers > TOPO_METH_IPMI_STATE_VERSION)
358825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
359825ba0f2Srobj 
36088045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
36188045cffSRobert Johnston 	    &entity_refs, &nelems, &err) != 0) {
36288045cffSRobert Johnston 		topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
36388045cffSRobert Johnston 		    "property (%s)", __func__, topo_strerror(err));
364825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
365825ba0f2Srobj 	}
366825ba0f2Srobj 
3670b1b4412SEric Schrock 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
368825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
369e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
370825ba0f2Srobj 		return (-1);
371825ba0f2Srobj 	}
372825ba0f2Srobj 
373ea30102cSRob Johnston 	pnode = topo_node_parent(node);
374ea30102cSRob Johnston 	if (topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
375ea30102cSRob Johnston 	    TOPO_PROP_IPMI_ENTITY_ID, &e_id, &err) != 0 ||
376ea30102cSRob Johnston 	    topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
377ea30102cSRob Johnston 	    TOPO_PROP_IPMI_ENTITY_INST, &e_inst, &err) != 0) {
378ea30102cSRob Johnston 		e_id = IPMI_ET_UNSPECIFIED;
379ea30102cSRob Johnston 		e_inst = 0;
380ea30102cSRob Johnston 	}
381ea30102cSRob Johnston 
38288045cffSRobert Johnston 	for (i = 0; i < nelems; i++) {
383ea30102cSRob Johnston 		if ((sdr = ipmi_sdr_lookup_precise(hdl, entity_refs[i],
384ea30102cSRob Johnston 		    (uint8_t)e_id, (uint8_t)e_inst)) != NULL) {
38588045cffSRobert Johnston 			found_sdr = B_TRUE;
38688045cffSRobert Johnston 			break;
38788045cffSRobert Johnston 		} else
38888045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
38988045cffSRobert Johnston 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
39088045cffSRobert Johnston 	}
39188045cffSRobert Johnston 
39288045cffSRobert Johnston 	if (! found_sdr) {
393e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
3940b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
395825ba0f2Srobj 		return (-1);
396825ba0f2Srobj 	}
397825ba0f2Srobj 
398825ba0f2Srobj 	switch (sdr->is_type) {
399825ba0f2Srobj 		case IPMI_SDR_TYPE_FULL_SENSOR:
400825ba0f2Srobj 			fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record;
401825ba0f2Srobj 			sensor_num = fsensor->is_fs_number;
402825ba0f2Srobj 			break;
403825ba0f2Srobj 		case IPMI_SDR_TYPE_COMPACT_SENSOR:
404825ba0f2Srobj 			csensor = (ipmi_sdr_compact_sensor_t *)sdr->is_record;
405825ba0f2Srobj 			sensor_num = csensor->is_cs_number;
406825ba0f2Srobj 			break;
407825ba0f2Srobj 		default:
408825ba0f2Srobj 			topo_mod_dprintf(mod, "%s does not refer to a full or "
40988045cffSRobert Johnston 			    "compact SDR\n", entity_refs[i]);
4100b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
411e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
412825ba0f2Srobj 			return (-1);
413825ba0f2Srobj 	}
414825ba0f2Srobj 	if ((reading = ipmi_get_sensor_reading(hdl, sensor_num))
415825ba0f2Srobj 	    == NULL) {
416825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
41788045cffSRobert Johnston 		    "%s, sensor_num=%d (%s)\n", entity_refs[i], sensor_num,
418825ba0f2Srobj 		    ipmi_errmsg(hdl));
419e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
4200b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
421825ba0f2Srobj 		return (-1);
422825ba0f2Srobj 	}
423985366beSMatthias Scheler 	if (reading->isr_state_unavailable) {
424985366beSMatthias Scheler 		topo_mod_dprintf(mod, "Unavailable sensor %s, sensor_num=%d\n",
425985366beSMatthias Scheler 		    entity_refs[i], sensor_num);
426e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
427985366beSMatthias Scheler 		topo_mod_ipmi_rele(mod);
428985366beSMatthias Scheler 		return (-1);
429985366beSMatthias Scheler 	}
430e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
4310b1b4412SEric Schrock 	topo_mod_ipmi_rele(mod);
432825ba0f2Srobj 
433881aaecdSRob Johnston 	if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
434881aaecdSRob Johnston 	    &sensor_class, &err) != 0) {
435*6597d6fcSRobert Mustacchi 		topo_mod_dprintf(mod, "Failed to lookup prop %s/%s on node %s "
436881aaecdSRob Johnston 		    "(%s)", TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
437881aaecdSRob Johnston 		    topo_node_name(node), topo_strerror(err));
438881aaecdSRob Johnston 		return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
439881aaecdSRob Johnston 	}
440881aaecdSRob Johnston 	/*
441881aaecdSRob Johnston 	 * Mask off bits that are marked as reserved in the IPMI spec.
442881aaecdSRob Johnston 	 * For threshold sensors, bits 6:7 are reserved.
443881aaecdSRob Johnston 	 * For discrete sensors, bit 15 is reserved.
444881aaecdSRob Johnston 	 */
445881aaecdSRob Johnston 	state = reading->isr_state;
446881aaecdSRob Johnston 	if (strcmp(sensor_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0)
447881aaecdSRob Johnston 		state = state & 0x3F;
448881aaecdSRob Johnston 	else
449881aaecdSRob Johnston 		state = state & 0x7FFF;
450881aaecdSRob Johnston 
451881aaecdSRob Johnston 	topo_mod_strfree(mod, sensor_class);
452881aaecdSRob Johnston 
453825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
454825ba0f2Srobj 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
455825ba0f2Srobj 	    TOPO_SENSOR_STATE) != 0 ||
456825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
457881aaecdSRob Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, state) != 0) {
458825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
459825ba0f2Srobj 		nvlist_free(nvl);
460825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
461825ba0f2Srobj 	}
462825ba0f2Srobj 	*out = nvl;
463825ba0f2Srobj 
464825ba0f2Srobj 	return (0);
465825ba0f2Srobj }
466825ba0f2Srobj 
467825ba0f2Srobj /*ARGSUSED*/
468825ba0f2Srobj static int
ipmi_sensor_reading(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)469825ba0f2Srobj ipmi_sensor_reading(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
470825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
471825ba0f2Srobj {
47288045cffSRobert Johnston 	char **entity_refs, reading_str[BUFSZ];
47388045cffSRobert Johnston 	uint_t nelems;
47488045cffSRobert Johnston 	int err = 0, i;
475ea30102cSRob Johnston 	ipmi_sdr_t *sdr = NULL;
476ea30102cSRob Johnston 	ipmi_sdr_full_sensor_t *fsensor;
477825ba0f2Srobj 	ipmi_sensor_reading_t  *reading;
478825ba0f2Srobj 	double conv_reading;
479825ba0f2Srobj 	ipmi_handle_t *hdl;
480825ba0f2Srobj 	nvlist_t *nvl;
48188045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
482ea30102cSRob Johnston 	uint8_t sensor_num;
483ea30102cSRob Johnston 	uint32_t e_id, e_inst;
484ea30102cSRob Johnston 	tnode_t *pnode;
485825ba0f2Srobj 
486825ba0f2Srobj 	if (vers > TOPO_METH_IPMI_READING_VERSION)
487825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
488825ba0f2Srobj 
48988045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
49088045cffSRobert Johnston 	    &entity_refs, &nelems, &err) != 0) {
491825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
492825ba0f2Srobj 		    "(%s)", topo_strerror(err));
493825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
494825ba0f2Srobj 	}
495825ba0f2Srobj 
4960b1b4412SEric Schrock 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
497825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
498e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
499825ba0f2Srobj 		return (-1);
500825ba0f2Srobj 	}
501825ba0f2Srobj 
502ea30102cSRob Johnston 	pnode = topo_node_parent(node);
503ea30102cSRob Johnston 	if (topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
504ea30102cSRob Johnston 	    TOPO_PROP_IPMI_ENTITY_ID, &e_id, &err) != 0 ||
505ea30102cSRob Johnston 	    topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
506ea30102cSRob Johnston 	    TOPO_PROP_IPMI_ENTITY_INST, &e_inst, &err) != 0) {
507ea30102cSRob Johnston 		e_id = IPMI_ET_UNSPECIFIED;
508ea30102cSRob Johnston 		e_inst = 0;
509ea30102cSRob Johnston 	}
510ea30102cSRob Johnston 
51188045cffSRobert Johnston 	for (i = 0; i < nelems; i++) {
512ea30102cSRob Johnston 		if ((sdr = ipmi_sdr_lookup_precise(hdl, entity_refs[i],
513ea30102cSRob Johnston 		    (uint8_t)e_id, (uint8_t)e_inst)) != NULL) {
51488045cffSRobert Johnston 			found_sdr = B_TRUE;
51588045cffSRobert Johnston 			break;
51688045cffSRobert Johnston 		} else
51788045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
51888045cffSRobert Johnston 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
51988045cffSRobert Johnston 	}
52088045cffSRobert Johnston 
52188045cffSRobert Johnston 	if (! found_sdr) {
522e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
5230b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
524825ba0f2Srobj 		return (-1);
525825ba0f2Srobj 	}
526ea30102cSRob Johnston 	switch (sdr->is_type) {
527ea30102cSRob Johnston 		case IPMI_SDR_TYPE_FULL_SENSOR:
528ea30102cSRob Johnston 			fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record;
529ea30102cSRob Johnston 			sensor_num = fsensor->is_fs_number;
530ea30102cSRob Johnston 			break;
531ea30102cSRob Johnston 		default:
532ea30102cSRob Johnston 			topo_mod_dprintf(mod, "%s does not refer to a full "
533ea30102cSRob Johnston 			    "sensor SDR\n", entity_refs[i]);
534ea30102cSRob Johnston 			topo_mod_ipmi_rele(mod);
535e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
536ea30102cSRob Johnston 			return (-1);
537ea30102cSRob Johnston 	}
538825ba0f2Srobj 
539ea30102cSRob Johnston 	if ((reading = ipmi_get_sensor_reading(hdl, sensor_num)) == NULL) {
540825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
54188045cffSRobert Johnston 		    "%s, sensor_num=%d (%s)\n", entity_refs[i],
542ea30102cSRob Johnston 		    sensor_num, ipmi_errmsg(hdl));
543e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
5440b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
545825ba0f2Srobj 		return (-1);
546825ba0f2Srobj 	}
5470b1b4412SEric Schrock 	topo_mod_ipmi_rele(mod);
5480b1b4412SEric Schrock 
549ea30102cSRob Johnston 	if (ipmi_sdr_conv_reading(fsensor, reading->isr_reading, &conv_reading)
550825ba0f2Srobj 	    != 0) {
551825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to convert sensor reading for "
55288045cffSRobert Johnston 		    "sensor %s (%s)\n", entity_refs[i], ipmi_errmsg(hdl));
553e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
554825ba0f2Srobj 		return (-1);
555825ba0f2Srobj 	}
556e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
557825ba0f2Srobj 
558825ba0f2Srobj 	(void) snprintf(reading_str, BUFSZ, "%f", conv_reading);
559825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
560825ba0f2Srobj 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
561825ba0f2Srobj 	    TOPO_SENSOR_READING) != 0 ||
562825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_DOUBLE) != 0 ||
563825ba0f2Srobj 	    nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, conv_reading) != 0) {
564825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
565825ba0f2Srobj 		nvlist_free(nvl);
566825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
567825ba0f2Srobj 	}
568825ba0f2Srobj 	*out = nvl;
569825ba0f2Srobj 
570825ba0f2Srobj 	return (0);
571825ba0f2Srobj }
572825ba0f2Srobj 
573825ba0f2Srobj static int
ipmi_indicator_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)574825ba0f2Srobj ipmi_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
575825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
576825ba0f2Srobj {
57788045cffSRobert Johnston 	char **entity_refs;
57888045cffSRobert Johnston 	uint_t nelems;
579825ba0f2Srobj 	ipmi_sdr_generic_locator_t *gdl = NULL;
580825ba0f2Srobj 	ipmi_handle_t *hdl;
58188045cffSRobert Johnston 	int err, ret, i;
582825ba0f2Srobj 	uint8_t ledmode;
583825ba0f2Srobj 	uint32_t mode_in;
584825ba0f2Srobj 	nvlist_t *pargs, *nvl;
58588045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
586825ba0f2Srobj 
587825ba0f2Srobj 	if (vers > TOPO_METH_IPMI_MODE_VERSION)
588825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
589825ba0f2Srobj 
590825ba0f2Srobj 	/*
591825ba0f2Srobj 	 * Get an IPMI handle and then lookup the generic device locator sensor
592825ba0f2Srobj 	 * data record referenced by the entity_ref prop val
593825ba0f2Srobj 	 */
5940b1b4412SEric Schrock 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
595825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
596825ba0f2Srobj 		return (-1);
597825ba0f2Srobj 	}
598825ba0f2Srobj 
59988045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
60088045cffSRobert Johnston 	    &entity_refs, &nelems, &err) != 0) {
601825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
602825ba0f2Srobj 		    "(%s)", topo_strerror(err));
6030b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
604825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
605825ba0f2Srobj 	}
606825ba0f2Srobj 
60788045cffSRobert Johnston 	for (i = 0; i < nelems; i++) {
60888045cffSRobert Johnston 		if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
60988045cffSRobert Johnston 		    != NULL) {
61088045cffSRobert Johnston 			found_sdr = B_TRUE;
61188045cffSRobert Johnston 			break;
61288045cffSRobert Johnston 		} else
61388045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
61488045cffSRobert Johnston 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
61588045cffSRobert Johnston 	}
61688045cffSRobert Johnston 
61788045cffSRobert Johnston 	if (! found_sdr) {
618e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
6190b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
620825ba0f2Srobj 		return (-1);
621825ba0f2Srobj 	}
622825ba0f2Srobj 
623825ba0f2Srobj 	/*
624825ba0f2Srobj 	 * Now look for a private argument list to figure out whether we're
625825ba0f2Srobj 	 * doing a get or a set operation, and then do it.
626825ba0f2Srobj 	 */
627825ba0f2Srobj 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
628825ba0f2Srobj 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
629825ba0f2Srobj 		/*
630825ba0f2Srobj 		 * Set the LED mode
631825ba0f2Srobj 		 */
632825ba0f2Srobj 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
633825ba0f2Srobj 		    &mode_in)) != 0) {
634825ba0f2Srobj 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
635825ba0f2Srobj 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
636e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
6370b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
638825ba0f2Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
639825ba0f2Srobj 		}
640825ba0f2Srobj 		if (mode_in != TOPO_LED_STATE_OFF &&
641825ba0f2Srobj 		    mode_in != TOPO_LED_STATE_ON) {
642825ba0f2Srobj 			topo_mod_dprintf(mod, "Invalid property value: %d\n",
643825ba0f2Srobj 			    mode_in);
644e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
6450b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
646825ba0f2Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
647825ba0f2Srobj 		}
648825ba0f2Srobj 		ledmode = (uint8_t)mode_in;
649825ba0f2Srobj 		if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
65088045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: Failed to set LED mode for "
65188045cffSRobert Johnston 			    "%s (%s) to %s\n", __func__, entity_refs[i],
65288045cffSRobert Johnston 			    ipmi_errmsg(hdl), ledmode ? "ON" : "OFF");
653e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
6540b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
655825ba0f2Srobj 			return (-1);
656825ba0f2Srobj 		}
657825ba0f2Srobj 	} else {
658825ba0f2Srobj 		/*
659825ba0f2Srobj 		 * Get the LED mode
660825ba0f2Srobj 		 */
661825ba0f2Srobj 		if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
66288045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
66388045cffSRobert Johnston 			    "%s (%s)\n", __func__, entity_refs[i],
66488045cffSRobert Johnston 			    ipmi_errmsg(hdl));
665e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
6660b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
667825ba0f2Srobj 			return (-1);
668825ba0f2Srobj 		}
669825ba0f2Srobj 	}
670e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
6710b1b4412SEric Schrock 	topo_mod_ipmi_rele(mod);
672825ba0f2Srobj 
673825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
674825ba0f2Srobj 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
675825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
676825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
677825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
678825ba0f2Srobj 		nvlist_free(nvl);
679825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
680825ba0f2Srobj 	}
681825ba0f2Srobj 	*out = nvl;
682825ba0f2Srobj 
683825ba0f2Srobj 	return (0);
684825ba0f2Srobj }
685825ba0f2Srobj 
686825ba0f2Srobj /*
68788045cffSRobert Johnston  * On most Sun platforms there is no seperate locate LED for the drive bays.
68888045cffSRobert Johnston  * This propmethod simulates a locate LED by blinking the ok2rm LED.
68988045cffSRobert Johnston  *
69088045cffSRobert Johnston  * LED control is through a the Sun OEM led/get commands.  This propmethod can
69188045cffSRobert Johnston  * work on X4500/X4540 with ILOM 2.x and on
69288045cffSRobert Johnston  * X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms with ILOM 3.x.
693825ba0f2Srobj  */
694825ba0f2Srobj static int
bay_locate_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)69588045cffSRobert Johnston bay_locate_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
696825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
697825ba0f2Srobj {
69888045cffSRobert Johnston 	char **entity_refs;
69988045cffSRobert Johnston 	uint_t nelems;
700825ba0f2Srobj 	ipmi_sdr_generic_locator_t *gdl = NULL;
701825ba0f2Srobj 	ipmi_handle_t *hdl;
70288045cffSRobert Johnston 	int err, ret, i;
703825ba0f2Srobj 	uint8_t ledmode;
704825ba0f2Srobj 	uint32_t mode_in;
705825ba0f2Srobj 	nvlist_t *pargs, *nvl;
70688045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
707825ba0f2Srobj 
70888045cffSRobert Johnston 	if (vers > TOPO_METH_BAY_LOCATE_VERSION)
709825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
710825ba0f2Srobj 
711825ba0f2Srobj 	/*
712825ba0f2Srobj 	 * Get an IPMI handle and then lookup the generic device locator sensor
713825ba0f2Srobj 	 * data record referenced by the entity_ref prop val
714825ba0f2Srobj 	 */
7150b1b4412SEric Schrock 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
716825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
717825ba0f2Srobj 		return (-1);
718825ba0f2Srobj 	}
719825ba0f2Srobj 
72088045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
72188045cffSRobert Johnston 	    &entity_refs, &nelems, &err) != 0) {
722825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
723825ba0f2Srobj 		    "(%s)", topo_strerror(err));
7240b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
725825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
726825ba0f2Srobj 	}
727825ba0f2Srobj 
72888045cffSRobert Johnston 	for (i = 0; i < nelems; i++) {
72988045cffSRobert Johnston 		if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
73088045cffSRobert Johnston 		    != NULL) {
73188045cffSRobert Johnston 			found_sdr = B_TRUE;
73288045cffSRobert Johnston 			break;
73388045cffSRobert Johnston 		} else
73488045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
73588045cffSRobert Johnston 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
73688045cffSRobert Johnston 	}
73788045cffSRobert Johnston 
73888045cffSRobert Johnston 	if (! found_sdr) {
739e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
7400b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
741825ba0f2Srobj 		return (-1);
742825ba0f2Srobj 	}
743825ba0f2Srobj 
744825ba0f2Srobj 	/*
745825ba0f2Srobj 	 * Now look for a private argument list to figure out whether we're
746825ba0f2Srobj 	 * doing a get or a set operation, and then do it.
747825ba0f2Srobj 	 */
748825ba0f2Srobj 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
749825ba0f2Srobj 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
750825ba0f2Srobj 		/*
751825ba0f2Srobj 		 * Set the LED mode
752825ba0f2Srobj 		 */
753825ba0f2Srobj 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
754825ba0f2Srobj 		    &mode_in)) != 0) {
755825ba0f2Srobj 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
756825ba0f2Srobj 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
757e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
7580b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
759825ba0f2Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
760825ba0f2Srobj 		}
761825ba0f2Srobj 		if (mode_in != TOPO_LED_STATE_OFF &&
762825ba0f2Srobj 		    mode_in != TOPO_LED_STATE_ON) {
763825ba0f2Srobj 			topo_mod_dprintf(mod, "Invalid property value: %d\n",
764825ba0f2Srobj 			    mode_in);
765e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
7660b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
767825ba0f2Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
768825ba0f2Srobj 		}
769825ba0f2Srobj 		if (mode_in == TOPO_LED_STATE_ON)
77088045cffSRobert Johnston 			ledmode = IPMI_SUNOEM_LED_MODE_FAST;
771825ba0f2Srobj 		else
77288045cffSRobert Johnston 			ledmode = IPMI_SUNOEM_LED_MODE_OFF;
773825ba0f2Srobj 		if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
774825ba0f2Srobj 			topo_mod_dprintf(mod, "Failed to set LED mode for %s "
77588045cffSRobert Johnston 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
776e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
7770b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
778825ba0f2Srobj 			return (-1);
779825ba0f2Srobj 		}
780825ba0f2Srobj 	} else {
781825ba0f2Srobj 		/*
782825ba0f2Srobj 		 * Get the LED mode
783825ba0f2Srobj 		 */
784825ba0f2Srobj 		if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
785825ba0f2Srobj 			topo_mod_dprintf(mod, "Failed to get LED mode for %s "
78688045cffSRobert Johnston 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
787e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
7880b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
789825ba0f2Srobj 			return (-1);
790825ba0f2Srobj 		}
791825ba0f2Srobj 	}
792e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
7930b1b4412SEric Schrock 	topo_mod_ipmi_rele(mod);
794825ba0f2Srobj 
795e5dcf7beSRobert Johnston 	if (ledmode == IPMI_SUNOEM_LED_MODE_SLOW ||
796e5dcf7beSRobert Johnston 	    ledmode == IPMI_SUNOEM_LED_MODE_FAST)
797825ba0f2Srobj 		ledmode = TOPO_LED_STATE_ON;
798825ba0f2Srobj 	else
799825ba0f2Srobj 		ledmode = TOPO_LED_STATE_OFF;
800825ba0f2Srobj 
801825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
802825ba0f2Srobj 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
803825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
804825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
805825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
806825ba0f2Srobj 		nvlist_free(nvl);
807825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
808825ba0f2Srobj 	}
809825ba0f2Srobj 	*out = nvl;
810825ba0f2Srobj 
811825ba0f2Srobj 	return (0);
812825ba0f2Srobj }
813825ba0f2Srobj 
814825ba0f2Srobj /*
81588045cffSRobert Johnston  * This is a method for the "mode" property that is specific for the ok2rm and
81688045cffSRobert Johnston  * service drive bay LED's on the X4500/X4540 platforms running ILOM 2.x and
81788045cffSRobert Johnston  * for X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms running
81888045cffSRobert Johnston  * ILOM 3.x.
81988045cffSRobert Johnston  *
82088045cffSRobert Johnston  * For ILOM 2.x, the LED's are controlled by a Sun OEM led set command
82188045cffSRobert Johnston  *
82288045cffSRobert Johnston  * For ILOM 3.x platforms the LED's are controlled by sending a platform event
82388045cffSRobert Johnston  * message for the appropriate DBP/HDD##/STATE compact SDR.
82488045cffSRobert Johnston  *
82588045cffSRobert Johnston  * For both ILOM 2 and ILOM 3, the current LED mode can be obtained by a
82688045cffSRobert Johnston  * Sun OEM led get command.
827825ba0f2Srobj  */
828825ba0f2Srobj static int
bay_indicator_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)82988045cffSRobert Johnston bay_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
830825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
831825ba0f2Srobj {
83288045cffSRobert Johnston 	char **entity_refs;
83388045cffSRobert Johnston 	uint_t nelems;
834825ba0f2Srobj 	ipmi_sdr_compact_sensor_t *cs = NULL;
83588045cffSRobert Johnston 	ipmi_sdr_generic_locator_t *gdl = NULL;
83688045cffSRobert Johnston 	ipmi_deviceid_t *sp_devid;
83788045cffSRobert Johnston 	ipmi_platform_event_message_t pem;
838825ba0f2Srobj 	ipmi_handle_t *hdl;
83988045cffSRobert Johnston 	int err, ret, i;
84088045cffSRobert Johnston 	uint32_t type, ledmode;
84188045cffSRobert Johnston 	uint8_t mode_in, ev_off;
842825ba0f2Srobj 	nvlist_t *pargs, *nvl;
84388045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
844825ba0f2Srobj 
84588045cffSRobert Johnston 	if (vers > TOPO_METH_BAY_MODE_VERSION)
846825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
847825ba0f2Srobj 
848825ba0f2Srobj 	if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
849825ba0f2Srobj 	    &type, &err) != 0) {
850825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup %s property "
851825ba0f2Srobj 		    "(%s)", TOPO_FACILITY_TYPE, topo_strerror(err));
852825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
853825ba0f2Srobj 	}
854825ba0f2Srobj 	switch (type) {
855825ba0f2Srobj 	case (TOPO_LED_TYPE_SERVICE):
85688045cffSRobert Johnston 		ev_off = 0x01;
857825ba0f2Srobj 		break;
858825ba0f2Srobj 	case (TOPO_LED_TYPE_OK2RM):
85988045cffSRobert Johnston 		ev_off = 0x03;
860825ba0f2Srobj 		break;
861825ba0f2Srobj 	default:
862825ba0f2Srobj 		topo_mod_dprintf(mod, "Invalid LED type: 0x%x\n", type);
863825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
864825ba0f2Srobj 	}
865825ba0f2Srobj 
86688045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
86788045cffSRobert Johnston 	    &entity_refs, &nelems, &err) != 0) {
86888045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
86988045cffSRobert Johnston 		    "(%s)", topo_strerror(err));
87088045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
87188045cffSRobert Johnston 	}
87288045cffSRobert Johnston 
873825ba0f2Srobj 	/*
87488045cffSRobert Johnston 	 * Figure out whether the SP is running ILOM 2.x or ILOM 3.x
875825ba0f2Srobj 	 */
8760b1b4412SEric Schrock 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
877825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
878e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
879825ba0f2Srobj 		return (-1);
880825ba0f2Srobj 	}
881825ba0f2Srobj 
88288045cffSRobert Johnston 	if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
88388045cffSRobert Johnston 		topo_mod_dprintf(mod, "%s: GET DEVICEID command failed (%s)\n",
88488045cffSRobert Johnston 		    __func__, ipmi_errmsg(hdl));
885e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
88688045cffSRobert Johnston 		topo_mod_ipmi_rele(mod);
88788045cffSRobert Johnston 		return (-1);
88888045cffSRobert Johnston 	}
88988045cffSRobert Johnston 
89088045cffSRobert Johnston 	/*
89188045cffSRobert Johnston 	 * Now lookup the propmethod argument list and figure out whether we're
89288045cffSRobert Johnston 	 * doing a get or a set operation, and then do it.
89388045cffSRobert Johnston 	 */
89488045cffSRobert Johnston 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
89588045cffSRobert Johnston 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
89688045cffSRobert Johnston 		/*
89788045cffSRobert Johnston 		 * Set the LED mode
89888045cffSRobert Johnston 		 */
89988045cffSRobert Johnston 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
90088045cffSRobert Johnston 		    &ledmode)) != 0) {
90188045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
90288045cffSRobert Johnston 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
903e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
90488045cffSRobert Johnston 			topo_mod_ipmi_rele(mod);
90588045cffSRobert Johnston 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
90688045cffSRobert Johnston 		}
90788045cffSRobert Johnston 
90888045cffSRobert Johnston 		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
90988045cffSRobert Johnston 		    ledmode ? "ON" : "OFF");
91088045cffSRobert Johnston 
91188045cffSRobert Johnston 		if (sp_devid->id_firm_major == 2) {
91288045cffSRobert Johnston 			for (i = 0; i < nelems; i++) {
91388045cffSRobert Johnston 				if ((gdl = ipmi_sdr_lookup_generic(hdl,
91488045cffSRobert Johnston 				    entity_refs[i])) != NULL) {
91588045cffSRobert Johnston 					found_sdr = B_TRUE;
91688045cffSRobert Johnston 					break;
91788045cffSRobert Johnston 				} else
91888045cffSRobert Johnston 					topo_mod_dprintf(mod,
91988045cffSRobert Johnston 					    "Failed to lookup SDR for %s(%s)\n",
92088045cffSRobert Johnston 					    entity_refs[i], ipmi_errmsg(hdl));
92188045cffSRobert Johnston 			}
92288045cffSRobert Johnston 
92388045cffSRobert Johnston 			if (! found_sdr) {
924e2336878SRob Johnston 				topo_mod_strfreev(mod, entity_refs, nelems);
92588045cffSRobert Johnston 				topo_mod_ipmi_rele(mod);
92688045cffSRobert Johnston 				return (-1);
92788045cffSRobert Johnston 			}
92888045cffSRobert Johnston 
92988045cffSRobert Johnston 			if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)ledmode)
93088045cffSRobert Johnston 			    < 0) {
93188045cffSRobert Johnston 				topo_mod_dprintf(mod,
93288045cffSRobert Johnston 				    "Failed to set LED mode for %s (%s)\n",
93388045cffSRobert Johnston 				    entity_refs[i], ipmi_errmsg(hdl));
934e2336878SRob Johnston 				topo_mod_strfreev(mod, entity_refs, nelems);
93588045cffSRobert Johnston 				topo_mod_ipmi_rele(mod);
93688045cffSRobert Johnston 				return (-1);
93788045cffSRobert Johnston 			}
93888045cffSRobert Johnston 		} else {
93988045cffSRobert Johnston 			for (i = 0; i < nelems; i++) {
94088045cffSRobert Johnston 				if ((cs = ipmi_sdr_lookup_compact_sensor(hdl,
94188045cffSRobert Johnston 				    entity_refs[i])) != NULL) {
94288045cffSRobert Johnston 					found_sdr = B_TRUE;
94388045cffSRobert Johnston 					break;
94488045cffSRobert Johnston 				} else
94588045cffSRobert Johnston 					topo_mod_dprintf(mod,
94688045cffSRobert Johnston 					    "Failed to lookup SDR for %s(%s)\n",
94788045cffSRobert Johnston 					    entity_refs[i], ipmi_errmsg(hdl));
94888045cffSRobert Johnston 			}
94988045cffSRobert Johnston 
95088045cffSRobert Johnston 			if (! found_sdr) {
951e2336878SRob Johnston 				topo_mod_strfreev(mod, entity_refs, nelems);
95288045cffSRobert Johnston 				topo_mod_ipmi_rele(mod);
95388045cffSRobert Johnston 				return (-1);
95488045cffSRobert Johnston 			}
95588045cffSRobert Johnston 
95688045cffSRobert Johnston 			pem.ipem_generator = IPMI_SEL_SYSTEM;
95788045cffSRobert Johnston 			pem.ipem_rev = IPMI_EV_REV15;
95888045cffSRobert Johnston 			pem.ipem_sensor_type = IPMI_ST_BAY;
95988045cffSRobert Johnston 			pem.ipem_sensor_num = cs->is_cs_number;
96088045cffSRobert Johnston 			pem.ipem_event_type =  IPMI_RT_SPECIFIC;
96188045cffSRobert Johnston 			if (ledmode == TOPO_LED_STATE_ON)
96288045cffSRobert Johnston 				pem.ipem_event_dir = 0;
96388045cffSRobert Johnston 			else
96488045cffSRobert Johnston 				pem.ipem_event_dir = 1;
96588045cffSRobert Johnston 
96688045cffSRobert Johnston 			pem.ipem_event_data[0] = ev_off;
96788045cffSRobert Johnston 			pem.ipem_event_data[1] = 0xff;
96888045cffSRobert Johnston 			pem.ipem_event_data[2] = 0xff;
96988045cffSRobert Johnston 
97088045cffSRobert Johnston 			if (ipmi_event_platform_message(hdl, &pem) != 0) {
97188045cffSRobert Johnston 				topo_mod_dprintf(mod, "%s: Failed to send "
97288045cffSRobert Johnston 				    "platform event mesg for %s (%s)\n",
97388045cffSRobert Johnston 				    __func__, entity_refs[i], ipmi_errmsg(hdl));
974e2336878SRob Johnston 				topo_mod_strfreev(mod, entity_refs, nelems);
97588045cffSRobert Johnston 				topo_mod_ipmi_rele(mod);
97688045cffSRobert Johnston 				return (-1);
97788045cffSRobert Johnston 			}
97888045cffSRobert Johnston 		}
97988045cffSRobert Johnston 	} else {
98088045cffSRobert Johnston 		/*
98188045cffSRobert Johnston 		 * Get the LED mode
98288045cffSRobert Johnston 		 */
98388045cffSRobert Johnston 		for (i = 0; i < nelems; i++) {
98488045cffSRobert Johnston 			if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
98588045cffSRobert Johnston 			    != NULL) {
98688045cffSRobert Johnston 				found_sdr = B_TRUE;
98788045cffSRobert Johnston 				break;
98888045cffSRobert Johnston 			} else
98988045cffSRobert Johnston 				topo_mod_dprintf(mod, "%s: Failed to lookup "
99088045cffSRobert Johnston 				    "SDR for %s (%s)\n", __func__,
99188045cffSRobert Johnston 				    entity_refs[i], ipmi_errmsg(hdl));
99288045cffSRobert Johnston 		}
99388045cffSRobert Johnston 
99488045cffSRobert Johnston 		if (! found_sdr) {
995e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
99688045cffSRobert Johnston 			topo_mod_ipmi_rele(mod);
99788045cffSRobert Johnston 			return (-1);
99888045cffSRobert Johnston 		}
99988045cffSRobert Johnston 		if (ipmi_sunoem_led_get(hdl, gdl, &mode_in) < 0) {
100088045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
100188045cffSRobert Johnston 			    "%s (%s)\n", __func__, entity_refs[i],
100288045cffSRobert Johnston 			    ipmi_errmsg(hdl));
1003e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
100488045cffSRobert Johnston 			topo_mod_ipmi_rele(mod);
100588045cffSRobert Johnston 			return (-1);
100688045cffSRobert Johnston 		}
100788045cffSRobert Johnston 		ledmode = mode_in;
100888045cffSRobert Johnston 	}
1009e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
101088045cffSRobert Johnston 	topo_mod_ipmi_rele(mod);
101188045cffSRobert Johnston 
101288045cffSRobert Johnston 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
101388045cffSRobert Johnston 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
101488045cffSRobert Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
101588045cffSRobert Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
101688045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
101788045cffSRobert Johnston 		nvlist_free(nvl);
101888045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
101988045cffSRobert Johnston 	}
102088045cffSRobert Johnston 	*out = nvl;
102188045cffSRobert Johnston 	return (0);
102288045cffSRobert Johnston }
102388045cffSRobert Johnston 
102488045cffSRobert Johnston /*
102588045cffSRobert Johnston  * This propmethod is for controlling the present LED on the drive bays for
102688045cffSRobert Johnston  * the X4500 platform.
102788045cffSRobert Johnston  */
102888045cffSRobert Johnston static int
x4500_present_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)102988045cffSRobert Johnston x4500_present_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
103088045cffSRobert Johnston     nvlist_t *in, nvlist_t **out)
103188045cffSRobert Johnston {
103288045cffSRobert Johnston 	char **entity_refs;
103388045cffSRobert Johnston 	uint_t nelems;
103488045cffSRobert Johnston 	ipmi_sdr_compact_sensor_t *cs = NULL;
103588045cffSRobert Johnston 	ipmi_set_sensor_reading_t sr_out = { 0 };
103688045cffSRobert Johnston 	ipmi_handle_t *hdl;
103788045cffSRobert Johnston 	int err, ret, i;
103888045cffSRobert Johnston 	uint32_t ledmode;
103988045cffSRobert Johnston 	nvlist_t *pargs, *nvl;
104088045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
104188045cffSRobert Johnston 
104288045cffSRobert Johnston 	if (vers > TOPO_METH_X4500_MODE_VERSION)
104388045cffSRobert Johnston 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
104488045cffSRobert Johnston 
104588045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
104688045cffSRobert Johnston 	    &entity_refs, &nelems, &err) != 0) {
1047825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
1048825ba0f2Srobj 		    "(%s)", topo_strerror(err));
1049825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1050825ba0f2Srobj 	}
1051825ba0f2Srobj 
105288045cffSRobert Johnston 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
105388045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1054e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
105588045cffSRobert Johnston 		return (-1);
105688045cffSRobert Johnston 	}
105788045cffSRobert Johnston 	for (i = 0; i < nelems; i++) {
105888045cffSRobert Johnston 		if ((cs = ipmi_sdr_lookup_compact_sensor(hdl, entity_refs[i]))
105988045cffSRobert Johnston 		    != NULL) {
106088045cffSRobert Johnston 			found_sdr = B_TRUE;
106188045cffSRobert Johnston 			break;
106288045cffSRobert Johnston 		} else
106388045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
106488045cffSRobert Johnston 			    "(%s)\n", entity_refs[i],
106588045cffSRobert Johnston 			    ipmi_errmsg(hdl));
106688045cffSRobert Johnston 	}
106788045cffSRobert Johnston 
106888045cffSRobert Johnston 	if (! found_sdr) {
1069e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
10700b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
1071825ba0f2Srobj 		return (-1);
1072825ba0f2Srobj 	}
1073825ba0f2Srobj 
1074825ba0f2Srobj 	/*
1075825ba0f2Srobj 	 * Now lookup the propmethod argument list and figure out whether we're
1076825ba0f2Srobj 	 * doing a get or a set operation, and then do it.
1077825ba0f2Srobj 	 */
1078825ba0f2Srobj 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1079825ba0f2Srobj 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1080825ba0f2Srobj 		/*
1081825ba0f2Srobj 		 * Set the LED mode
1082825ba0f2Srobj 		 */
1083825ba0f2Srobj 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1084825ba0f2Srobj 		    &ledmode)) != 0) {
1085825ba0f2Srobj 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1086825ba0f2Srobj 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1087e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
10880b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
1089825ba0f2Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1090825ba0f2Srobj 		}
1091825ba0f2Srobj 
109288045cffSRobert Johnston 		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
109388045cffSRobert Johnston 		    ledmode ? "ON" : "OFF");
109488045cffSRobert Johnston 
1095825ba0f2Srobj 		if (ledmode == TOPO_LED_STATE_OFF) {
109688045cffSRobert Johnston 			sr_out.iss_deassert_state = BAY_PRESENT_LED_MASK;
1097825ba0f2Srobj 			sr_out.iss_deassrt_op = IPMI_SENSOR_OP_SET;
1098825ba0f2Srobj 		} else if (ledmode == TOPO_LED_STATE_ON) {
109988045cffSRobert Johnston 			sr_out.iss_assert_state = BAY_PRESENT_LED_MASK;
1100825ba0f2Srobj 			sr_out.iss_assert_op = IPMI_SENSOR_OP_SET;
1101825ba0f2Srobj 		} else {
110288045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: Invalid LED mode: "
110388045cffSRobert Johnston 			    "%d\n", __func__, ledmode);
1104e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
11050b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
1106825ba0f2Srobj 			return (-1);
1107825ba0f2Srobj 		}
1108825ba0f2Srobj 		sr_out.iss_id = cs->is_cs_number;
110988045cffSRobert Johnston 		topo_mod_dprintf(mod, "Setting LED mode (mask=0x%x)\n",
111088045cffSRobert Johnston 		    BAY_PRESENT_LED_MASK);
1111825ba0f2Srobj 		if (ipmi_set_sensor_reading(hdl, &sr_out) != 0) {
111288045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: Failed to set "
111388045cffSRobert Johnston 			    "sensor reading for %s (%s)\n", __func__,
111488045cffSRobert Johnston 			    entity_refs[i], ipmi_errmsg(hdl));
1115e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
11160b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
1117825ba0f2Srobj 			return (-1);
1118825ba0f2Srobj 		}
1119825ba0f2Srobj 	} else {
1120825ba0f2Srobj 		/*
1121825ba0f2Srobj 		 * Get the LED mode
1122825ba0f2Srobj 		 */
1123825ba0f2Srobj 		ipmi_sensor_reading_t *sr_in;
1124825ba0f2Srobj 
1125825ba0f2Srobj 		topo_mod_dprintf(mod, "Getting LED mode\n");
1126825ba0f2Srobj 		if ((sr_in = ipmi_get_sensor_reading(hdl, cs->is_cs_number))
1127825ba0f2Srobj 		    == NULL) {
1128825ba0f2Srobj 			topo_mod_dprintf(mod, "Failed to get sensor reading "
1129825ba0f2Srobj 			    "for sensor %s (sensor num: %d) (error: %s)\n",
113088045cffSRobert Johnston 			    entity_refs[i], cs->is_cs_number, ipmi_errmsg(hdl));
1131e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
11320b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
1133825ba0f2Srobj 			return (-1);
1134825ba0f2Srobj 		}
113588045cffSRobert Johnston 		if (sr_in->isr_state & (uint16_t)BAY_PRESENT_LED_MASK)
1136825ba0f2Srobj 			ledmode = TOPO_LED_STATE_ON;
1137825ba0f2Srobj 		else
1138825ba0f2Srobj 			ledmode = TOPO_LED_STATE_OFF;
1139825ba0f2Srobj 	}
1140e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
114188045cffSRobert Johnston 	topo_mod_ipmi_rele(mod);
114288045cffSRobert Johnston 
114388045cffSRobert Johnston 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
114488045cffSRobert Johnston 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
114588045cffSRobert Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
114688045cffSRobert Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
114788045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
114888045cffSRobert Johnston 		nvlist_free(nvl);
114988045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
115088045cffSRobert Johnston 	}
115188045cffSRobert Johnston 	*out = nvl;
115288045cffSRobert Johnston 	return (0);
115388045cffSRobert Johnston }
115488045cffSRobert Johnston 
115588045cffSRobert Johnston /*
115688045cffSRobert Johnston  * This is a property method for controlling the chassis service LED on
115788045cffSRobert Johnston  * ILOM 3.x based platforms.
115888045cffSRobert Johnston  */
115988045cffSRobert Johnston static int
chassis_service_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)116088045cffSRobert Johnston chassis_service_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
116188045cffSRobert Johnston     nvlist_t *in, nvlist_t **out)
116288045cffSRobert Johnston {
116388045cffSRobert Johnston 	char **entity_refs;
116488045cffSRobert Johnston 	uint_t nelems;
116588045cffSRobert Johnston 	ipmi_sdr_generic_locator_t *gdl = NULL;
116688045cffSRobert Johnston 	ipmi_deviceid_t *sp_devid;
116788045cffSRobert Johnston 	ipmi_platform_event_message_t pem;
116888045cffSRobert Johnston 	ipmi_handle_t *hdl;
116988045cffSRobert Johnston 	int err, ret, i;
117088045cffSRobert Johnston 	uint8_t ledmode;
117188045cffSRobert Johnston 	uint32_t mode_in;
117288045cffSRobert Johnston 	nvlist_t *pargs, *nvl;
117388045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
117488045cffSRobert Johnston 
117588045cffSRobert Johnston 	if (vers > TOPO_METH_CHASSIS_SERVICE_VERSION)
117688045cffSRobert Johnston 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
117788045cffSRobert Johnston 
117888045cffSRobert Johnston 	/*
117988045cffSRobert Johnston 	 * Get an IPMI handle and then lookup the generic device locator record
118088045cffSRobert Johnston 	 * referenced by the entity_ref prop val
118188045cffSRobert Johnston 	 */
118288045cffSRobert Johnston 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
118388045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
118488045cffSRobert Johnston 		return (-1);
118588045cffSRobert Johnston 	}
118688045cffSRobert Johnston 
118788045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
118888045cffSRobert Johnston 	    &entity_refs, &nelems, &err) != 0) {
118988045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
119088045cffSRobert Johnston 		    "(%s)", topo_strerror(err));
119188045cffSRobert Johnston 		topo_mod_ipmi_rele(mod);
119288045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
119388045cffSRobert Johnston 	}
119488045cffSRobert Johnston 
119588045cffSRobert Johnston 	for (i = 0; i < nelems; i++) {
119688045cffSRobert Johnston 		if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
119788045cffSRobert Johnston 		    != NULL) {
119888045cffSRobert Johnston 			found_sdr = B_TRUE;
119988045cffSRobert Johnston 			break;
120088045cffSRobert Johnston 		} else
120188045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
120288045cffSRobert Johnston 			    "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
120388045cffSRobert Johnston 	}
120488045cffSRobert Johnston 
120588045cffSRobert Johnston 	if (! found_sdr) {
1206e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
120788045cffSRobert Johnston 		topo_mod_ipmi_rele(mod);
120888045cffSRobert Johnston 		return (-1);
120988045cffSRobert Johnston 	}
121088045cffSRobert Johnston 
121188045cffSRobert Johnston 	/*
121288045cffSRobert Johnston 	 * Now lookup the propmethod argument list and figure out whether we're
121388045cffSRobert Johnston 	 * doing a get or a set operation, and then do it.
121488045cffSRobert Johnston 	 */
121588045cffSRobert Johnston 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
121688045cffSRobert Johnston 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
121788045cffSRobert Johnston 		/*
121888045cffSRobert Johnston 		 * Set the LED mode
121988045cffSRobert Johnston 		 */
122088045cffSRobert Johnston 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
122188045cffSRobert Johnston 		    &mode_in)) != 0) {
122288045cffSRobert Johnston 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
122388045cffSRobert Johnston 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1224e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
122588045cffSRobert Johnston 			topo_mod_ipmi_rele(mod);
122688045cffSRobert Johnston 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
122788045cffSRobert Johnston 		}
122888045cffSRobert Johnston 
122988045cffSRobert Johnston 		/*
123088045cffSRobert Johnston 		 * Determine which IPMI mechanism to use to set the LED mode
123188045cffSRobert Johnston 		 * based on whether the SP is running ILOM 2 or later.
123288045cffSRobert Johnston 		 */
123388045cffSRobert Johnston 		if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
123488045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: GET DEVICEID command failed "
123588045cffSRobert Johnston 			"(%s)\n", __func__, ipmi_errmsg(hdl));
1236e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
123788045cffSRobert Johnston 			topo_mod_ipmi_rele(mod);
123888045cffSRobert Johnston 			return (-1);
123988045cffSRobert Johnston 		}
124088045cffSRobert Johnston 
124188045cffSRobert Johnston 		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
124288045cffSRobert Johnston 		    mode_in ? "ON" : "OFF");
124388045cffSRobert Johnston 
124488045cffSRobert Johnston 		if (sp_devid->id_firm_major == 2) {
124588045cffSRobert Johnston 			if (mode_in != TOPO_LED_STATE_OFF &&
124688045cffSRobert Johnston 			    mode_in != TOPO_LED_STATE_ON) {
124788045cffSRobert Johnston 				topo_mod_dprintf(mod, "Invalid property value: "
124888045cffSRobert Johnston 				    "%d\n", mode_in);
1249e2336878SRob Johnston 				topo_mod_strfreev(mod, entity_refs, nelems);
125088045cffSRobert Johnston 				topo_mod_ipmi_rele(mod);
125188045cffSRobert Johnston 				return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
125288045cffSRobert Johnston 			}
125388045cffSRobert Johnston 			if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)mode_in)
125488045cffSRobert Johnston 			    < 0) {
125588045cffSRobert Johnston 				topo_mod_dprintf(mod, "Failed to set LED mode "
125688045cffSRobert Johnston 				    "for %s (%s)\n", entity_refs[i],
125788045cffSRobert Johnston 				    ipmi_errmsg(hdl));
1258e2336878SRob Johnston 				topo_mod_strfreev(mod, entity_refs, nelems);
125988045cffSRobert Johnston 				topo_mod_ipmi_rele(mod);
126088045cffSRobert Johnston 				return (-1);
126188045cffSRobert Johnston 			}
126288045cffSRobert Johnston 		} else {
126388045cffSRobert Johnston 			pem.ipem_generator = IPMI_SEL_SYSTEM;
126488045cffSRobert Johnston 			pem.ipem_rev = IPMI_EV_REV15;
126588045cffSRobert Johnston 			pem.ipem_sensor_type = IPMI_ST_SYSTEM;
126688045cffSRobert Johnston 			pem.ipem_sensor_num = 0x00;
126788045cffSRobert Johnston 			pem.ipem_event_type =  IPMI_RT_SPECIFIC;
126888045cffSRobert Johnston 			if (mode_in == TOPO_LED_STATE_ON)
126988045cffSRobert Johnston 				pem.ipem_event_dir = 0;
127088045cffSRobert Johnston 			else
127188045cffSRobert Johnston 				pem.ipem_event_dir = 1;
127288045cffSRobert Johnston 
127388045cffSRobert Johnston 			pem.ipem_event_data[0] = 0x02;
127488045cffSRobert Johnston 			pem.ipem_event_data[1] = 0xff;
127588045cffSRobert Johnston 			pem.ipem_event_data[2] = 0xff;
127688045cffSRobert Johnston 
127788045cffSRobert Johnston 			topo_mod_dprintf(mod, "Sending platform event\n");
127888045cffSRobert Johnston 			if (ipmi_event_platform_message(hdl, &pem) != 0) {
127988045cffSRobert Johnston 				topo_mod_dprintf(mod, "%s: Failed to send "
128088045cffSRobert Johnston 				    "platform event mesg for sensor 0 (%s)\n",
128188045cffSRobert Johnston 				    __func__, ipmi_errmsg(hdl));
1282e2336878SRob Johnston 				topo_mod_strfreev(mod, entity_refs, nelems);
128388045cffSRobert Johnston 				topo_mod_ipmi_rele(mod);
128488045cffSRobert Johnston 				return (-1);
128588045cffSRobert Johnston 			}
128688045cffSRobert Johnston 		}
128788045cffSRobert Johnston 	} else {
128888045cffSRobert Johnston 		/*
128988045cffSRobert Johnston 		 * Get the LED mode
129088045cffSRobert Johnston 		 */
129188045cffSRobert Johnston 		if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
129288045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
129388045cffSRobert Johnston 			    "%s (%s)\n", __func__, entity_refs[i],
129488045cffSRobert Johnston 			    ipmi_errmsg(hdl));
1295e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
129688045cffSRobert Johnston 			topo_mod_ipmi_rele(mod);
129788045cffSRobert Johnston 			return (-1);
129888045cffSRobert Johnston 		}
129988045cffSRobert Johnston 	}
1300e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
13010b1b4412SEric Schrock 	topo_mod_ipmi_rele(mod);
1302825ba0f2Srobj 
1303825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1304825ba0f2Srobj 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1305825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1306825ba0f2Srobj 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
1307825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1308825ba0f2Srobj 		nvlist_free(nvl);
1309825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1310825ba0f2Srobj 	}
1311825ba0f2Srobj 	*out = nvl;
1312825ba0f2Srobj 	return (0);
1313825ba0f2Srobj }
1314825ba0f2Srobj 
13158f022dd6SRob Johnston /*
13168f022dd6SRob Johnston  * This is a property method for controlling the chassis identify LED using
13178f022dd6SRob Johnston  * generic IPMI mechanisms.
13188f022dd6SRob Johnston  */
13198f022dd6SRob Johnston /*ARGSUSED*/
13208f022dd6SRob Johnston static int
chassis_ident_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)13218f022dd6SRob Johnston chassis_ident_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
13228f022dd6SRob Johnston     nvlist_t *in, nvlist_t **out)
13238f022dd6SRob Johnston {
13248f022dd6SRob Johnston 	ipmi_handle_t *hdl;
13258f022dd6SRob Johnston 	int ret;
13268f022dd6SRob Johnston 	uint32_t modeval;
13278f022dd6SRob Johnston 	boolean_t assert_ident;
13288f022dd6SRob Johnston 	nvlist_t *pargs, *nvl;
13298f022dd6SRob Johnston 	ipmi_chassis_status_t *chs;
13308f022dd6SRob Johnston 
13318f022dd6SRob Johnston 	if (vers > TOPO_METH_CHASSIS_IDENT_VERSION)
13328f022dd6SRob Johnston 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
13338f022dd6SRob Johnston 
13348f022dd6SRob Johnston 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
13358f022dd6SRob Johnston 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
13368f022dd6SRob Johnston 		return (-1);
13378f022dd6SRob Johnston 	}
13388f022dd6SRob Johnston 
13398f022dd6SRob Johnston 	/*
13408f022dd6SRob Johnston 	 * Now lookup the propmethod argument list and figure out whether we're
13418f022dd6SRob Johnston 	 * doing a get or a set operation, and then do it.
13428f022dd6SRob Johnston 	 */
13438f022dd6SRob Johnston 	if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
13448f022dd6SRob Johnston 	    nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
13458f022dd6SRob Johnston 		/*
13468f022dd6SRob Johnston 		 * Set the LED mode
13478f022dd6SRob Johnston 		 */
13488f022dd6SRob Johnston 		if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
13498f022dd6SRob Johnston 		    &modeval)) != 0) {
13508f022dd6SRob Johnston 			topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
13518f022dd6SRob Johnston 			    "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
13528f022dd6SRob Johnston 			topo_mod_ipmi_rele(mod);
13538f022dd6SRob Johnston 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
13548f022dd6SRob Johnston 		}
13558f022dd6SRob Johnston 
13568f022dd6SRob Johnston 		assert_ident = modeval ? B_TRUE : B_FALSE;
13578f022dd6SRob Johnston 		topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
13588f022dd6SRob Johnston 		    assert_ident ? "ON" : "OFF");
13598f022dd6SRob Johnston 		if (ipmi_chassis_identify(hdl, assert_ident) != 0) {
13608f022dd6SRob Johnston 			topo_mod_ipmi_rele(mod);
13618f022dd6SRob Johnston 			return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
13628f022dd6SRob Johnston 		}
13638f022dd6SRob Johnston 
13648f022dd6SRob Johnston 	} else {
13658f022dd6SRob Johnston 		/*
13668f022dd6SRob Johnston 		 * Get the LED mode
13678f022dd6SRob Johnston 		 */
13688f022dd6SRob Johnston 		if ((chs = ipmi_chassis_status(hdl)) == NULL ||
13698f022dd6SRob Johnston 		    !chs->ichs_identify_supported) {
13708f022dd6SRob Johnston 			free(chs);
13718f022dd6SRob Johnston 			topo_mod_ipmi_rele(mod);
13728f022dd6SRob Johnston 			return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
13738f022dd6SRob Johnston 		}
13748f022dd6SRob Johnston 		/*
13758f022dd6SRob Johnston 		 * ichs_identify_state is a 2-bit value with the following
13768f022dd6SRob Johnston 		 * semantics:
13778f022dd6SRob Johnston 		 * 0 - ident is off
13788f022dd6SRob Johnston 		 * 1 - ident is temporarily on
13798f022dd6SRob Johnston 		 * 2 - ident is indefinitely on
13808f022dd6SRob Johnston 		 * 3 - reserved
13818f022dd6SRob Johnston 		 */
13828f022dd6SRob Johnston 		switch (chs->ichs_identify_state) {
13838f022dd6SRob Johnston 		case 0:
13848f022dd6SRob Johnston 			modeval = TOPO_LED_STATE_OFF;
13858f022dd6SRob Johnston 			break;
13868f022dd6SRob Johnston 		case 1:
13878f022dd6SRob Johnston 		case 2:
13888f022dd6SRob Johnston 			modeval = TOPO_LED_STATE_ON;
13898f022dd6SRob Johnston 			break;
13908f022dd6SRob Johnston 		default:
13918f022dd6SRob Johnston 			free(chs);
13928f022dd6SRob Johnston 			topo_mod_ipmi_rele(mod);
13938f022dd6SRob Johnston 			return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
13948f022dd6SRob Johnston 		}
13958f022dd6SRob Johnston 		free(chs);
13968f022dd6SRob Johnston 	}
13978f022dd6SRob Johnston 	topo_mod_ipmi_rele(mod);
13988f022dd6SRob Johnston 
13998f022dd6SRob Johnston 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
14008f022dd6SRob Johnston 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
14018f022dd6SRob Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
14028f022dd6SRob Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, modeval) != 0) {
14038f022dd6SRob Johnston 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
14048f022dd6SRob Johnston 		nvlist_free(nvl);
14058f022dd6SRob Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
14068f022dd6SRob Johnston 	}
14078f022dd6SRob Johnston 	*out = nvl;
14088f022dd6SRob Johnston 	return (0);
14098f022dd6SRob Johnston }
14108f022dd6SRob Johnston 
1411208e1562SRob Johnston #define	ISBITSET(MASK, BIT)	((MASK & BIT) == BIT)
1412208e1562SRob Johnston 
1413208e1562SRob Johnston struct sensor_thresh {
1414208e1562SRob Johnston 	uint8_t	sthr_threshbit;
1415208e1562SRob Johnston 	const char *sthr_propname;
1416208e1562SRob Johnston 	uint8_t sthr_threshoff;
1417208e1562SRob Johnston };
1418208e1562SRob Johnston 
1419208e1562SRob Johnston static const struct sensor_thresh threshset[] = {
1420208e1562SRob Johnston 	{ IPMI_SENSOR_THRESHOLD_LOWER_NONCRIT, TOPO_PROP_THRESHOLD_LNC,
1421208e1562SRob Johnston 	    offsetof(ipmi_sensor_thresholds_t, ithr_lower_noncrit) },
1422208e1562SRob Johnston 	{ IPMI_SENSOR_THRESHOLD_LOWER_CRIT, TOPO_PROP_THRESHOLD_LCR,
1423208e1562SRob Johnston 	    offsetof(ipmi_sensor_thresholds_t, ithr_lower_crit) },
1424208e1562SRob Johnston 	{ IPMI_SENSOR_THRESHOLD_LOWER_NONRECOV, TOPO_PROP_THRESHOLD_LNR,
1425208e1562SRob Johnston 	    offsetof(ipmi_sensor_thresholds_t, ithr_lower_nonrec) },
1426208e1562SRob Johnston 	{ IPMI_SENSOR_THRESHOLD_UPPER_NONCRIT, TOPO_PROP_THRESHOLD_UNC,
1427208e1562SRob Johnston 	    offsetof(ipmi_sensor_thresholds_t, ithr_upper_noncrit) },
1428208e1562SRob Johnston 	{ IPMI_SENSOR_THRESHOLD_UPPER_CRIT, TOPO_PROP_THRESHOLD_UCR,
1429208e1562SRob Johnston 	    offsetof(ipmi_sensor_thresholds_t, ithr_upper_crit) },
1430208e1562SRob Johnston 	{ IPMI_SENSOR_THRESHOLD_UPPER_NONRECOV, TOPO_PROP_THRESHOLD_UNR,
1431208e1562SRob Johnston 	    offsetof(ipmi_sensor_thresholds_t, ithr_upper_nonrec) }
1432208e1562SRob Johnston };
1433208e1562SRob Johnston 
1434208e1562SRob Johnston static uint_t num_thresholds =
1435208e1562SRob Johnston     sizeof (threshset) / sizeof (struct sensor_thresh);
1436208e1562SRob Johnston 
1437208e1562SRob Johnston static int
set_thresh_prop(topo_mod_t * mod,tnode_t * fnode,ipmi_sdr_full_sensor_t * fs,uint8_t raw_thresh,const struct sensor_thresh * thresh)1438208e1562SRob Johnston set_thresh_prop(topo_mod_t *mod, tnode_t *fnode, ipmi_sdr_full_sensor_t *fs,
1439208e1562SRob Johnston     uint8_t raw_thresh, const struct sensor_thresh *thresh)
1440208e1562SRob Johnston {
1441208e1562SRob Johnston 	int err;
1442208e1562SRob Johnston 	double conv_thresh;
1443208e1562SRob Johnston 
1444208e1562SRob Johnston 	if (ipmi_sdr_conv_reading(fs, raw_thresh, &conv_thresh) != 0) {
1445208e1562SRob Johnston 		topo_mod_dprintf(mod, "Failed to convert threshold %s on node "
1446208e1562SRob Johnston 		    "%s", thresh->sthr_propname, topo_node_name(fnode));
1447208e1562SRob Johnston 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1448208e1562SRob Johnston 	}
1449208e1562SRob Johnston 	if (topo_prop_set_double(fnode, TOPO_PGROUP_FACILITY,
1450208e1562SRob Johnston 	    thresh->sthr_propname, TOPO_PROP_IMMUTABLE, conv_thresh, &err) !=
1451208e1562SRob Johnston 	    0) {
1452208e1562SRob Johnston 		topo_mod_dprintf(mod, "Failed to set property %s on node %s "
1453208e1562SRob Johnston 		    "(%s)", thresh->sthr_propname, topo_node_name(fnode),
1454208e1562SRob Johnston 		    topo_strerror(err));
1455208e1562SRob Johnston 		return (topo_mod_seterrno(mod, err));
1456208e1562SRob Johnston 	}
1457208e1562SRob Johnston 	return (0);
1458208e1562SRob Johnston }
1459208e1562SRob Johnston 
1460825ba0f2Srobj static int
make_sensor_node(topo_mod_t * mod,tnode_t * pnode,struct sensor_data * sd,ipmi_handle_t * hdl)1461208e1562SRob Johnston make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd,
1462208e1562SRob Johnston     ipmi_handle_t *hdl)
1463825ba0f2Srobj {
14647fcedef2SRobert Johnston 	int err, ret, i;
1465825ba0f2Srobj 	tnode_t *fnode;
146688045cffSRobert Johnston 	char *ftype = "sensor", facname[MAX_ID_LEN], **entity_refs;
1467825ba0f2Srobj 	topo_pgroup_info_t pgi;
1468825ba0f2Srobj 	nvlist_t *arg_nvl = NULL;
1469208e1562SRob Johnston 	ipmi_sensor_thresholds_t thresh = { 0 };
1470208e1562SRob Johnston 	uint8_t mask;
1471825ba0f2Srobj 
14727fcedef2SRobert Johnston 	/*
14737fcedef2SRobert Johnston 	 * Some platforms have '/' characters in the IPMI entity name, but '/'
14747fcedef2SRobert Johnston 	 * has a special meaning for FMRI's so we change them to '.' before
14757fcedef2SRobert Johnston 	 * binding the node into the topology.
14767fcedef2SRobert Johnston 	 */
14777fcedef2SRobert Johnston 	(void) strcpy(facname, sd->sd_entity_ref);
14787fcedef2SRobert Johnston 	for (i = 0; facname[i]; i++)
14797fcedef2SRobert Johnston 		if (facname[i] == '/')
14807fcedef2SRobert Johnston 			facname[i] = '.';
14817fcedef2SRobert Johnston 
14827fcedef2SRobert Johnston 	if ((fnode = topo_node_facbind(mod, pnode, facname, ftype)) == NULL) {
1483825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to bind facility node: %s\n",
14847fcedef2SRobert Johnston 		    facname);
1485208e1562SRob Johnston 		/* errno set */
1486825ba0f2Srobj 		return (-1);
1487825ba0f2Srobj 	}
1488825ba0f2Srobj 
1489825ba0f2Srobj 	pgi.tpi_name = TOPO_PGROUP_FACILITY;
1490825ba0f2Srobj 	pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1491825ba0f2Srobj 	pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1492825ba0f2Srobj 	pgi.tpi_version = 1;
1493825ba0f2Srobj 	if (topo_pgroup_create(fnode, &pgi, &err) != 0) {
1494825ba0f2Srobj 		if (err != ETOPO_PROP_DEFD) {
1495825ba0f2Srobj 			topo_mod_dprintf(mod,  "pgroups create failure: %s\n",
1496825ba0f2Srobj 			    topo_strerror(err));
1497825ba0f2Srobj 			topo_node_unbind(fnode);
1498208e1562SRob Johnston 			return (topo_mod_seterrno(mod, err));
1499825ba0f2Srobj 		}
1500825ba0f2Srobj 	}
1501825ba0f2Srobj 	if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) {
1502825ba0f2Srobj 		topo_mod_dprintf(mod, "make_fac_node: "
1503825ba0f2Srobj 		    "failed to register facility methods");
1504825ba0f2Srobj 		topo_node_unbind(fnode);
1505208e1562SRob Johnston 		/* errno set */
1506825ba0f2Srobj 		return (-1);
1507825ba0f2Srobj 	}
1508825ba0f2Srobj 	/*
1509825ba0f2Srobj 	 * For both threshold and discrete sensors we set up a propmethod for
1510825ba0f2Srobj 	 * getting the sensor state and properties to hold the entity ref,
1511825ba0f2Srobj 	 * sensor class and sensor type.
1512825ba0f2Srobj 	 */
151388045cffSRobert Johnston 	if ((entity_refs = topo_mod_alloc(mod, sizeof (char *))) == NULL)
151488045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
151588045cffSRobert Johnston 
151688045cffSRobert Johnston 	entity_refs[0] = topo_mod_strdup(mod, sd->sd_entity_ref);
151788045cffSRobert Johnston 
151888045cffSRobert Johnston 	if (topo_prop_set_string_array(fnode, TOPO_PGROUP_FACILITY,
151988045cffSRobert Johnston 	    "entity_ref", TOPO_PROP_IMMUTABLE, (const char **)entity_refs, 1,
152088045cffSRobert Johnston 	    &err) != 0) {
152188045cffSRobert Johnston 		topo_mod_dprintf(mod, "%s: Failed to set entity_ref property "
1522*6597d6fcSRobert Mustacchi 		    "on node: %s=%" PRIu64 " (%s)\n", __func__,
1523*6597d6fcSRobert Mustacchi 		    topo_node_name(fnode), topo_node_instance(fnode),
1524*6597d6fcSRobert Mustacchi 		    topo_strerror(err));
1525e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, 1);
1526208e1562SRob Johnston 		return (topo_mod_seterrno(mod, err));
1527825ba0f2Srobj 	}
1528e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, 1);
152988045cffSRobert Johnston 
1530825ba0f2Srobj 	if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
1531825ba0f2Srobj 	    TOPO_PROP_IMMUTABLE, sd->sd_class, &err) != 0) {
1532825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to set %s property on node: "
1533*6597d6fcSRobert Mustacchi 		    "%s=%" PRIu64 " (%s)\n", TOPO_SENSOR_CLASS,
1534*6597d6fcSRobert Mustacchi 		    topo_node_name(fnode), topo_node_instance(fnode),
1535*6597d6fcSRobert Mustacchi 		    topo_strerror(err));
1536208e1562SRob Johnston 		return (topo_mod_seterrno(mod, err));
1537825ba0f2Srobj 	}
1538825ba0f2Srobj 	if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1539825ba0f2Srobj 	    TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) {
1540825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to set %s property on node: "
1541*6597d6fcSRobert Mustacchi 		    "%s=%" PRIu64 " (%s)\n", TOPO_FACILITY_TYPE,
1542*6597d6fcSRobert Mustacchi 		    topo_node_name(fnode), topo_node_instance(fnode),
1543*6597d6fcSRobert Mustacchi 		    topo_strerror(err));
1544208e1562SRob Johnston 		return (topo_mod_seterrno(mod, err));
1545825ba0f2Srobj 	}
1546825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) {
1547825ba0f2Srobj 		topo_node_unbind(fnode);
1548825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1549825ba0f2Srobj 	}
1550825ba0f2Srobj 
1551825ba0f2Srobj 	if ((ret = nvlist_add_string(arg_nvl, "ipmi_entity", sd->sd_entity_ref))
1552825ba0f2Srobj 	    != 0) {
1553825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n",
1554825ba0f2Srobj 		    strerror(ret));
1555825ba0f2Srobj 		nvlist_free(arg_nvl);
1556208e1562SRob Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1557825ba0f2Srobj 	}
1558825ba0f2Srobj 
1559825ba0f2Srobj 	if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1560825ba0f2Srobj 	    TOPO_SENSOR_STATE, TOPO_TYPE_UINT32, "ipmi_sensor_state", arg_nvl,
1561825ba0f2Srobj 	    &err) != 0) {
1562825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to register %s propmeth on fac "
1563825ba0f2Srobj 		    "node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode),
1564825ba0f2Srobj 		    topo_strerror(err));
1565825ba0f2Srobj 		nvlist_free(arg_nvl);
1566208e1562SRob Johnston 		return (topo_mod_seterrno(mod, err));
1567825ba0f2Srobj 	}
1568825ba0f2Srobj 
1569208e1562SRob Johnston 	/*
1570208e1562SRob Johnston 	 * If it's a discrete sensor then we're done.  For threshold sensors,
1571208e1562SRob Johnston 	 * there are additional properties to set up.
1572208e1562SRob Johnston 	 */
1573208e1562SRob Johnston 	if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) != 0) {
1574208e1562SRob Johnston 		nvlist_free(arg_nvl);
1575208e1562SRob Johnston 		return (0);
1576208e1562SRob Johnston 	}
1577208e1562SRob Johnston 
1578208e1562SRob Johnston 	/*
1579208e1562SRob Johnston 	 * Create properties to expose the analog sensor reading, the unit
1580208e1562SRob Johnston 	 * type and the upper and lower thresholds, if available.
1581208e1562SRob Johnston 	 */
1582208e1562SRob Johnston 	if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1583208e1562SRob Johnston 	    TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, "ipmi_sensor_reading",
1584208e1562SRob Johnston 	    arg_nvl, &err) != 0) {
1585208e1562SRob Johnston 		topo_mod_dprintf(mod, "Failed to register %s propmeth on fac "
1586208e1562SRob Johnston 		    "node %s (%s)\n", TOPO_SENSOR_READING,
1587208e1562SRob Johnston 		    topo_node_name(fnode), topo_strerror(err));
1588208e1562SRob Johnston 		nvlist_free(arg_nvl);
1589208e1562SRob Johnston 		return (topo_mod_seterrno(mod, err));
1590208e1562SRob Johnston 	}
1591208e1562SRob Johnston 	if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1592208e1562SRob Johnston 	    TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err) != 0) {
1593208e1562SRob Johnston 		topo_mod_dprintf(mod, "Failed to set units property on node "
1594208e1562SRob Johnston 		    "%s (%s)\n", topo_node_name(fnode), topo_strerror(err));
1595208e1562SRob Johnston 		nvlist_free(arg_nvl);
1596208e1562SRob Johnston 		return (topo_mod_seterrno(mod, err));
1597208e1562SRob Johnston 	}
1598208e1562SRob Johnston 	nvlist_free(arg_nvl);
1599208e1562SRob Johnston 
1600208e1562SRob Johnston 	/*
1601208e1562SRob Johnston 	 * It is possible (though unusual) for a compact sensor record to
1602208e1562SRob Johnston 	 * represent a threshold sensor.  However, due to how
1603208e1562SRob Johnston 	 * ipmi_sdr_conv_reading() is currently implemented, we only support
1604208e1562SRob Johnston 	 * gathering threshold readings on sensors enumerated from Full Sensor
1605208e1562SRob Johnston 	 * Records.
1606208e1562SRob Johnston 	 */
1607208e1562SRob Johnston 	if (sd->sd_fs_sdr == NULL)
1608208e1562SRob Johnston 		return (0);
1609208e1562SRob Johnston 
1610208e1562SRob Johnston 	if (ipmi_get_sensor_thresholds(hdl, &thresh,
1611208e1562SRob Johnston 	    sd->sd_fs_sdr->is_fs_number) != 0) {
161222e991d5SYuri Pankov 		/*
161322e991d5SYuri Pankov 		 * Some sensors report supporting reading thresholds, but Get
161422e991d5SYuri Pankov 		 * Sensor Thresholds returns Invalid Command.  Do not consider
161522e991d5SYuri Pankov 		 * this an error so we could continue enumerating sensors for
161622e991d5SYuri Pankov 		 * the entity.
161722e991d5SYuri Pankov 		 */
161822e991d5SYuri Pankov 		if (ipmi_errno(hdl) == EIPMI_INVALID_COMMAND)
161922e991d5SYuri Pankov 			return (0);
162022e991d5SYuri Pankov 
1621208e1562SRob Johnston 		topo_mod_dprintf(mod, "Failed to get sensor thresholds for "
1622208e1562SRob Johnston 		    "node %s (%s)\n", topo_node_name(fnode), ipmi_errmsg(hdl));
1623208e1562SRob Johnston 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1624208e1562SRob Johnston 	}
1625208e1562SRob Johnston 
1626208e1562SRob Johnston 	/*
1627208e1562SRob Johnston 	 * The IPMI Get Sensor Thresholds command returns a bitmask describing
1628208e1562SRob Johnston 	 * which of the 3 upper and lower thresholds are readable.  Iterate
1629208e1562SRob Johnston 	 * through those and create a topo property for each threshold that is
1630208e1562SRob Johnston 	 * readable.
1631208e1562SRob Johnston 	 */
1632208e1562SRob Johnston 	mask = thresh.ithr_readable_mask;
1633208e1562SRob Johnston 	for (i = 0; i < num_thresholds; i++) {
1634208e1562SRob Johnston 		if (!ISBITSET(mask, threshset[i].sthr_threshbit))
1635208e1562SRob Johnston 			continue;
1636208e1562SRob Johnston 
1637208e1562SRob Johnston 		if (set_thresh_prop(mod, fnode, sd->sd_fs_sdr,
1638208e1562SRob Johnston 		    *(uint8_t *)((char *)&thresh +
1639208e1562SRob Johnston 		    threshset[i].sthr_threshoff), &threshset[i]) != 0) {
1640208e1562SRob Johnston 			/* errno set */
1641825ba0f2Srobj 			return (-1);
1642825ba0f2Srobj 		}
1643825ba0f2Srobj 	}
1644825ba0f2Srobj 	return (0);
1645825ba0f2Srobj }
1646825ba0f2Srobj 
16478f022dd6SRob Johnston static boolean_t
seq_search(char * key,char ** list,uint_t nelem)16488f022dd6SRob Johnston seq_search(char *key, char **list, uint_t nelem)
16498f022dd6SRob Johnston {
16508f022dd6SRob Johnston 	for (int i = 0; i < nelem; i++)
16518f022dd6SRob Johnston 		if (strcmp(key, list[i]) == 0)
16528f022dd6SRob Johnston 			return (B_TRUE);
16538f022dd6SRob Johnston 	return (B_FALSE);
16548f022dd6SRob Johnston }
16558f022dd6SRob Johnston 
1656825ba0f2Srobj /* ARGSUSED */
1657825ba0f2Srobj static int
sdr_callback(ipmi_handle_t * hdl,const char * id,ipmi_sdr_t * sdr,void * data)1658825ba0f2Srobj sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data)
1659825ba0f2Srobj {
1660825ba0f2Srobj 	uint8_t sensor_entity, sensor_inst;
1661825ba0f2Srobj 	int sensor_idlen;
1662825ba0f2Srobj 	ipmi_sdr_full_sensor_t *f_sensor = NULL;
1663825ba0f2Srobj 	ipmi_sdr_compact_sensor_t *c_sensor = NULL;
1664825ba0f2Srobj 	struct sensor_data sd;
1665825ba0f2Srobj 	struct entity_info *ei = (struct entity_info *)data;
1666825ba0f2Srobj 
1667825ba0f2Srobj 	switch (sdr->is_type) {
1668825ba0f2Srobj 		case IPMI_SDR_TYPE_FULL_SENSOR:
1669825ba0f2Srobj 			f_sensor =
1670825ba0f2Srobj 			    (ipmi_sdr_full_sensor_t *)sdr->is_record;
1671825ba0f2Srobj 			sensor_entity = f_sensor->is_fs_entity_id;
1672825ba0f2Srobj 			sensor_inst = f_sensor->is_fs_entity_instance;
1673825ba0f2Srobj 			sensor_idlen = f_sensor->is_fs_idlen;
1674825ba0f2Srobj 			(void) strncpy(sd.sd_entity_ref,
1675825ba0f2Srobj 			    f_sensor->is_fs_idstring,
1676825ba0f2Srobj 			    f_sensor->is_fs_idlen);
1677825ba0f2Srobj 			sd.sd_entity_ref[sensor_idlen] = '\0';
1678825ba0f2Srobj 			sd.sd_units = f_sensor->is_fs_unit2;
1679825ba0f2Srobj 			sd.sd_stype = f_sensor->is_fs_type;
1680825ba0f2Srobj 			sd.sd_rtype = f_sensor->is_fs_reading_type;
1681208e1562SRob Johnston 			sd.sd_fs_sdr = f_sensor;
1682825ba0f2Srobj 			break;
1683825ba0f2Srobj 		case IPMI_SDR_TYPE_COMPACT_SENSOR:
1684825ba0f2Srobj 			c_sensor =
1685825ba0f2Srobj 			    (ipmi_sdr_compact_sensor_t *)sdr->is_record;
1686825ba0f2Srobj 			sensor_entity = c_sensor->is_cs_entity_id;
1687825ba0f2Srobj 			sensor_inst = c_sensor->is_cs_entity_instance;
1688825ba0f2Srobj 			sensor_idlen = c_sensor->is_cs_idlen;
1689825ba0f2Srobj 			(void) strncpy(sd.sd_entity_ref,
1690825ba0f2Srobj 			    c_sensor->is_cs_idstring,
1691825ba0f2Srobj 			    sensor_idlen);
1692825ba0f2Srobj 			sd.sd_entity_ref[sensor_idlen] = '\0';
1693825ba0f2Srobj 			sd.sd_units = c_sensor->is_cs_unit2;
1694825ba0f2Srobj 			sd.sd_stype = c_sensor->is_cs_type;
1695825ba0f2Srobj 			sd.sd_rtype = c_sensor->is_cs_reading_type;
1696208e1562SRob Johnston 			sd.sd_fs_sdr = NULL;
1697825ba0f2Srobj 			break;
1698825ba0f2Srobj 		default:
1699825ba0f2Srobj 			return (0);
1700825ba0f2Srobj 	}
170188045cffSRobert Johnston 	if (sd.sd_rtype == IPMI_RT_THRESHOLD)
170288045cffSRobert Johnston 		sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD;
170388045cffSRobert Johnston 	else
170488045cffSRobert Johnston 		sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE;
170588045cffSRobert Johnston 
1706825ba0f2Srobj 	/*
1707825ba0f2Srobj 	 * We offset the threshold and generic sensor reading types by 0x100
1708825ba0f2Srobj 	 */
1709825ba0f2Srobj 	if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc)
1710825ba0f2Srobj 		sd.sd_stype = sd.sd_rtype + 0x100;
1711825ba0f2Srobj 
17128f022dd6SRob Johnston 	if ((ei->ei_list != NULL && seq_search(sd.sd_entity_ref,
17138f022dd6SRob Johnston 	    ei->ei_list, ei->ei_listsz) == B_TRUE) ||
17148f022dd6SRob Johnston 	    (sensor_entity == ei->ei_id && sensor_inst == ei->ei_inst)) {
17158f022dd6SRob Johnston 
1716208e1562SRob Johnston 		if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd, hdl) != 0) {
1717825ba0f2Srobj 			topo_mod_dprintf(ei->ei_mod, "Failed to create sensor "
1718825ba0f2Srobj 			    "node for %s\n", sd.sd_entity_ref);
1719825ba0f2Srobj 			if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP)
1720825ba0f2Srobj 				return (-1);
1721825ba0f2Srobj 		}
17228f022dd6SRob Johnston 	}
1723825ba0f2Srobj 	return (0);
1724825ba0f2Srobj }
1725825ba0f2Srobj 
1726825ba0f2Srobj static int
get_entity_info(topo_mod_t * mod,tnode_t * node,ipmi_handle_t * hdl,struct entity_info * ei)17278f022dd6SRob Johnston get_entity_info(topo_mod_t *mod, tnode_t *node, ipmi_handle_t *hdl,
17288f022dd6SRob Johnston     struct entity_info *ei)
1729825ba0f2Srobj {
173088045cffSRobert Johnston 	char **entity_refs;
1731825ba0f2Srobj 	int err;
173288045cffSRobert Johnston 	uint_t nelems;
1733825ba0f2Srobj 	ipmi_sdr_t *ref_sdr;
1734825ba0f2Srobj 	ipmi_sdr_full_sensor_t *fsensor;
1735825ba0f2Srobj 	ipmi_sdr_compact_sensor_t *csensor;
1736825ba0f2Srobj 	ipmi_sdr_fru_locator_t *floc;
1737825ba0f2Srobj 	ipmi_sdr_generic_locator_t *gloc;
173888045cffSRobert Johnston 	boolean_t found_sdr = B_FALSE;
1739825ba0f2Srobj 
1740825ba0f2Srobj 	/*
1741825ba0f2Srobj 	 * Use the entity ref to lookup the SDR, which will have the entity ID
1742825ba0f2Srobj 	 * and instance.
1743825ba0f2Srobj 	 */
174488045cffSRobert Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI,
174588045cffSRobert Johnston 	    "entity_ref", &entity_refs, &nelems, &err) != 0) {
174688045cffSRobert Johnston 		topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
1747*6597d6fcSRobert Mustacchi 		    "property on %s=%" PRIu64 " (%s)\n", __func__,
1748*6597d6fcSRobert Mustacchi 		    topo_node_name(node), topo_node_instance(node),
1749*6597d6fcSRobert Mustacchi 		    topo_strerror(err));
17500b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
1751825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1752825ba0f2Srobj 	}
1753825ba0f2Srobj 
175488045cffSRobert Johnston 	for (int i = 0; i < nelems; i++) {
175588045cffSRobert Johnston 		if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_refs[i])) != NULL) {
175688045cffSRobert Johnston 			found_sdr = B_TRUE;
175788045cffSRobert Johnston 			break;
175888045cffSRobert Johnston 		} else
175988045cffSRobert Johnston 			topo_mod_dprintf(mod, "%s: Failed to lookup SDR for %s "
176088045cffSRobert Johnston 			    "(%s)\n", __func__, entity_refs[i],
176188045cffSRobert Johnston 			    ipmi_errmsg(hdl));
176288045cffSRobert Johnston 	}
1763e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
176488045cffSRobert Johnston 	if (! found_sdr) {
17650b1b4412SEric Schrock 		topo_mod_ipmi_rele(mod);
176688045cffSRobert Johnston 		return (-1);
1767825ba0f2Srobj 	}
1768825ba0f2Srobj 
1769825ba0f2Srobj 	switch (ref_sdr->is_type) {
1770825ba0f2Srobj 		case IPMI_SDR_TYPE_FULL_SENSOR:
1771825ba0f2Srobj 			fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record;
17728f022dd6SRob Johnston 			ei->ei_id = fsensor->is_fs_entity_id;
17738f022dd6SRob Johnston 			ei->ei_inst = fsensor->is_fs_entity_instance;
1774825ba0f2Srobj 			break;
1775825ba0f2Srobj 		case IPMI_SDR_TYPE_COMPACT_SENSOR:
1776825ba0f2Srobj 			csensor
1777825ba0f2Srobj 			    = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record;
17788f022dd6SRob Johnston 			ei->ei_id = csensor->is_cs_entity_id;
17798f022dd6SRob Johnston 			ei->ei_inst = csensor->is_cs_entity_instance;
1780825ba0f2Srobj 			break;
1781825ba0f2Srobj 		case IPMI_SDR_TYPE_FRU_LOCATOR:
1782825ba0f2Srobj 			floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record;
17838f022dd6SRob Johnston 			ei->ei_id = floc->is_fl_entity;
17848f022dd6SRob Johnston 			ei->ei_inst = floc->is_fl_instance;
1785825ba0f2Srobj 			break;
1786825ba0f2Srobj 		case IPMI_SDR_TYPE_GENERIC_LOCATOR:
1787825ba0f2Srobj 			gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record;
17888f022dd6SRob Johnston 			ei->ei_id = gloc->is_gl_entity;
17898f022dd6SRob Johnston 			ei->ei_inst = gloc->is_gl_instance;
1790825ba0f2Srobj 			break;
1791825ba0f2Srobj 		default:
1792825ba0f2Srobj 			topo_mod_dprintf(mod, "Failed to determine entity id "
1793*6597d6fcSRobert Mustacchi 			    "and instance: %s\n", ipmi_errmsg(hdl));
17940b1b4412SEric Schrock 			topo_mod_ipmi_rele(mod);
1795825ba0f2Srobj 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1796825ba0f2Srobj 	}
17978f022dd6SRob Johnston 	return (0);
17988f022dd6SRob Johnston }
17998f022dd6SRob Johnston 
18008f022dd6SRob Johnston /* ARGSUSED */
18018f022dd6SRob Johnston static int
ipmi_sensor_enum(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)18028f022dd6SRob Johnston ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
18038f022dd6SRob Johnston     nvlist_t *in, nvlist_t **out)
18048f022dd6SRob Johnston {
18058f022dd6SRob Johnston 	int err, ret = -1;
18068f022dd6SRob Johnston 	struct entity_info ei = {0};
18078f022dd6SRob Johnston 	ipmi_handle_t *hdl;
18088f022dd6SRob Johnston 
18098f022dd6SRob Johnston 	if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
18108f022dd6SRob Johnston 		topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
18118f022dd6SRob Johnston 		return (-1);
18128f022dd6SRob Johnston 	}
18138f022dd6SRob Johnston 
18148f022dd6SRob Johnston 	/*
18158f022dd6SRob Johnston 	 * For cases where the records in the SDR are hopelessly broken, then
18168f022dd6SRob Johnston 	 * we'll resort to hardcoding a list of sensor entities that should be
18178f022dd6SRob Johnston 	 * bound to this particular node.  Otherwise, we'll first check if the
18188f022dd6SRob Johnston 	 * properties for the associated IPMI entity id and instance exist.  If
18198f022dd6SRob Johnston 	 * not, we check for a property referencing an IPMI entity name on which
18208f022dd6SRob Johnston 	 * we can lookup the entity ID and instance.  If none of the above pans
18218f022dd6SRob Johnston 	 * out, then we bail out.
18228f022dd6SRob Johnston 	 */
18238f022dd6SRob Johnston 	if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI,
18248f022dd6SRob Johnston 	    TOPO_PROP_IPMI_ENTITY_LIST, &ei.ei_list, &ei.ei_listsz, &err)
18258f022dd6SRob Johnston 	    != 0 && (topo_prop_get_uint32(node, TOPO_PGROUP_IPMI,
18268f022dd6SRob Johnston 	    TOPO_PROP_IPMI_ENTITY_ID, &ei.ei_id, &err) != 0 ||
18278f022dd6SRob Johnston 	    topo_prop_get_uint32(node, TOPO_PGROUP_IPMI,
18288f022dd6SRob Johnston 	    TOPO_PROP_IPMI_ENTITY_INST, &ei.ei_inst, &err) != 0)) {
18298f022dd6SRob Johnston 		if (get_entity_info(mod, node, hdl, &ei) != 0)
18308f022dd6SRob Johnston 			goto out;
18318f022dd6SRob Johnston 	}
1832825ba0f2Srobj 	ei.ei_node = node;
1833825ba0f2Srobj 	ei.ei_mod = mod;
1834825ba0f2Srobj 
1835825ba0f2Srobj 	/*
1836825ba0f2Srobj 	 * Now iterate through all of the full and compact sensor data records
1837825ba0f2Srobj 	 * and create a sensor facility node for each record that matches our
1838825ba0f2Srobj 	 * entity ID and instance
1839825ba0f2Srobj 	 */
18408f022dd6SRob Johnston 	if ((ret = ipmi_sdr_iter(hdl, sdr_callback, &ei)) != 0) {
1841825ba0f2Srobj 		topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n");
1842825ba0f2Srobj 	}
18438f022dd6SRob Johnston out:
18440b1b4412SEric Schrock 	topo_mod_ipmi_rele(mod);
18458f022dd6SRob Johnston 	if (ei.ei_list != NULL)
1846e2336878SRob Johnston 		topo_mod_strfreev(mod, ei.ei_list, ei.ei_listsz);
18470b1b4412SEric Schrock 
18488f022dd6SRob Johnston 	return (ret);
1849825ba0f2Srobj }
1850825ba0f2Srobj 
1851825ba0f2Srobj static int
ipmi_entity(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1852825ba0f2Srobj ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1853825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
1854825ba0f2Srobj {
185588045cffSRobert Johnston 	char **fmtarr, **entity_refs, buf[BUFSZ];
1856825ba0f2Srobj 	tnode_t *refnode;
185788045cffSRobert Johnston 	uint_t nelems;
1858825ba0f2Srobj 	int ret, inst1, inst2;
1859825ba0f2Srobj 	uint32_t offset, nparams;
1860825ba0f2Srobj 	nvlist_t *args, *nvl;
1861825ba0f2Srobj 
1862825ba0f2Srobj 	if (vers > TOPO_METH_IPMI_ENTITY_VERSION)
1863825ba0f2Srobj 		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1864825ba0f2Srobj 
1865825ba0f2Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1866825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1867825ba0f2Srobj 		    strerror(ret));
1868825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1869825ba0f2Srobj 	}
1870825ba0f2Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1871825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1872825ba0f2Srobj 		    strerror(ret));
1873825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1874825ba0f2Srobj 	}
1875825ba0f2Srobj 	if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) {
1876825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n",
1877825ba0f2Srobj 		    strerror(ret));
1878825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1879825ba0f2Srobj 	}
188088045cffSRobert Johnston 	if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
188188045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
188288045cffSRobert Johnston 		    strerror(errno));
188388045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1884825ba0f2Srobj 	}
1885825ba0f2Srobj 
188688045cffSRobert Johnston 	if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
188788045cffSRobert Johnston 	    == NULL)
188888045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
188988045cffSRobert Johnston 
1890825ba0f2Srobj 	if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1891825ba0f2Srobj 		refnode = topo_node_parent(node);
1892825ba0f2Srobj 	else
1893825ba0f2Srobj 		refnode = node;
1894825ba0f2Srobj 
189588045cffSRobert Johnston 	for (int i = 0; i < nelems; i++) {
189688045cffSRobert Johnston 		switch (nparams) {
189788045cffSRobert Johnston 		case 1:
189888045cffSRobert Johnston 			/* LINTED: E_SEC_PRINTF_VAR_FMT */
189988045cffSRobert Johnston 			(void) snprintf(buf, BUFSZ, fmtarr[i],
190088045cffSRobert Johnston 			    (topo_node_instance(refnode) + offset));
190188045cffSRobert Johnston 			break;
190288045cffSRobert Johnston 		case 2:
190388045cffSRobert Johnston 			inst1 = topo_node_instance(topo_node_parent(refnode))
190488045cffSRobert Johnston 			    + offset;
190588045cffSRobert Johnston 			inst2 = topo_node_instance(refnode) + offset;
190688045cffSRobert Johnston 			/* LINTED: E_SEC_PRINTF_VAR_FMT */
190788045cffSRobert Johnston 			(void) snprintf(buf, BUFSZ, fmtarr[i], inst1, inst2);
190888045cffSRobert Johnston 			break;
190988045cffSRobert Johnston 		default:
191088045cffSRobert Johnston 			topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n",
191188045cffSRobert Johnston 			    nparams);
1912e2336878SRob Johnston 			topo_mod_strfreev(mod, entity_refs, nelems);
191388045cffSRobert Johnston 			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
191488045cffSRobert Johnston 		}
191588045cffSRobert Johnston 		entity_refs[i] = topo_mod_strdup(mod, buf);
1916825ba0f2Srobj 	}
1917825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1918825ba0f2Srobj 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
191988045cffSRobert Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
192088045cffSRobert Johnston 	    TOPO_TYPE_STRING_ARRAY) != 0 ||
192188045cffSRobert Johnston 	    nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs,
192288045cffSRobert Johnston 	    nelems) != 0) {
192388045cffSRobert Johnston 
1924825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1925e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
1926825ba0f2Srobj 		nvlist_free(nvl);
1927825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
1928825ba0f2Srobj 	}
1929e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
1930825ba0f2Srobj 	*out = nvl;
1931825ba0f2Srobj 
1932825ba0f2Srobj 	return (0);
1933825ba0f2Srobj }
1934825ba0f2Srobj 
1935825ba0f2Srobj /* ARGSUSED */
1936825ba0f2Srobj static int
dimm_ipmi_entity(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1937825ba0f2Srobj dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1938825ba0f2Srobj     nvlist_t *in, nvlist_t **out)
1939825ba0f2Srobj {
194088045cffSRobert Johnston 	char **fmtarr, **entity_refs, buf[BUFSZ];
1941825ba0f2Srobj 	tnode_t *chip, *dimm;
1942825ba0f2Srobj 	int ret;
194388045cffSRobert Johnston 	uint_t nelems;
1944825ba0f2Srobj 	uint32_t offset;
1945825ba0f2Srobj 	nvlist_t *args, *nvl;
1946825ba0f2Srobj 
1947825ba0f2Srobj 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1948825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1949825ba0f2Srobj 		    strerror(ret));
1950825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1951825ba0f2Srobj 	}
1952825ba0f2Srobj 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1953825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1954825ba0f2Srobj 		    strerror(ret));
1955825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1956825ba0f2Srobj 	}
195788045cffSRobert Johnston 	if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
195888045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
195988045cffSRobert Johnston 		    strerror(errno));
196088045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1961825ba0f2Srobj 	}
1962825ba0f2Srobj 
196388045cffSRobert Johnston 	if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
196488045cffSRobert Johnston 	    == NULL)
196588045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
196688045cffSRobert Johnston 
1967825ba0f2Srobj 	if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1968825ba0f2Srobj 		dimm = topo_node_parent(node);
1969825ba0f2Srobj 	else
1970825ba0f2Srobj 		dimm = node;
1971825ba0f2Srobj 
1972825ba0f2Srobj 	chip = topo_node_parent(topo_node_parent(dimm));
1973825ba0f2Srobj 
197488045cffSRobert Johnston 	for (int i = 0; i < nelems; i++) {
197588045cffSRobert Johnston 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
197688045cffSRobert Johnston 		(void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
197788045cffSRobert Johnston 		    (topo_node_instance(dimm) + offset));
197888045cffSRobert Johnston 		entity_refs[i] = topo_mod_strdup(mod, buf);
197988045cffSRobert Johnston 	}
1980825ba0f2Srobj 
1981825ba0f2Srobj 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1982825ba0f2Srobj 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
198388045cffSRobert Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
198488045cffSRobert Johnston 	    TOPO_TYPE_STRING_ARRAY) != 0 ||
198588045cffSRobert Johnston 	    nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
198688045cffSRobert Johnston 	    != 0) {
198788045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1988e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
198988045cffSRobert Johnston 		nvlist_free(nvl);
199088045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
199188045cffSRobert Johnston 	}
1992e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
199388045cffSRobert Johnston 	*out = nvl;
199488045cffSRobert Johnston 
199588045cffSRobert Johnston 	return (0);
199688045cffSRobert Johnston }
199788045cffSRobert Johnston 
199888045cffSRobert Johnston /* ARGSUSED */
199988045cffSRobert Johnston static int
cs_ipmi_entity(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)200088045cffSRobert Johnston cs_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
200188045cffSRobert Johnston     nvlist_t *in, nvlist_t **out)
200288045cffSRobert Johnston {
200388045cffSRobert Johnston 	char **fmtarr, **entity_refs, buf[BUFSZ];
200488045cffSRobert Johnston 	tnode_t *chip, *chan, *cs;
200588045cffSRobert Johnston 	int ret, dimm_num;
200688045cffSRobert Johnston 	uint_t nelems;
200788045cffSRobert Johnston 	uint32_t offset;
200888045cffSRobert Johnston 	nvlist_t *args, *nvl;
200988045cffSRobert Johnston 
201088045cffSRobert Johnston 	if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
201188045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
201288045cffSRobert Johnston 		    strerror(ret));
201388045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
201488045cffSRobert Johnston 	}
201588045cffSRobert Johnston 	if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
201688045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
201788045cffSRobert Johnston 		    strerror(ret));
201888045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
201988045cffSRobert Johnston 	}
202088045cffSRobert Johnston 	if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
202188045cffSRobert Johnston 		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
202288045cffSRobert Johnston 		    strerror(errno));
202388045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
202488045cffSRobert Johnston 	}
202588045cffSRobert Johnston 
202688045cffSRobert Johnston 	if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
202788045cffSRobert Johnston 	    == NULL)
202888045cffSRobert Johnston 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
202988045cffSRobert Johnston 
203088045cffSRobert Johnston 	if (topo_node_flags(node) & TOPO_NODE_FACILITY) {
203188045cffSRobert Johnston 		cs = topo_node_parent(node);
203288045cffSRobert Johnston 		chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
203388045cffSRobert Johnston 		chan = topo_node_parent(cs);
203488045cffSRobert Johnston 
203588045cffSRobert Johnston 		dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
203688045cffSRobert Johnston 		    + topo_node_instance(cs) + offset;
203788045cffSRobert Johnston 	} else {
203888045cffSRobert Johnston 		cs = node;
203988045cffSRobert Johnston 		chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
204088045cffSRobert Johnston 		chan = topo_node_parent(cs);
204188045cffSRobert Johnston 
204288045cffSRobert Johnston 		dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
204388045cffSRobert Johnston 		    + topo_node_instance(chan) + offset;
204488045cffSRobert Johnston 	}
204588045cffSRobert Johnston 
204688045cffSRobert Johnston 	for (int i = 0; i < nelems; i++) {
204788045cffSRobert Johnston 		/* LINTED: E_SEC_PRINTF_VAR_FMT */
204888045cffSRobert Johnston 		(void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
204988045cffSRobert Johnston 		    dimm_num);
205088045cffSRobert Johnston 		entity_refs[i] = topo_mod_strdup(mod, buf);
205188045cffSRobert Johnston 	}
205288045cffSRobert Johnston 
205388045cffSRobert Johnston 	if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
205488045cffSRobert Johnston 	    nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
205588045cffSRobert Johnston 	    nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
205688045cffSRobert Johnston 	    TOPO_TYPE_STRING_ARRAY) != 0 ||
205788045cffSRobert Johnston 	    nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
205888045cffSRobert Johnston 	    != 0) {
2059825ba0f2Srobj 		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
2060e2336878SRob Johnston 		topo_mod_strfreev(mod, entity_refs, nelems);
2061825ba0f2Srobj 		nvlist_free(nvl);
2062825ba0f2Srobj 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
2063825ba0f2Srobj 	}
2064e2336878SRob Johnston 	topo_mod_strfreev(mod, entity_refs, nelems);
2065825ba0f2Srobj 	*out = nvl;
2066825ba0f2Srobj 
2067825ba0f2Srobj 	return (0);
2068825ba0f2Srobj }
2069825ba0f2Srobj 
2070825ba0f2Srobj /*ARGSUSED*/
2071825ba0f2Srobj static int
fac_prov_ipmi_enum(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * unused)2072825ba0f2Srobj fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
2073825ba0f2Srobj     topo_instance_t min, topo_instance_t max, void *arg, void *unused)
2074825ba0f2Srobj {
2075825ba0f2Srobj 	topo_pgroup_info_t pgi;
2076825ba0f2Srobj 	int err;
2077825ba0f2Srobj 
2078825ba0f2Srobj 	if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) {
2079825ba0f2Srobj 		pgi.tpi_name = TOPO_PGROUP_IPMI;
2080825ba0f2Srobj 		pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
2081825ba0f2Srobj 		pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
2082825ba0f2Srobj 		pgi.tpi_version = 1;
2083825ba0f2Srobj 		if (topo_pgroup_create(rnode, &pgi, &err) != 0) {
2084825ba0f2Srobj 			if (err != ETOPO_PROP_DEFD) {
2085825ba0f2Srobj 				topo_mod_dprintf(mod,
2086825ba0f2Srobj 				    "pgroups create failure: %s\n",
2087825ba0f2Srobj 				    topo_strerror(err));
2088825ba0f2Srobj 				return (-1);
2089825ba0f2Srobj 			}
2090825ba0f2Srobj 		}
2091825ba0f2Srobj 		if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) {
2092825ba0f2Srobj 			topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
2093825ba0f2Srobj 			    "topo_method_register() failed: %s",
2094825ba0f2Srobj 			    topo_mod_errmsg(mod));
2095825ba0f2Srobj 			return (-1);
2096825ba0f2Srobj 		}
2097825ba0f2Srobj 	} else {
2098825ba0f2Srobj 		if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) {
2099825ba0f2Srobj 			topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
2100825ba0f2Srobj 			    "topo_method_register() failed: %s",
2101825ba0f2Srobj 			    topo_mod_errmsg(mod));
2102825ba0f2Srobj 			return (-1);
2103825ba0f2Srobj 		}
2104825ba0f2Srobj 	}
2105825ba0f2Srobj 	return (0);
2106825ba0f2Srobj }
2107