1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * Copyright 2019 Joyent, Inc.
27 * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
28 */
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <limits.h>
35 #include <alloca.h>
36 #include <errno.h>
37 #include <libnvpair.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/fm/protocol.h>
41 #include <fm/libtopo.h>
42 #include <fm/topo_mod.h>
43 #include <libipmi.h>
44
45 #define BUFSZ 128
46
47 #define BAY_PRESENT_LED_MASK 0x01
48
49 /*
50 * The largest possible SDR ID length is 2^5+1
51 */
52 #define MAX_ID_LEN 33
53
54 #define TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION 0
55 #define TOPO_METH_IPMI_READING_VERSION 0
56 #define TOPO_METH_IPMI_STATE_VERSION 0
57 #define TOPO_METH_IPMI_MODE_VERSION 0
58 #define TOPO_METH_X4500_MODE_VERSION 0
59 #define TOPO_METH_BAY_LOCATE_VERSION 0
60 #define TOPO_METH_BAY_MODE_VERSION 0
61 #define TOPO_METH_CHASSIS_SERVICE_VERSION 0
62 #define TOPO_METH_IPMI_ENTITY_VERSION 0
63 #define TOPO_METH_DIMM_IPMI_ENTITY_VERSION 0
64 #define TOPO_METH_CHASSIS_IDENT_VERSION 0
65
66 static int fac_prov_ipmi_enum(topo_mod_t *, tnode_t *, const char *,
67 topo_instance_t, topo_instance_t, void *, void *);
68
69 /*
70 * IPMI facility provider methods
71 */
72 static int ipmi_sensor_enum(topo_mod_t *, tnode_t *, topo_version_t,
73 nvlist_t *, nvlist_t **);
74 static int ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
75 nvlist_t **);
76 static int dimm_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
77 nvlist_t **);
78 static int cs_ipmi_entity(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
79 nvlist_t **);
80 static int ipmi_platform_message(topo_mod_t *, tnode_t *, topo_version_t,
81 nvlist_t *, nvlist_t **);
82 static int ipmi_sensor_reading(topo_mod_t *, tnode_t *, topo_version_t,
83 nvlist_t *, nvlist_t **);
84 static int ipmi_sensor_state(topo_mod_t *, tnode_t *, topo_version_t,
85 nvlist_t *, nvlist_t **);
86 static int ipmi_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
87 nvlist_t *, nvlist_t **);
88 static int bay_locate_mode(topo_mod_t *, tnode_t *, topo_version_t,
89 nvlist_t *, nvlist_t **);
90 static int x4500_present_mode(topo_mod_t *, tnode_t *, topo_version_t,
91 nvlist_t *, nvlist_t **);
92 static int bay_indicator_mode(topo_mod_t *, tnode_t *, topo_version_t,
93 nvlist_t *, nvlist_t **);
94 static int chassis_service_mode(topo_mod_t *, tnode_t *, topo_version_t,
95 nvlist_t *, nvlist_t **);
96 static int chassis_ident_mode(topo_mod_t *, tnode_t *, topo_version_t,
97 nvlist_t *, nvlist_t **);
98
99 const topo_modops_t ipmi_ops = { fac_prov_ipmi_enum, NULL };
100
101 const topo_modinfo_t ipmi_info =
102 { "IPMI facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION,
103 &ipmi_ops };
104
105 static const topo_method_t ipmi_node_methods[] = {
106 { TOPO_METH_FAC_ENUM, TOPO_METH_FAC_ENUM_DESC, 0,
107 TOPO_STABILITY_INTERNAL, ipmi_sensor_enum },
108 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
109 TOPO_METH_IPMI_ENTITY_VERSION,
110 TOPO_STABILITY_INTERNAL, ipmi_entity },
111 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
112 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
113 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
114 { "cs_ipmi_entity", TOPO_PROP_METH_DESC,
115 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
116 TOPO_STABILITY_INTERNAL, cs_ipmi_entity },
117 { TOPO_METH_SENSOR_FAILURE, TOPO_METH_SENSOR_FAILURE_DESC,
118 TOPO_METH_SENSOR_FAILURE_VERSION, TOPO_STABILITY_INTERNAL,
119 topo_method_sensor_failure },
120 { NULL }
121 };
122
123 static const topo_method_t ipmi_fac_methods[] = {
124 { "ipmi_platform_message", TOPO_PROP_METH_DESC,
125 TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION,
126 TOPO_STABILITY_INTERNAL, ipmi_platform_message },
127 { "ipmi_sensor_reading", TOPO_PROP_METH_DESC,
128 TOPO_METH_IPMI_READING_VERSION,
129 TOPO_STABILITY_INTERNAL, ipmi_sensor_reading },
130 { "ipmi_sensor_state", TOPO_PROP_METH_DESC,
131 TOPO_METH_IPMI_STATE_VERSION,
132 TOPO_STABILITY_INTERNAL, ipmi_sensor_state },
133 { "ipmi_indicator_mode", TOPO_PROP_METH_DESC,
134 TOPO_METH_IPMI_MODE_VERSION,
135 TOPO_STABILITY_INTERNAL, ipmi_indicator_mode },
136 { "bay_locate_mode", TOPO_PROP_METH_DESC,
137 TOPO_METH_BAY_LOCATE_VERSION,
138 TOPO_STABILITY_INTERNAL, bay_locate_mode },
139 { "bay_indicator_mode", TOPO_PROP_METH_DESC,
140 TOPO_METH_BAY_MODE_VERSION,
141 TOPO_STABILITY_INTERNAL, bay_indicator_mode },
142 { "chassis_service_mode", TOPO_PROP_METH_DESC,
143 TOPO_METH_CHASSIS_SERVICE_VERSION,
144 TOPO_STABILITY_INTERNAL, chassis_service_mode },
145 { "chassis_ident_mode", TOPO_PROP_METH_DESC,
146 TOPO_METH_CHASSIS_SERVICE_VERSION,
147 TOPO_STABILITY_INTERNAL, chassis_ident_mode },
148 { "x4500_present_mode", TOPO_PROP_METH_DESC,
149 TOPO_METH_CHASSIS_SERVICE_VERSION,
150 TOPO_STABILITY_INTERNAL, x4500_present_mode },
151 { TOPO_METH_IPMI_ENTITY, TOPO_PROP_METH_DESC,
152 TOPO_METH_IPMI_ENTITY_VERSION,
153 TOPO_STABILITY_INTERNAL, ipmi_entity },
154 { "dimm_ipmi_entity", TOPO_PROP_METH_DESC,
155 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
156 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
157 { "cs_ipmi_entity", TOPO_PROP_METH_DESC,
158 TOPO_METH_DIMM_IPMI_ENTITY_VERSION,
159 TOPO_STABILITY_INTERNAL, dimm_ipmi_entity },
160 { NULL }
161 };
162
163 struct entity_info {
164 uint32_t ei_id;
165 uint32_t ei_inst;
166 topo_mod_t *ei_mod;
167 tnode_t *ei_node;
168 char **ei_list;
169 uint_t ei_listsz;
170 };
171
172 struct sensor_data {
173 char sd_entity_ref[MAX_ID_LEN];
174 uint8_t sd_units;
175 uint32_t sd_stype;
176 uint32_t sd_rtype;
177 char *sd_class;
178 ipmi_sdr_full_sensor_t *sd_fs_sdr;
179 };
180
181 /*ARGSUSED*/
182 int
_topo_init(topo_mod_t * mod,topo_version_t version)183 _topo_init(topo_mod_t *mod, topo_version_t version)
184 {
185 if (getenv("TOPOFACIPMIDEBUG") != NULL)
186 topo_mod_setdebug(mod);
187
188 return (topo_mod_register(mod, &ipmi_info, TOPO_VERSION));
189 }
190
191 void
_topo_fini(topo_mod_t * mod)192 _topo_fini(topo_mod_t *mod)
193 {
194 topo_mod_unregister(mod);
195 }
196
197 /*
198 * Some platforms (most notably G1/2N) use the 'platform event message' command
199 * to manipulate disk fault LEDs over IPMI, but uses the standard sensor
200 * reading to read the value. This method implements this alternative
201 * interface for these platforms.
202 */
203 /*ARGSUSED*/
204 static int
ipmi_platform_message(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)205 ipmi_platform_message(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
206 nvlist_t *in, nvlist_t **out)
207 {
208 char *entity_ref;
209 ipmi_sdr_compact_sensor_t *csp;
210 ipmi_handle_t *hdl;
211 int err, ret;
212 uint32_t mode;
213 nvlist_t *pargs, *nvl;
214 ipmi_platform_event_message_t pem;
215 ipmi_sensor_reading_t *reading;
216
217 if (vers > TOPO_METH_IPMI_PLATFORM_MESSAGE_VERSION)
218 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
219
220 /*
221 * Get an IPMI handle and then lookup the generic device locator sensor
222 * data record referenced by the entity_ref prop val
223 */
224 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
225 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
226 return (-1);
227 }
228
229 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, "entity_ref",
230 &entity_ref, &err) != 0) {
231 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
232 "(%s)", topo_strerror(err));
233 topo_mod_ipmi_rele(mod);
234 return (-1);
235 }
236
237 if ((csp = ipmi_sdr_lookup_compact_sensor(hdl, entity_ref)) == NULL) {
238 topo_mod_dprintf(mod, "Failed to lookup SDR for %s (%s)\n",
239 entity_ref, ipmi_errmsg(hdl));
240 topo_mod_strfree(mod, entity_ref);
241 topo_mod_ipmi_rele(mod);
242 return (-1);
243 }
244
245 /*
246 * Now look for a private argument list to figure out whether we're
247 * doing a get or a set operation, and then do it.
248 */
249 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
250 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
251 /*
252 * Set the LED mode
253 */
254 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
255 &mode)) != 0) {
256 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
257 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
258 topo_mod_strfree(mod, entity_ref);
259 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
260 topo_mod_ipmi_rele(mod);
261 return (-1);
262 }
263
264 if (mode != TOPO_LED_STATE_OFF &&
265 mode != TOPO_LED_STATE_ON) {
266 topo_mod_dprintf(mod, "Invalid property value: %d\n",
267 mode);
268 topo_mod_strfree(mod, entity_ref);
269 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
270 topo_mod_ipmi_rele(mod);
271 return (-1);
272 }
273
274 pem.ipem_sensor_type = csp->is_cs_type;
275 pem.ipem_sensor_num = csp->is_cs_number;
276 pem.ipem_event_type = csp->is_cs_reading_type;
277
278 /*
279 * The spec states that any values between 0x20 and 0x29 are
280 * legitimate for "system software". However, some versions of
281 * Sun's ILOM rejects messages over /dev/ipmi0 with a generator
282 * of 0x20, so we use 0x21 instead.
283 */
284 pem.ipem_generator = 0x21;
285 pem.ipem_event_dir = 0;
286 pem.ipem_rev = 0x04;
287 if (mode == TOPO_LED_STATE_ON)
288 pem.ipem_event_data[0] = 1;
289 else
290 pem.ipem_event_data[0] = 0;
291 pem.ipem_event_data[1] = 0xff;
292 pem.ipem_event_data[2] = 0xff;
293
294 if (ipmi_event_platform_message(hdl, &pem) < 0) {
295 topo_mod_dprintf(mod, "Failed to set LED mode for %s "
296 "(%s)\n", entity_ref, ipmi_errmsg(hdl));
297 topo_mod_strfree(mod, entity_ref);
298 topo_mod_ipmi_rele(mod);
299 return (-1);
300 }
301 } else {
302 /*
303 * Get the LED mode
304 */
305 if ((reading = ipmi_get_sensor_reading(hdl, csp->is_cs_number))
306 == NULL) {
307 topo_mod_dprintf(mod, "Failed to get sensor reading "
308 "for sensor %s: %s\n", entity_ref,
309 ipmi_errmsg(hdl));
310 topo_mod_strfree(mod, entity_ref);
311 topo_mod_ipmi_rele(mod);
312 return (-1);
313 }
314
315 if (reading->isr_state &
316 TOPO_SENSOR_STATE_GENERIC_STATE_ASSERTED)
317 mode = TOPO_LED_STATE_ON;
318 else
319 mode = TOPO_LED_STATE_OFF;
320 }
321 topo_mod_strfree(mod, entity_ref);
322
323 topo_mod_ipmi_rele(mod);
324
325 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
326 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
327 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
328 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, mode) != 0) {
329 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
330 nvlist_free(nvl);
331 return (topo_mod_seterrno(mod, EMOD_NOMEM));
332 }
333 *out = nvl;
334
335 return (0);
336 }
337
338 /*ARGSUSED*/
339 static int
ipmi_sensor_state(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)340 ipmi_sensor_state(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
341 nvlist_t *in, nvlist_t **out)
342 {
343 char **entity_refs, *sensor_class;
344 uint_t nelems;
345 ipmi_sdr_t *sdr = NULL;
346 ipmi_sensor_reading_t *reading;
347 ipmi_handle_t *hdl;
348 int err, i;
349 uint8_t sensor_num;
350 uint32_t e_id, e_inst, state;
351 ipmi_sdr_full_sensor_t *fsensor;
352 ipmi_sdr_compact_sensor_t *csensor;
353 nvlist_t *nvl;
354 boolean_t found_sdr = B_FALSE;
355 tnode_t *pnode;
356
357 if (vers > TOPO_METH_IPMI_STATE_VERSION)
358 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
359
360 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
361 &entity_refs, &nelems, &err) != 0) {
362 topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
363 "property (%s)", __func__, topo_strerror(err));
364 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
365 }
366
367 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
368 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
369 topo_mod_strfreev(mod, entity_refs, nelems);
370 return (-1);
371 }
372
373 pnode = topo_node_parent(node);
374 if (topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
375 TOPO_PROP_IPMI_ENTITY_ID, &e_id, &err) != 0 ||
376 topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
377 TOPO_PROP_IPMI_ENTITY_INST, &e_inst, &err) != 0) {
378 e_id = IPMI_ET_UNSPECIFIED;
379 e_inst = 0;
380 }
381
382 for (i = 0; i < nelems; i++) {
383 if ((sdr = ipmi_sdr_lookup_precise(hdl, entity_refs[i],
384 (uint8_t)e_id, (uint8_t)e_inst)) != NULL) {
385 found_sdr = B_TRUE;
386 break;
387 } else
388 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
389 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
390 }
391
392 if (! found_sdr) {
393 topo_mod_strfreev(mod, entity_refs, nelems);
394 topo_mod_ipmi_rele(mod);
395 return (-1);
396 }
397
398 switch (sdr->is_type) {
399 case IPMI_SDR_TYPE_FULL_SENSOR:
400 fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record;
401 sensor_num = fsensor->is_fs_number;
402 break;
403 case IPMI_SDR_TYPE_COMPACT_SENSOR:
404 csensor = (ipmi_sdr_compact_sensor_t *)sdr->is_record;
405 sensor_num = csensor->is_cs_number;
406 break;
407 default:
408 topo_mod_dprintf(mod, "%s does not refer to a full or "
409 "compact SDR\n", entity_refs[i]);
410 topo_mod_ipmi_rele(mod);
411 topo_mod_strfreev(mod, entity_refs, nelems);
412 return (-1);
413 }
414 if ((reading = ipmi_get_sensor_reading(hdl, sensor_num))
415 == NULL) {
416 topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
417 "%s, sensor_num=%d (%s)\n", entity_refs[i], sensor_num,
418 ipmi_errmsg(hdl));
419 topo_mod_strfreev(mod, entity_refs, nelems);
420 topo_mod_ipmi_rele(mod);
421 return (-1);
422 }
423 if (reading->isr_state_unavailable) {
424 topo_mod_dprintf(mod, "Unavailable sensor %s, sensor_num=%d\n",
425 entity_refs[i], sensor_num);
426 topo_mod_strfreev(mod, entity_refs, nelems);
427 topo_mod_ipmi_rele(mod);
428 return (-1);
429 }
430 topo_mod_strfreev(mod, entity_refs, nelems);
431 topo_mod_ipmi_rele(mod);
432
433 if (topo_prop_get_string(node, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
434 &sensor_class, &err) != 0) {
435 topo_mod_dprintf(mod, "Failed to lookup prop %s/%s on node %s "
436 "(%s)", TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
437 topo_node_name(node), topo_strerror(err));
438 return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
439 }
440 /*
441 * Mask off bits that are marked as reserved in the IPMI spec.
442 * For threshold sensors, bits 6:7 are reserved.
443 * For discrete sensors, bit 15 is reserved.
444 */
445 state = reading->isr_state;
446 if (strcmp(sensor_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0)
447 state = state & 0x3F;
448 else
449 state = state & 0x7FFF;
450
451 topo_mod_strfree(mod, sensor_class);
452
453 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
454 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
455 TOPO_SENSOR_STATE) != 0 ||
456 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
457 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, state) != 0) {
458 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
459 nvlist_free(nvl);
460 return (topo_mod_seterrno(mod, EMOD_NOMEM));
461 }
462 *out = nvl;
463
464 return (0);
465 }
466
467 /*ARGSUSED*/
468 static int
ipmi_sensor_reading(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)469 ipmi_sensor_reading(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
470 nvlist_t *in, nvlist_t **out)
471 {
472 char **entity_refs, reading_str[BUFSZ];
473 uint_t nelems;
474 int err = 0, i;
475 ipmi_sdr_t *sdr = NULL;
476 ipmi_sdr_full_sensor_t *fsensor;
477 ipmi_sensor_reading_t *reading;
478 double conv_reading;
479 ipmi_handle_t *hdl;
480 nvlist_t *nvl;
481 boolean_t found_sdr = B_FALSE;
482 uint8_t sensor_num;
483 uint32_t e_id, e_inst;
484 tnode_t *pnode;
485
486 if (vers > TOPO_METH_IPMI_READING_VERSION)
487 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
488
489 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
490 &entity_refs, &nelems, &err) != 0) {
491 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
492 "(%s)", topo_strerror(err));
493 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
494 }
495
496 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
497 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
498 topo_mod_strfreev(mod, entity_refs, nelems);
499 return (-1);
500 }
501
502 pnode = topo_node_parent(node);
503 if (topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
504 TOPO_PROP_IPMI_ENTITY_ID, &e_id, &err) != 0 ||
505 topo_prop_get_uint32(pnode, TOPO_PGROUP_IPMI,
506 TOPO_PROP_IPMI_ENTITY_INST, &e_inst, &err) != 0) {
507 e_id = IPMI_ET_UNSPECIFIED;
508 e_inst = 0;
509 }
510
511 for (i = 0; i < nelems; i++) {
512 if ((sdr = ipmi_sdr_lookup_precise(hdl, entity_refs[i],
513 (uint8_t)e_id, (uint8_t)e_inst)) != NULL) {
514 found_sdr = B_TRUE;
515 break;
516 } else
517 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
518 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
519 }
520
521 if (! found_sdr) {
522 topo_mod_strfreev(mod, entity_refs, nelems);
523 topo_mod_ipmi_rele(mod);
524 return (-1);
525 }
526 switch (sdr->is_type) {
527 case IPMI_SDR_TYPE_FULL_SENSOR:
528 fsensor = (ipmi_sdr_full_sensor_t *)sdr->is_record;
529 sensor_num = fsensor->is_fs_number;
530 break;
531 default:
532 topo_mod_dprintf(mod, "%s does not refer to a full "
533 "sensor SDR\n", entity_refs[i]);
534 topo_mod_ipmi_rele(mod);
535 topo_mod_strfreev(mod, entity_refs, nelems);
536 return (-1);
537 }
538
539 if ((reading = ipmi_get_sensor_reading(hdl, sensor_num)) == NULL) {
540 topo_mod_dprintf(mod, "Failed to get sensor reading for sensor "
541 "%s, sensor_num=%d (%s)\n", entity_refs[i],
542 sensor_num, ipmi_errmsg(hdl));
543 topo_mod_strfreev(mod, entity_refs, nelems);
544 topo_mod_ipmi_rele(mod);
545 return (-1);
546 }
547 topo_mod_ipmi_rele(mod);
548
549 if (ipmi_sdr_conv_reading(fsensor, reading->isr_reading, &conv_reading)
550 != 0) {
551 topo_mod_dprintf(mod, "Failed to convert sensor reading for "
552 "sensor %s (%s)\n", entity_refs[i], ipmi_errmsg(hdl));
553 topo_mod_strfreev(mod, entity_refs, nelems);
554 return (-1);
555 }
556 topo_mod_strfreev(mod, entity_refs, nelems);
557
558 (void) snprintf(reading_str, BUFSZ, "%f", conv_reading);
559 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
560 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
561 TOPO_SENSOR_READING) != 0 ||
562 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_DOUBLE) != 0 ||
563 nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, conv_reading) != 0) {
564 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
565 nvlist_free(nvl);
566 return (topo_mod_seterrno(mod, EMOD_NOMEM));
567 }
568 *out = nvl;
569
570 return (0);
571 }
572
573 static int
ipmi_indicator_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)574 ipmi_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
575 nvlist_t *in, nvlist_t **out)
576 {
577 char **entity_refs;
578 uint_t nelems;
579 ipmi_sdr_generic_locator_t *gdl = NULL;
580 ipmi_handle_t *hdl;
581 int err, ret, i;
582 uint8_t ledmode;
583 uint32_t mode_in;
584 nvlist_t *pargs, *nvl;
585 boolean_t found_sdr = B_FALSE;
586
587 if (vers > TOPO_METH_IPMI_MODE_VERSION)
588 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
589
590 /*
591 * Get an IPMI handle and then lookup the generic device locator sensor
592 * data record referenced by the entity_ref prop val
593 */
594 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
595 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
596 return (-1);
597 }
598
599 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
600 &entity_refs, &nelems, &err) != 0) {
601 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
602 "(%s)", topo_strerror(err));
603 topo_mod_ipmi_rele(mod);
604 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
605 }
606
607 for (i = 0; i < nelems; i++) {
608 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
609 != NULL) {
610 found_sdr = B_TRUE;
611 break;
612 } else
613 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
614 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
615 }
616
617 if (! found_sdr) {
618 topo_mod_strfreev(mod, entity_refs, nelems);
619 topo_mod_ipmi_rele(mod);
620 return (-1);
621 }
622
623 /*
624 * Now look for a private argument list to figure out whether we're
625 * doing a get or a set operation, and then do it.
626 */
627 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
628 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
629 /*
630 * Set the LED mode
631 */
632 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
633 &mode_in)) != 0) {
634 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
635 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
636 topo_mod_strfreev(mod, entity_refs, nelems);
637 topo_mod_ipmi_rele(mod);
638 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
639 }
640 if (mode_in != TOPO_LED_STATE_OFF &&
641 mode_in != TOPO_LED_STATE_ON) {
642 topo_mod_dprintf(mod, "Invalid property value: %d\n",
643 mode_in);
644 topo_mod_strfreev(mod, entity_refs, nelems);
645 topo_mod_ipmi_rele(mod);
646 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
647 }
648 ledmode = (uint8_t)mode_in;
649 if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
650 topo_mod_dprintf(mod, "%s: Failed to set LED mode for "
651 "%s (%s) to %s\n", __func__, entity_refs[i],
652 ipmi_errmsg(hdl), ledmode ? "ON" : "OFF");
653 topo_mod_strfreev(mod, entity_refs, nelems);
654 topo_mod_ipmi_rele(mod);
655 return (-1);
656 }
657 } else {
658 /*
659 * Get the LED mode
660 */
661 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
662 topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
663 "%s (%s)\n", __func__, entity_refs[i],
664 ipmi_errmsg(hdl));
665 topo_mod_strfreev(mod, entity_refs, nelems);
666 topo_mod_ipmi_rele(mod);
667 return (-1);
668 }
669 }
670 topo_mod_strfreev(mod, entity_refs, nelems);
671 topo_mod_ipmi_rele(mod);
672
673 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
674 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
675 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
676 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
677 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
678 nvlist_free(nvl);
679 return (topo_mod_seterrno(mod, EMOD_NOMEM));
680 }
681 *out = nvl;
682
683 return (0);
684 }
685
686 /*
687 * On most Sun platforms there is no seperate locate LED for the drive bays.
688 * This propmethod simulates a locate LED by blinking the ok2rm LED.
689 *
690 * LED control is through a the Sun OEM led/get commands. This propmethod can
691 * work on X4500/X4540 with ILOM 2.x and on
692 * X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms with ILOM 3.x.
693 */
694 static int
bay_locate_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)695 bay_locate_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
696 nvlist_t *in, nvlist_t **out)
697 {
698 char **entity_refs;
699 uint_t nelems;
700 ipmi_sdr_generic_locator_t *gdl = NULL;
701 ipmi_handle_t *hdl;
702 int err, ret, i;
703 uint8_t ledmode;
704 uint32_t mode_in;
705 nvlist_t *pargs, *nvl;
706 boolean_t found_sdr = B_FALSE;
707
708 if (vers > TOPO_METH_BAY_LOCATE_VERSION)
709 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
710
711 /*
712 * Get an IPMI handle and then lookup the generic device locator sensor
713 * data record referenced by the entity_ref prop val
714 */
715 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
716 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
717 return (-1);
718 }
719
720 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
721 &entity_refs, &nelems, &err) != 0) {
722 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
723 "(%s)", topo_strerror(err));
724 topo_mod_ipmi_rele(mod);
725 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
726 }
727
728 for (i = 0; i < nelems; i++) {
729 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
730 != NULL) {
731 found_sdr = B_TRUE;
732 break;
733 } else
734 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
735 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
736 }
737
738 if (! found_sdr) {
739 topo_mod_strfreev(mod, entity_refs, nelems);
740 topo_mod_ipmi_rele(mod);
741 return (-1);
742 }
743
744 /*
745 * Now look for a private argument list to figure out whether we're
746 * doing a get or a set operation, and then do it.
747 */
748 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
749 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
750 /*
751 * Set the LED mode
752 */
753 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
754 &mode_in)) != 0) {
755 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
756 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
757 topo_mod_strfreev(mod, entity_refs, nelems);
758 topo_mod_ipmi_rele(mod);
759 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
760 }
761 if (mode_in != TOPO_LED_STATE_OFF &&
762 mode_in != TOPO_LED_STATE_ON) {
763 topo_mod_dprintf(mod, "Invalid property value: %d\n",
764 mode_in);
765 topo_mod_strfreev(mod, entity_refs, nelems);
766 topo_mod_ipmi_rele(mod);
767 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
768 }
769 if (mode_in == TOPO_LED_STATE_ON)
770 ledmode = IPMI_SUNOEM_LED_MODE_FAST;
771 else
772 ledmode = IPMI_SUNOEM_LED_MODE_OFF;
773 if (ipmi_sunoem_led_set(hdl, gdl, ledmode) < 0) {
774 topo_mod_dprintf(mod, "Failed to set LED mode for %s "
775 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
776 topo_mod_strfreev(mod, entity_refs, nelems);
777 topo_mod_ipmi_rele(mod);
778 return (-1);
779 }
780 } else {
781 /*
782 * Get the LED mode
783 */
784 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
785 topo_mod_dprintf(mod, "Failed to get LED mode for %s "
786 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
787 topo_mod_strfreev(mod, entity_refs, nelems);
788 topo_mod_ipmi_rele(mod);
789 return (-1);
790 }
791 }
792 topo_mod_strfreev(mod, entity_refs, nelems);
793 topo_mod_ipmi_rele(mod);
794
795 if (ledmode == IPMI_SUNOEM_LED_MODE_SLOW ||
796 ledmode == IPMI_SUNOEM_LED_MODE_FAST)
797 ledmode = TOPO_LED_STATE_ON;
798 else
799 ledmode = TOPO_LED_STATE_OFF;
800
801 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
802 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
803 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
804 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
805 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
806 nvlist_free(nvl);
807 return (topo_mod_seterrno(mod, EMOD_NOMEM));
808 }
809 *out = nvl;
810
811 return (0);
812 }
813
814 /*
815 * This is a method for the "mode" property that is specific for the ok2rm and
816 * service drive bay LED's on the X4500/X4540 platforms running ILOM 2.x and
817 * for X4140/X4240/X4440/X4500/X4540/X4150/X4250 and X4450 platforms running
818 * ILOM 3.x.
819 *
820 * For ILOM 2.x, the LED's are controlled by a Sun OEM led set command
821 *
822 * For ILOM 3.x platforms the LED's are controlled by sending a platform event
823 * message for the appropriate DBP/HDD##/STATE compact SDR.
824 *
825 * For both ILOM 2 and ILOM 3, the current LED mode can be obtained by a
826 * Sun OEM led get command.
827 */
828 static int
bay_indicator_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)829 bay_indicator_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
830 nvlist_t *in, nvlist_t **out)
831 {
832 char **entity_refs;
833 uint_t nelems;
834 ipmi_sdr_compact_sensor_t *cs = NULL;
835 ipmi_sdr_generic_locator_t *gdl = NULL;
836 ipmi_deviceid_t *sp_devid;
837 ipmi_platform_event_message_t pem;
838 ipmi_handle_t *hdl;
839 int err, ret, i;
840 uint32_t type, ledmode;
841 uint8_t mode_in, ev_off;
842 nvlist_t *pargs, *nvl;
843 boolean_t found_sdr = B_FALSE;
844
845 if (vers > TOPO_METH_BAY_MODE_VERSION)
846 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
847
848 if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
849 &type, &err) != 0) {
850 topo_mod_dprintf(mod, "Failed to lookup %s property "
851 "(%s)", TOPO_FACILITY_TYPE, topo_strerror(err));
852 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
853 }
854 switch (type) {
855 case (TOPO_LED_TYPE_SERVICE):
856 ev_off = 0x01;
857 break;
858 case (TOPO_LED_TYPE_OK2RM):
859 ev_off = 0x03;
860 break;
861 default:
862 topo_mod_dprintf(mod, "Invalid LED type: 0x%x\n", type);
863 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
864 }
865
866 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
867 &entity_refs, &nelems, &err) != 0) {
868 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
869 "(%s)", topo_strerror(err));
870 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
871 }
872
873 /*
874 * Figure out whether the SP is running ILOM 2.x or ILOM 3.x
875 */
876 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
877 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
878 topo_mod_strfreev(mod, entity_refs, nelems);
879 return (-1);
880 }
881
882 if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
883 topo_mod_dprintf(mod, "%s: GET DEVICEID command failed (%s)\n",
884 __func__, ipmi_errmsg(hdl));
885 topo_mod_strfreev(mod, entity_refs, nelems);
886 topo_mod_ipmi_rele(mod);
887 return (-1);
888 }
889
890 /*
891 * Now lookup the propmethod argument list and figure out whether we're
892 * doing a get or a set operation, and then do it.
893 */
894 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
895 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
896 /*
897 * Set the LED mode
898 */
899 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
900 &ledmode)) != 0) {
901 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
902 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
903 topo_mod_strfreev(mod, entity_refs, nelems);
904 topo_mod_ipmi_rele(mod);
905 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
906 }
907
908 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
909 ledmode ? "ON" : "OFF");
910
911 if (sp_devid->id_firm_major == 2) {
912 for (i = 0; i < nelems; i++) {
913 if ((gdl = ipmi_sdr_lookup_generic(hdl,
914 entity_refs[i])) != NULL) {
915 found_sdr = B_TRUE;
916 break;
917 } else
918 topo_mod_dprintf(mod,
919 "Failed to lookup SDR for %s(%s)\n",
920 entity_refs[i], ipmi_errmsg(hdl));
921 }
922
923 if (! found_sdr) {
924 topo_mod_strfreev(mod, entity_refs, nelems);
925 topo_mod_ipmi_rele(mod);
926 return (-1);
927 }
928
929 if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)ledmode)
930 < 0) {
931 topo_mod_dprintf(mod,
932 "Failed to set LED mode for %s (%s)\n",
933 entity_refs[i], ipmi_errmsg(hdl));
934 topo_mod_strfreev(mod, entity_refs, nelems);
935 topo_mod_ipmi_rele(mod);
936 return (-1);
937 }
938 } else {
939 for (i = 0; i < nelems; i++) {
940 if ((cs = ipmi_sdr_lookup_compact_sensor(hdl,
941 entity_refs[i])) != NULL) {
942 found_sdr = B_TRUE;
943 break;
944 } else
945 topo_mod_dprintf(mod,
946 "Failed to lookup SDR for %s(%s)\n",
947 entity_refs[i], ipmi_errmsg(hdl));
948 }
949
950 if (! found_sdr) {
951 topo_mod_strfreev(mod, entity_refs, nelems);
952 topo_mod_ipmi_rele(mod);
953 return (-1);
954 }
955
956 pem.ipem_generator = IPMI_SEL_SYSTEM;
957 pem.ipem_rev = IPMI_EV_REV15;
958 pem.ipem_sensor_type = IPMI_ST_BAY;
959 pem.ipem_sensor_num = cs->is_cs_number;
960 pem.ipem_event_type = IPMI_RT_SPECIFIC;
961 if (ledmode == TOPO_LED_STATE_ON)
962 pem.ipem_event_dir = 0;
963 else
964 pem.ipem_event_dir = 1;
965
966 pem.ipem_event_data[0] = ev_off;
967 pem.ipem_event_data[1] = 0xff;
968 pem.ipem_event_data[2] = 0xff;
969
970 if (ipmi_event_platform_message(hdl, &pem) != 0) {
971 topo_mod_dprintf(mod, "%s: Failed to send "
972 "platform event mesg for %s (%s)\n",
973 __func__, entity_refs[i], ipmi_errmsg(hdl));
974 topo_mod_strfreev(mod, entity_refs, nelems);
975 topo_mod_ipmi_rele(mod);
976 return (-1);
977 }
978 }
979 } else {
980 /*
981 * Get the LED mode
982 */
983 for (i = 0; i < nelems; i++) {
984 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
985 != NULL) {
986 found_sdr = B_TRUE;
987 break;
988 } else
989 topo_mod_dprintf(mod, "%s: Failed to lookup "
990 "SDR for %s (%s)\n", __func__,
991 entity_refs[i], ipmi_errmsg(hdl));
992 }
993
994 if (! found_sdr) {
995 topo_mod_strfreev(mod, entity_refs, nelems);
996 topo_mod_ipmi_rele(mod);
997 return (-1);
998 }
999 if (ipmi_sunoem_led_get(hdl, gdl, &mode_in) < 0) {
1000 topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
1001 "%s (%s)\n", __func__, entity_refs[i],
1002 ipmi_errmsg(hdl));
1003 topo_mod_strfreev(mod, entity_refs, nelems);
1004 topo_mod_ipmi_rele(mod);
1005 return (-1);
1006 }
1007 ledmode = mode_in;
1008 }
1009 topo_mod_strfreev(mod, entity_refs, nelems);
1010 topo_mod_ipmi_rele(mod);
1011
1012 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1013 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1014 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1015 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
1016 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1017 nvlist_free(nvl);
1018 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1019 }
1020 *out = nvl;
1021 return (0);
1022 }
1023
1024 /*
1025 * This propmethod is for controlling the present LED on the drive bays for
1026 * the X4500 platform.
1027 */
1028 static int
x4500_present_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1029 x4500_present_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1030 nvlist_t *in, nvlist_t **out)
1031 {
1032 char **entity_refs;
1033 uint_t nelems;
1034 ipmi_sdr_compact_sensor_t *cs = NULL;
1035 ipmi_set_sensor_reading_t sr_out = { 0 };
1036 ipmi_handle_t *hdl;
1037 int err, ret, i;
1038 uint32_t ledmode;
1039 nvlist_t *pargs, *nvl;
1040 boolean_t found_sdr = B_FALSE;
1041
1042 if (vers > TOPO_METH_X4500_MODE_VERSION)
1043 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1044
1045 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
1046 &entity_refs, &nelems, &err) != 0) {
1047 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
1048 "(%s)", topo_strerror(err));
1049 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1050 }
1051
1052 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1053 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1054 topo_mod_strfreev(mod, entity_refs, nelems);
1055 return (-1);
1056 }
1057 for (i = 0; i < nelems; i++) {
1058 if ((cs = ipmi_sdr_lookup_compact_sensor(hdl, entity_refs[i]))
1059 != NULL) {
1060 found_sdr = B_TRUE;
1061 break;
1062 } else
1063 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
1064 "(%s)\n", entity_refs[i],
1065 ipmi_errmsg(hdl));
1066 }
1067
1068 if (! found_sdr) {
1069 topo_mod_strfreev(mod, entity_refs, nelems);
1070 topo_mod_ipmi_rele(mod);
1071 return (-1);
1072 }
1073
1074 /*
1075 * Now lookup the propmethod argument list and figure out whether we're
1076 * doing a get or a set operation, and then do it.
1077 */
1078 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1079 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1080 /*
1081 * Set the LED mode
1082 */
1083 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1084 &ledmode)) != 0) {
1085 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1086 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1087 topo_mod_strfreev(mod, entity_refs, nelems);
1088 topo_mod_ipmi_rele(mod);
1089 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1090 }
1091
1092 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
1093 ledmode ? "ON" : "OFF");
1094
1095 if (ledmode == TOPO_LED_STATE_OFF) {
1096 sr_out.iss_deassert_state = BAY_PRESENT_LED_MASK;
1097 sr_out.iss_deassrt_op = IPMI_SENSOR_OP_SET;
1098 } else if (ledmode == TOPO_LED_STATE_ON) {
1099 sr_out.iss_assert_state = BAY_PRESENT_LED_MASK;
1100 sr_out.iss_assert_op = IPMI_SENSOR_OP_SET;
1101 } else {
1102 topo_mod_dprintf(mod, "%s: Invalid LED mode: "
1103 "%d\n", __func__, ledmode);
1104 topo_mod_strfreev(mod, entity_refs, nelems);
1105 topo_mod_ipmi_rele(mod);
1106 return (-1);
1107 }
1108 sr_out.iss_id = cs->is_cs_number;
1109 topo_mod_dprintf(mod, "Setting LED mode (mask=0x%x)\n",
1110 BAY_PRESENT_LED_MASK);
1111 if (ipmi_set_sensor_reading(hdl, &sr_out) != 0) {
1112 topo_mod_dprintf(mod, "%s: Failed to set "
1113 "sensor reading for %s (%s)\n", __func__,
1114 entity_refs[i], ipmi_errmsg(hdl));
1115 topo_mod_strfreev(mod, entity_refs, nelems);
1116 topo_mod_ipmi_rele(mod);
1117 return (-1);
1118 }
1119 } else {
1120 /*
1121 * Get the LED mode
1122 */
1123 ipmi_sensor_reading_t *sr_in;
1124
1125 topo_mod_dprintf(mod, "Getting LED mode\n");
1126 if ((sr_in = ipmi_get_sensor_reading(hdl, cs->is_cs_number))
1127 == NULL) {
1128 topo_mod_dprintf(mod, "Failed to get sensor reading "
1129 "for sensor %s (sensor num: %d) (error: %s)\n",
1130 entity_refs[i], cs->is_cs_number, ipmi_errmsg(hdl));
1131 topo_mod_strfreev(mod, entity_refs, nelems);
1132 topo_mod_ipmi_rele(mod);
1133 return (-1);
1134 }
1135 if (sr_in->isr_state & (uint16_t)BAY_PRESENT_LED_MASK)
1136 ledmode = TOPO_LED_STATE_ON;
1137 else
1138 ledmode = TOPO_LED_STATE_OFF;
1139 }
1140 topo_mod_strfreev(mod, entity_refs, nelems);
1141 topo_mod_ipmi_rele(mod);
1142
1143 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1144 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1145 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1146 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
1147 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1148 nvlist_free(nvl);
1149 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1150 }
1151 *out = nvl;
1152 return (0);
1153 }
1154
1155 /*
1156 * This is a property method for controlling the chassis service LED on
1157 * ILOM 3.x based platforms.
1158 */
1159 static int
chassis_service_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1160 chassis_service_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1161 nvlist_t *in, nvlist_t **out)
1162 {
1163 char **entity_refs;
1164 uint_t nelems;
1165 ipmi_sdr_generic_locator_t *gdl = NULL;
1166 ipmi_deviceid_t *sp_devid;
1167 ipmi_platform_event_message_t pem;
1168 ipmi_handle_t *hdl;
1169 int err, ret, i;
1170 uint8_t ledmode;
1171 uint32_t mode_in;
1172 nvlist_t *pargs, *nvl;
1173 boolean_t found_sdr = B_FALSE;
1174
1175 if (vers > TOPO_METH_CHASSIS_SERVICE_VERSION)
1176 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1177
1178 /*
1179 * Get an IPMI handle and then lookup the generic device locator record
1180 * referenced by the entity_ref prop val
1181 */
1182 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1183 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1184 return (-1);
1185 }
1186
1187 if (topo_prop_get_string_array(node, TOPO_PGROUP_FACILITY, "entity_ref",
1188 &entity_refs, &nelems, &err) != 0) {
1189 topo_mod_dprintf(mod, "Failed to lookup entity_ref property "
1190 "(%s)", topo_strerror(err));
1191 topo_mod_ipmi_rele(mod);
1192 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1193 }
1194
1195 for (i = 0; i < nelems; i++) {
1196 if ((gdl = ipmi_sdr_lookup_generic(hdl, entity_refs[i]))
1197 != NULL) {
1198 found_sdr = B_TRUE;
1199 break;
1200 } else
1201 topo_mod_dprintf(mod, "Failed to lookup SDR for %s "
1202 "(%s)\n", entity_refs[i], ipmi_errmsg(hdl));
1203 }
1204
1205 if (! found_sdr) {
1206 topo_mod_strfreev(mod, entity_refs, nelems);
1207 topo_mod_ipmi_rele(mod);
1208 return (-1);
1209 }
1210
1211 /*
1212 * Now lookup the propmethod argument list and figure out whether we're
1213 * doing a get or a set operation, and then do it.
1214 */
1215 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1216 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1217 /*
1218 * Set the LED mode
1219 */
1220 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1221 &mode_in)) != 0) {
1222 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1223 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1224 topo_mod_strfreev(mod, entity_refs, nelems);
1225 topo_mod_ipmi_rele(mod);
1226 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1227 }
1228
1229 /*
1230 * Determine which IPMI mechanism to use to set the LED mode
1231 * based on whether the SP is running ILOM 2 or later.
1232 */
1233 if ((sp_devid = ipmi_get_deviceid(hdl)) == NULL) {
1234 topo_mod_dprintf(mod, "%s: GET DEVICEID command failed "
1235 "(%s)\n", __func__, ipmi_errmsg(hdl));
1236 topo_mod_strfreev(mod, entity_refs, nelems);
1237 topo_mod_ipmi_rele(mod);
1238 return (-1);
1239 }
1240
1241 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
1242 mode_in ? "ON" : "OFF");
1243
1244 if (sp_devid->id_firm_major == 2) {
1245 if (mode_in != TOPO_LED_STATE_OFF &&
1246 mode_in != TOPO_LED_STATE_ON) {
1247 topo_mod_dprintf(mod, "Invalid property value: "
1248 "%d\n", mode_in);
1249 topo_mod_strfreev(mod, entity_refs, nelems);
1250 topo_mod_ipmi_rele(mod);
1251 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1252 }
1253 if (ipmi_sunoem_led_set(hdl, gdl, (uint8_t)mode_in)
1254 < 0) {
1255 topo_mod_dprintf(mod, "Failed to set LED mode "
1256 "for %s (%s)\n", entity_refs[i],
1257 ipmi_errmsg(hdl));
1258 topo_mod_strfreev(mod, entity_refs, nelems);
1259 topo_mod_ipmi_rele(mod);
1260 return (-1);
1261 }
1262 } else {
1263 pem.ipem_generator = IPMI_SEL_SYSTEM;
1264 pem.ipem_rev = IPMI_EV_REV15;
1265 pem.ipem_sensor_type = IPMI_ST_SYSTEM;
1266 pem.ipem_sensor_num = 0x00;
1267 pem.ipem_event_type = IPMI_RT_SPECIFIC;
1268 if (mode_in == TOPO_LED_STATE_ON)
1269 pem.ipem_event_dir = 0;
1270 else
1271 pem.ipem_event_dir = 1;
1272
1273 pem.ipem_event_data[0] = 0x02;
1274 pem.ipem_event_data[1] = 0xff;
1275 pem.ipem_event_data[2] = 0xff;
1276
1277 topo_mod_dprintf(mod, "Sending platform event\n");
1278 if (ipmi_event_platform_message(hdl, &pem) != 0) {
1279 topo_mod_dprintf(mod, "%s: Failed to send "
1280 "platform event mesg for sensor 0 (%s)\n",
1281 __func__, ipmi_errmsg(hdl));
1282 topo_mod_strfreev(mod, entity_refs, nelems);
1283 topo_mod_ipmi_rele(mod);
1284 return (-1);
1285 }
1286 }
1287 } else {
1288 /*
1289 * Get the LED mode
1290 */
1291 if (ipmi_sunoem_led_get(hdl, gdl, &ledmode) < 0) {
1292 topo_mod_dprintf(mod, "%s: Failed to get LED mode for "
1293 "%s (%s)\n", __func__, entity_refs[i],
1294 ipmi_errmsg(hdl));
1295 topo_mod_strfreev(mod, entity_refs, nelems);
1296 topo_mod_ipmi_rele(mod);
1297 return (-1);
1298 }
1299 }
1300 topo_mod_strfreev(mod, entity_refs, nelems);
1301 topo_mod_ipmi_rele(mod);
1302
1303 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1304 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1305 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1306 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
1307 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1308 nvlist_free(nvl);
1309 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1310 }
1311 *out = nvl;
1312 return (0);
1313 }
1314
1315 /*
1316 * This is a property method for controlling the chassis identify LED using
1317 * generic IPMI mechanisms.
1318 */
1319 /*ARGSUSED*/
1320 static int
chassis_ident_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1321 chassis_ident_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1322 nvlist_t *in, nvlist_t **out)
1323 {
1324 ipmi_handle_t *hdl;
1325 int ret;
1326 uint32_t modeval;
1327 boolean_t assert_ident;
1328 nvlist_t *pargs, *nvl;
1329 ipmi_chassis_status_t *chs;
1330
1331 if (vers > TOPO_METH_CHASSIS_IDENT_VERSION)
1332 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1333
1334 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1335 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1336 return (-1);
1337 }
1338
1339 /*
1340 * Now lookup the propmethod argument list and figure out whether we're
1341 * doing a get or a set operation, and then do it.
1342 */
1343 if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
1344 nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
1345 /*
1346 * Set the LED mode
1347 */
1348 if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
1349 &modeval)) != 0) {
1350 topo_mod_dprintf(mod, "Failed to lookup %s nvpair "
1351 "(%s)\n", TOPO_PROP_VAL_VAL, strerror(ret));
1352 topo_mod_ipmi_rele(mod);
1353 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1354 }
1355
1356 assert_ident = modeval ? B_TRUE : B_FALSE;
1357 topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
1358 assert_ident ? "ON" : "OFF");
1359 if (ipmi_chassis_identify(hdl, assert_ident) != 0) {
1360 topo_mod_ipmi_rele(mod);
1361 return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
1362 }
1363
1364 } else {
1365 /*
1366 * Get the LED mode
1367 */
1368 if ((chs = ipmi_chassis_status(hdl)) == NULL ||
1369 !chs->ichs_identify_supported) {
1370 free(chs);
1371 topo_mod_ipmi_rele(mod);
1372 return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
1373 }
1374 /*
1375 * ichs_identify_state is a 2-bit value with the following
1376 * semantics:
1377 * 0 - ident is off
1378 * 1 - ident is temporarily on
1379 * 2 - ident is indefinitely on
1380 * 3 - reserved
1381 */
1382 switch (chs->ichs_identify_state) {
1383 case 0:
1384 modeval = TOPO_LED_STATE_OFF;
1385 break;
1386 case 1:
1387 case 2:
1388 modeval = TOPO_LED_STATE_ON;
1389 break;
1390 default:
1391 free(chs);
1392 topo_mod_ipmi_rele(mod);
1393 return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
1394 }
1395 free(chs);
1396 }
1397 topo_mod_ipmi_rele(mod);
1398
1399 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1400 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
1401 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
1402 nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, modeval) != 0) {
1403 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1404 nvlist_free(nvl);
1405 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1406 }
1407 *out = nvl;
1408 return (0);
1409 }
1410
1411 #define ISBITSET(MASK, BIT) ((MASK & BIT) == BIT)
1412
1413 struct sensor_thresh {
1414 uint8_t sthr_threshbit;
1415 const char *sthr_propname;
1416 uint8_t sthr_threshoff;
1417 };
1418
1419 static const struct sensor_thresh threshset[] = {
1420 { IPMI_SENSOR_THRESHOLD_LOWER_NONCRIT, TOPO_PROP_THRESHOLD_LNC,
1421 offsetof(ipmi_sensor_thresholds_t, ithr_lower_noncrit) },
1422 { IPMI_SENSOR_THRESHOLD_LOWER_CRIT, TOPO_PROP_THRESHOLD_LCR,
1423 offsetof(ipmi_sensor_thresholds_t, ithr_lower_crit) },
1424 { IPMI_SENSOR_THRESHOLD_LOWER_NONRECOV, TOPO_PROP_THRESHOLD_LNR,
1425 offsetof(ipmi_sensor_thresholds_t, ithr_lower_nonrec) },
1426 { IPMI_SENSOR_THRESHOLD_UPPER_NONCRIT, TOPO_PROP_THRESHOLD_UNC,
1427 offsetof(ipmi_sensor_thresholds_t, ithr_upper_noncrit) },
1428 { IPMI_SENSOR_THRESHOLD_UPPER_CRIT, TOPO_PROP_THRESHOLD_UCR,
1429 offsetof(ipmi_sensor_thresholds_t, ithr_upper_crit) },
1430 { IPMI_SENSOR_THRESHOLD_UPPER_NONRECOV, TOPO_PROP_THRESHOLD_UNR,
1431 offsetof(ipmi_sensor_thresholds_t, ithr_upper_nonrec) }
1432 };
1433
1434 static uint_t num_thresholds =
1435 sizeof (threshset) / sizeof (struct sensor_thresh);
1436
1437 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)1438 set_thresh_prop(topo_mod_t *mod, tnode_t *fnode, ipmi_sdr_full_sensor_t *fs,
1439 uint8_t raw_thresh, const struct sensor_thresh *thresh)
1440 {
1441 int err;
1442 double conv_thresh;
1443
1444 if (ipmi_sdr_conv_reading(fs, raw_thresh, &conv_thresh) != 0) {
1445 topo_mod_dprintf(mod, "Failed to convert threshold %s on node "
1446 "%s", thresh->sthr_propname, topo_node_name(fnode));
1447 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1448 }
1449 if (topo_prop_set_double(fnode, TOPO_PGROUP_FACILITY,
1450 thresh->sthr_propname, TOPO_PROP_IMMUTABLE, conv_thresh, &err) !=
1451 0) {
1452 topo_mod_dprintf(mod, "Failed to set property %s on node %s "
1453 "(%s)", thresh->sthr_propname, topo_node_name(fnode),
1454 topo_strerror(err));
1455 return (topo_mod_seterrno(mod, err));
1456 }
1457 return (0);
1458 }
1459
1460 static int
make_sensor_node(topo_mod_t * mod,tnode_t * pnode,struct sensor_data * sd,ipmi_handle_t * hdl)1461 make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd,
1462 ipmi_handle_t *hdl)
1463 {
1464 int err, ret, i;
1465 tnode_t *fnode;
1466 char *ftype = "sensor", facname[MAX_ID_LEN], **entity_refs;
1467 topo_pgroup_info_t pgi;
1468 nvlist_t *arg_nvl = NULL;
1469 ipmi_sensor_thresholds_t thresh = { 0 };
1470 uint8_t mask;
1471
1472 /*
1473 * Some platforms have '/' characters in the IPMI entity name, but '/'
1474 * has a special meaning for FMRI's so we change them to '.' before
1475 * binding the node into the topology.
1476 */
1477 (void) strcpy(facname, sd->sd_entity_ref);
1478 for (i = 0; facname[i]; i++)
1479 if (facname[i] == '/')
1480 facname[i] = '.';
1481
1482 if ((fnode = topo_node_facbind(mod, pnode, facname, ftype)) == NULL) {
1483 topo_mod_dprintf(mod, "Failed to bind facility node: %s\n",
1484 facname);
1485 /* errno set */
1486 return (-1);
1487 }
1488
1489 pgi.tpi_name = TOPO_PGROUP_FACILITY;
1490 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1491 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1492 pgi.tpi_version = 1;
1493 if (topo_pgroup_create(fnode, &pgi, &err) != 0) {
1494 if (err != ETOPO_PROP_DEFD) {
1495 topo_mod_dprintf(mod, "pgroups create failure: %s\n",
1496 topo_strerror(err));
1497 topo_node_unbind(fnode);
1498 return (topo_mod_seterrno(mod, err));
1499 }
1500 }
1501 if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) {
1502 topo_mod_dprintf(mod, "make_fac_node: "
1503 "failed to register facility methods");
1504 topo_node_unbind(fnode);
1505 /* errno set */
1506 return (-1);
1507 }
1508 /*
1509 * For both threshold and discrete sensors we set up a propmethod for
1510 * getting the sensor state and properties to hold the entity ref,
1511 * sensor class and sensor type.
1512 */
1513 if ((entity_refs = topo_mod_alloc(mod, sizeof (char *))) == NULL)
1514 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1515
1516 entity_refs[0] = topo_mod_strdup(mod, sd->sd_entity_ref);
1517
1518 if (topo_prop_set_string_array(fnode, TOPO_PGROUP_FACILITY,
1519 "entity_ref", TOPO_PROP_IMMUTABLE, (const char **)entity_refs, 1,
1520 &err) != 0) {
1521 topo_mod_dprintf(mod, "%s: Failed to set entity_ref property "
1522 "on node: %s=%" PRIu64 " (%s)\n", __func__,
1523 topo_node_name(fnode), topo_node_instance(fnode),
1524 topo_strerror(err));
1525 topo_mod_strfreev(mod, entity_refs, 1);
1526 return (topo_mod_seterrno(mod, err));
1527 }
1528 topo_mod_strfreev(mod, entity_refs, 1);
1529
1530 if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY, TOPO_SENSOR_CLASS,
1531 TOPO_PROP_IMMUTABLE, sd->sd_class, &err) != 0) {
1532 topo_mod_dprintf(mod, "Failed to set %s property on node: "
1533 "%s=%" PRIu64 " (%s)\n", TOPO_SENSOR_CLASS,
1534 topo_node_name(fnode), topo_node_instance(fnode),
1535 topo_strerror(err));
1536 return (topo_mod_seterrno(mod, err));
1537 }
1538 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1539 TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) {
1540 topo_mod_dprintf(mod, "Failed to set %s property on node: "
1541 "%s=%" PRIu64 " (%s)\n", TOPO_FACILITY_TYPE,
1542 topo_node_name(fnode), topo_node_instance(fnode),
1543 topo_strerror(err));
1544 return (topo_mod_seterrno(mod, err));
1545 }
1546 if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) {
1547 topo_node_unbind(fnode);
1548 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1549 }
1550
1551 if ((ret = nvlist_add_string(arg_nvl, "ipmi_entity", sd->sd_entity_ref))
1552 != 0) {
1553 topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n",
1554 strerror(ret));
1555 nvlist_free(arg_nvl);
1556 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1557 }
1558
1559 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1560 TOPO_SENSOR_STATE, TOPO_TYPE_UINT32, "ipmi_sensor_state", arg_nvl,
1561 &err) != 0) {
1562 topo_mod_dprintf(mod, "Failed to register %s propmeth on fac "
1563 "node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode),
1564 topo_strerror(err));
1565 nvlist_free(arg_nvl);
1566 return (topo_mod_seterrno(mod, err));
1567 }
1568
1569 /*
1570 * If it's a discrete sensor then we're done. For threshold sensors,
1571 * there are additional properties to set up.
1572 */
1573 if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) != 0) {
1574 nvlist_free(arg_nvl);
1575 return (0);
1576 }
1577
1578 /*
1579 * Create properties to expose the analog sensor reading, the unit
1580 * type and the upper and lower thresholds, if available.
1581 */
1582 if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
1583 TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, "ipmi_sensor_reading",
1584 arg_nvl, &err) != 0) {
1585 topo_mod_dprintf(mod, "Failed to register %s propmeth on fac "
1586 "node %s (%s)\n", TOPO_SENSOR_READING,
1587 topo_node_name(fnode), topo_strerror(err));
1588 nvlist_free(arg_nvl);
1589 return (topo_mod_seterrno(mod, err));
1590 }
1591 if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
1592 TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err) != 0) {
1593 topo_mod_dprintf(mod, "Failed to set units property on node "
1594 "%s (%s)\n", topo_node_name(fnode), topo_strerror(err));
1595 nvlist_free(arg_nvl);
1596 return (topo_mod_seterrno(mod, err));
1597 }
1598 nvlist_free(arg_nvl);
1599
1600 /*
1601 * It is possible (though unusual) for a compact sensor record to
1602 * represent a threshold sensor. However, due to how
1603 * ipmi_sdr_conv_reading() is currently implemented, we only support
1604 * gathering threshold readings on sensors enumerated from Full Sensor
1605 * Records.
1606 */
1607 if (sd->sd_fs_sdr == NULL)
1608 return (0);
1609
1610 if (ipmi_get_sensor_thresholds(hdl, &thresh,
1611 sd->sd_fs_sdr->is_fs_number) != 0) {
1612 /*
1613 * Some sensors report supporting reading thresholds, but Get
1614 * Sensor Thresholds returns Invalid Command. Do not consider
1615 * this an error so we could continue enumerating sensors for
1616 * the entity.
1617 */
1618 if (ipmi_errno(hdl) == EIPMI_INVALID_COMMAND)
1619 return (0);
1620
1621 topo_mod_dprintf(mod, "Failed to get sensor thresholds for "
1622 "node %s (%s)\n", topo_node_name(fnode), ipmi_errmsg(hdl));
1623 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
1624 }
1625
1626 /*
1627 * The IPMI Get Sensor Thresholds command returns a bitmask describing
1628 * which of the 3 upper and lower thresholds are readable. Iterate
1629 * through those and create a topo property for each threshold that is
1630 * readable.
1631 */
1632 mask = thresh.ithr_readable_mask;
1633 for (i = 0; i < num_thresholds; i++) {
1634 if (!ISBITSET(mask, threshset[i].sthr_threshbit))
1635 continue;
1636
1637 if (set_thresh_prop(mod, fnode, sd->sd_fs_sdr,
1638 *(uint8_t *)((char *)&thresh +
1639 threshset[i].sthr_threshoff), &threshset[i]) != 0) {
1640 /* errno set */
1641 return (-1);
1642 }
1643 }
1644 return (0);
1645 }
1646
1647 static boolean_t
seq_search(char * key,char ** list,uint_t nelem)1648 seq_search(char *key, char **list, uint_t nelem)
1649 {
1650 for (int i = 0; i < nelem; i++)
1651 if (strcmp(key, list[i]) == 0)
1652 return (B_TRUE);
1653 return (B_FALSE);
1654 }
1655
1656 /* ARGSUSED */
1657 static int
sdr_callback(ipmi_handle_t * hdl,const char * id,ipmi_sdr_t * sdr,void * data)1658 sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data)
1659 {
1660 uint8_t sensor_entity, sensor_inst;
1661 int sensor_idlen;
1662 ipmi_sdr_full_sensor_t *f_sensor = NULL;
1663 ipmi_sdr_compact_sensor_t *c_sensor = NULL;
1664 struct sensor_data sd;
1665 struct entity_info *ei = (struct entity_info *)data;
1666
1667 switch (sdr->is_type) {
1668 case IPMI_SDR_TYPE_FULL_SENSOR:
1669 f_sensor =
1670 (ipmi_sdr_full_sensor_t *)sdr->is_record;
1671 sensor_entity = f_sensor->is_fs_entity_id;
1672 sensor_inst = f_sensor->is_fs_entity_instance;
1673 sensor_idlen = f_sensor->is_fs_idlen;
1674 (void) strncpy(sd.sd_entity_ref,
1675 f_sensor->is_fs_idstring,
1676 f_sensor->is_fs_idlen);
1677 sd.sd_entity_ref[sensor_idlen] = '\0';
1678 sd.sd_units = f_sensor->is_fs_unit2;
1679 sd.sd_stype = f_sensor->is_fs_type;
1680 sd.sd_rtype = f_sensor->is_fs_reading_type;
1681 sd.sd_fs_sdr = f_sensor;
1682 break;
1683 case IPMI_SDR_TYPE_COMPACT_SENSOR:
1684 c_sensor =
1685 (ipmi_sdr_compact_sensor_t *)sdr->is_record;
1686 sensor_entity = c_sensor->is_cs_entity_id;
1687 sensor_inst = c_sensor->is_cs_entity_instance;
1688 sensor_idlen = c_sensor->is_cs_idlen;
1689 (void) strncpy(sd.sd_entity_ref,
1690 c_sensor->is_cs_idstring,
1691 sensor_idlen);
1692 sd.sd_entity_ref[sensor_idlen] = '\0';
1693 sd.sd_units = c_sensor->is_cs_unit2;
1694 sd.sd_stype = c_sensor->is_cs_type;
1695 sd.sd_rtype = c_sensor->is_cs_reading_type;
1696 sd.sd_fs_sdr = NULL;
1697 break;
1698 default:
1699 return (0);
1700 }
1701 if (sd.sd_rtype == IPMI_RT_THRESHOLD)
1702 sd.sd_class = TOPO_SENSOR_CLASS_THRESHOLD;
1703 else
1704 sd.sd_class = TOPO_SENSOR_CLASS_DISCRETE;
1705
1706 /*
1707 * We offset the threshold and generic sensor reading types by 0x100
1708 */
1709 if (sd.sd_rtype >= 0x1 && sd.sd_rtype <= 0xc)
1710 sd.sd_stype = sd.sd_rtype + 0x100;
1711
1712 if ((ei->ei_list != NULL && seq_search(sd.sd_entity_ref,
1713 ei->ei_list, ei->ei_listsz) == B_TRUE) ||
1714 (sensor_entity == ei->ei_id && sensor_inst == ei->ei_inst)) {
1715
1716 if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd, hdl) != 0) {
1717 topo_mod_dprintf(ei->ei_mod, "Failed to create sensor "
1718 "node for %s\n", sd.sd_entity_ref);
1719 if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP)
1720 return (-1);
1721 }
1722 }
1723 return (0);
1724 }
1725
1726 static int
get_entity_info(topo_mod_t * mod,tnode_t * node,ipmi_handle_t * hdl,struct entity_info * ei)1727 get_entity_info(topo_mod_t *mod, tnode_t *node, ipmi_handle_t *hdl,
1728 struct entity_info *ei)
1729 {
1730 char **entity_refs;
1731 int err;
1732 uint_t nelems;
1733 ipmi_sdr_t *ref_sdr;
1734 ipmi_sdr_full_sensor_t *fsensor;
1735 ipmi_sdr_compact_sensor_t *csensor;
1736 ipmi_sdr_fru_locator_t *floc;
1737 ipmi_sdr_generic_locator_t *gloc;
1738 boolean_t found_sdr = B_FALSE;
1739
1740 /*
1741 * Use the entity ref to lookup the SDR, which will have the entity ID
1742 * and instance.
1743 */
1744 if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI,
1745 "entity_ref", &entity_refs, &nelems, &err) != 0) {
1746 topo_mod_dprintf(mod, "%s: Failed to lookup entity_ref "
1747 "property on %s=%" PRIu64 " (%s)\n", __func__,
1748 topo_node_name(node), topo_node_instance(node),
1749 topo_strerror(err));
1750 topo_mod_ipmi_rele(mod);
1751 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1752 }
1753
1754 for (int i = 0; i < nelems; i++) {
1755 if ((ref_sdr = ipmi_sdr_lookup(hdl, entity_refs[i])) != NULL) {
1756 found_sdr = B_TRUE;
1757 break;
1758 } else
1759 topo_mod_dprintf(mod, "%s: Failed to lookup SDR for %s "
1760 "(%s)\n", __func__, entity_refs[i],
1761 ipmi_errmsg(hdl));
1762 }
1763 topo_mod_strfreev(mod, entity_refs, nelems);
1764 if (! found_sdr) {
1765 topo_mod_ipmi_rele(mod);
1766 return (-1);
1767 }
1768
1769 switch (ref_sdr->is_type) {
1770 case IPMI_SDR_TYPE_FULL_SENSOR:
1771 fsensor = (ipmi_sdr_full_sensor_t *)ref_sdr->is_record;
1772 ei->ei_id = fsensor->is_fs_entity_id;
1773 ei->ei_inst = fsensor->is_fs_entity_instance;
1774 break;
1775 case IPMI_SDR_TYPE_COMPACT_SENSOR:
1776 csensor
1777 = (ipmi_sdr_compact_sensor_t *)ref_sdr->is_record;
1778 ei->ei_id = csensor->is_cs_entity_id;
1779 ei->ei_inst = csensor->is_cs_entity_instance;
1780 break;
1781 case IPMI_SDR_TYPE_FRU_LOCATOR:
1782 floc = (ipmi_sdr_fru_locator_t *)ref_sdr->is_record;
1783 ei->ei_id = floc->is_fl_entity;
1784 ei->ei_inst = floc->is_fl_instance;
1785 break;
1786 case IPMI_SDR_TYPE_GENERIC_LOCATOR:
1787 gloc = (ipmi_sdr_generic_locator_t *)ref_sdr->is_record;
1788 ei->ei_id = gloc->is_gl_entity;
1789 ei->ei_inst = gloc->is_gl_instance;
1790 break;
1791 default:
1792 topo_mod_dprintf(mod, "Failed to determine entity id "
1793 "and instance: %s\n", ipmi_errmsg(hdl));
1794 topo_mod_ipmi_rele(mod);
1795 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1796 }
1797 return (0);
1798 }
1799
1800 /* ARGSUSED */
1801 static int
ipmi_sensor_enum(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1802 ipmi_sensor_enum(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1803 nvlist_t *in, nvlist_t **out)
1804 {
1805 int err, ret = -1;
1806 struct entity_info ei = {0};
1807 ipmi_handle_t *hdl;
1808
1809 if ((hdl = topo_mod_ipmi_hold(mod)) == NULL) {
1810 topo_mod_dprintf(mod, "Failed to get IPMI handle\n");
1811 return (-1);
1812 }
1813
1814 /*
1815 * For cases where the records in the SDR are hopelessly broken, then
1816 * we'll resort to hardcoding a list of sensor entities that should be
1817 * bound to this particular node. Otherwise, we'll first check if the
1818 * properties for the associated IPMI entity id and instance exist. If
1819 * not, we check for a property referencing an IPMI entity name on which
1820 * we can lookup the entity ID and instance. If none of the above pans
1821 * out, then we bail out.
1822 */
1823 if (topo_prop_get_string_array(node, TOPO_PGROUP_IPMI,
1824 TOPO_PROP_IPMI_ENTITY_LIST, &ei.ei_list, &ei.ei_listsz, &err)
1825 != 0 && (topo_prop_get_uint32(node, TOPO_PGROUP_IPMI,
1826 TOPO_PROP_IPMI_ENTITY_ID, &ei.ei_id, &err) != 0 ||
1827 topo_prop_get_uint32(node, TOPO_PGROUP_IPMI,
1828 TOPO_PROP_IPMI_ENTITY_INST, &ei.ei_inst, &err) != 0)) {
1829 if (get_entity_info(mod, node, hdl, &ei) != 0)
1830 goto out;
1831 }
1832 ei.ei_node = node;
1833 ei.ei_mod = mod;
1834
1835 /*
1836 * Now iterate through all of the full and compact sensor data records
1837 * and create a sensor facility node for each record that matches our
1838 * entity ID and instance
1839 */
1840 if ((ret = ipmi_sdr_iter(hdl, sdr_callback, &ei)) != 0) {
1841 topo_mod_dprintf(mod, "ipmi_sdr_iter() failed\n");
1842 }
1843 out:
1844 topo_mod_ipmi_rele(mod);
1845 if (ei.ei_list != NULL)
1846 topo_mod_strfreev(mod, ei.ei_list, ei.ei_listsz);
1847
1848 return (ret);
1849 }
1850
1851 static int
ipmi_entity(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1852 ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1853 nvlist_t *in, nvlist_t **out)
1854 {
1855 char **fmtarr, **entity_refs, buf[BUFSZ];
1856 tnode_t *refnode;
1857 uint_t nelems;
1858 int ret, inst1, inst2;
1859 uint32_t offset, nparams;
1860 nvlist_t *args, *nvl;
1861
1862 if (vers > TOPO_METH_IPMI_ENTITY_VERSION)
1863 return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
1864
1865 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1866 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1867 strerror(ret));
1868 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1869 }
1870 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1871 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1872 strerror(ret));
1873 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1874 }
1875 if ((ret = nvlist_lookup_uint32(args, "nparams", &nparams)) != 0) {
1876 topo_mod_dprintf(mod, "Failed to lookup 'nparams' arg (%s)\n",
1877 strerror(ret));
1878 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1879 }
1880 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1881 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1882 strerror(errno));
1883 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1884 }
1885
1886 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1887 == NULL)
1888 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1889
1890 if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1891 refnode = topo_node_parent(node);
1892 else
1893 refnode = node;
1894
1895 for (int i = 0; i < nelems; i++) {
1896 switch (nparams) {
1897 case 1:
1898 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1899 (void) snprintf(buf, BUFSZ, fmtarr[i],
1900 (topo_node_instance(refnode) + offset));
1901 break;
1902 case 2:
1903 inst1 = topo_node_instance(topo_node_parent(refnode))
1904 + offset;
1905 inst2 = topo_node_instance(refnode) + offset;
1906 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1907 (void) snprintf(buf, BUFSZ, fmtarr[i], inst1, inst2);
1908 break;
1909 default:
1910 topo_mod_dprintf(mod, "Invalid 'nparams' argval (%d)\n",
1911 nparams);
1912 topo_mod_strfreev(mod, entity_refs, nelems);
1913 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1914 }
1915 entity_refs[i] = topo_mod_strdup(mod, buf);
1916 }
1917 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1918 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1919 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1920 TOPO_TYPE_STRING_ARRAY) != 0 ||
1921 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs,
1922 nelems) != 0) {
1923
1924 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1925 topo_mod_strfreev(mod, entity_refs, nelems);
1926 nvlist_free(nvl);
1927 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1928 }
1929 topo_mod_strfreev(mod, entity_refs, nelems);
1930 *out = nvl;
1931
1932 return (0);
1933 }
1934
1935 /* ARGSUSED */
1936 static int
dimm_ipmi_entity(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)1937 dimm_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
1938 nvlist_t *in, nvlist_t **out)
1939 {
1940 char **fmtarr, **entity_refs, buf[BUFSZ];
1941 tnode_t *chip, *dimm;
1942 int ret;
1943 uint_t nelems;
1944 uint32_t offset;
1945 nvlist_t *args, *nvl;
1946
1947 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
1948 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
1949 strerror(ret));
1950 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1951 }
1952 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
1953 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
1954 strerror(ret));
1955 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1956 }
1957 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
1958 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
1959 strerror(errno));
1960 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
1961 }
1962
1963 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
1964 == NULL)
1965 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1966
1967 if (topo_node_flags(node) & TOPO_NODE_FACILITY)
1968 dimm = topo_node_parent(node);
1969 else
1970 dimm = node;
1971
1972 chip = topo_node_parent(topo_node_parent(dimm));
1973
1974 for (int i = 0; i < nelems; i++) {
1975 /* LINTED: E_SEC_PRINTF_VAR_FMT */
1976 (void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
1977 (topo_node_instance(dimm) + offset));
1978 entity_refs[i] = topo_mod_strdup(mod, buf);
1979 }
1980
1981 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
1982 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
1983 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
1984 TOPO_TYPE_STRING_ARRAY) != 0 ||
1985 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
1986 != 0) {
1987 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
1988 topo_mod_strfreev(mod, entity_refs, nelems);
1989 nvlist_free(nvl);
1990 return (topo_mod_seterrno(mod, EMOD_NOMEM));
1991 }
1992 topo_mod_strfreev(mod, entity_refs, nelems);
1993 *out = nvl;
1994
1995 return (0);
1996 }
1997
1998 /* ARGSUSED */
1999 static int
cs_ipmi_entity(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** out)2000 cs_ipmi_entity(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
2001 nvlist_t *in, nvlist_t **out)
2002 {
2003 char **fmtarr, **entity_refs, buf[BUFSZ];
2004 tnode_t *chip, *chan, *cs;
2005 int ret, dimm_num;
2006 uint_t nelems;
2007 uint32_t offset;
2008 nvlist_t *args, *nvl;
2009
2010 if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
2011 topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
2012 strerror(ret));
2013 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2014 }
2015 if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
2016 topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
2017 strerror(ret));
2018 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2019 }
2020 if (nvlist_lookup_string_array(args, "format", &fmtarr, &nelems) != 0) {
2021 topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
2022 strerror(errno));
2023 return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
2024 }
2025
2026 if ((entity_refs = topo_mod_alloc(mod, (nelems * sizeof (char *))))
2027 == NULL)
2028 return (topo_mod_seterrno(mod, EMOD_NOMEM));
2029
2030 if (topo_node_flags(node) & TOPO_NODE_FACILITY) {
2031 cs = topo_node_parent(node);
2032 chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
2033 chan = topo_node_parent(cs);
2034
2035 dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
2036 + topo_node_instance(cs) + offset;
2037 } else {
2038 cs = node;
2039 chip = topo_node_parent(topo_node_parent(topo_node_parent(cs)));
2040 chan = topo_node_parent(cs);
2041
2042 dimm_num = topo_node_instance(cs) - (topo_node_instance(cs) % 2)
2043 + topo_node_instance(chan) + offset;
2044 }
2045
2046 for (int i = 0; i < nelems; i++) {
2047 /* LINTED: E_SEC_PRINTF_VAR_FMT */
2048 (void) snprintf(buf, BUFSZ, fmtarr[i], topo_node_instance(chip),
2049 dimm_num);
2050 entity_refs[i] = topo_mod_strdup(mod, buf);
2051 }
2052
2053 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
2054 nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, "entity_ref") != 0 ||
2055 nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE,
2056 TOPO_TYPE_STRING_ARRAY) != 0 ||
2057 nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL, entity_refs, nelems)
2058 != 0) {
2059 topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
2060 topo_mod_strfreev(mod, entity_refs, nelems);
2061 nvlist_free(nvl);
2062 return (topo_mod_seterrno(mod, EMOD_NOMEM));
2063 }
2064 topo_mod_strfreev(mod, entity_refs, nelems);
2065 *out = nvl;
2066
2067 return (0);
2068 }
2069
2070 /*ARGSUSED*/
2071 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)2072 fac_prov_ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
2073 topo_instance_t min, topo_instance_t max, void *arg, void *unused)
2074 {
2075 topo_pgroup_info_t pgi;
2076 int err;
2077
2078 if (topo_node_flags(rnode) == TOPO_NODE_DEFAULT) {
2079 pgi.tpi_name = TOPO_PGROUP_IPMI;
2080 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
2081 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
2082 pgi.tpi_version = 1;
2083 if (topo_pgroup_create(rnode, &pgi, &err) != 0) {
2084 if (err != ETOPO_PROP_DEFD) {
2085 topo_mod_dprintf(mod,
2086 "pgroups create failure: %s\n",
2087 topo_strerror(err));
2088 return (-1);
2089 }
2090 }
2091 if (topo_method_register(mod, rnode, ipmi_node_methods) != 0) {
2092 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
2093 "topo_method_register() failed: %s",
2094 topo_mod_errmsg(mod));
2095 return (-1);
2096 }
2097 } else {
2098 if (topo_method_register(mod, rnode, ipmi_fac_methods) != 0) {
2099 topo_mod_dprintf(mod, "fac_prov_ipmi_enum: "
2100 "topo_method_register() failed: %s",
2101 topo_mod_errmsg(mod));
2102 return (-1);
2103 }
2104 }
2105 return (0);
2106 }
2107